Récupérer une variable d'une fonction lancée par un menu
Résolu/Ferméyg_be Messages postés 23496 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 mars 2025 - 16 déc. 2023 à 20:34
- Récupérer une variable d'une fonction lancée par un menu
- Fonction si et - Guide
- Recuperer message whatsapp supprimé - Guide
- Récupérer une vidéo youtube - Guide
- Comment récupérer un compte facebook piraté - Guide
- Menu déroulant excel - Guide
10 réponses
Salut.
Pourquoi ne pas utiliser un classe de façon à partager tes valeurs ?
from tkinter import * class Point_3D: "Definition d'un point 3D" def __init__(self,x = 0.0,y = 0.0,z=0.0): self.__x = x self.__y = y self.__z = z def __repr__(self): return "X %f Y %f Z %f"%(self.__x,self.__y,self.__z) x = property(lambda s: s.__x) y = property(lambda s: s.__y) z = property(lambda s: s.__z) class Point: def __init__(self, area): self.area = area self.pt = Point_3D(10.0, 12.0, 30.0) def add(self, *args): pass def show(self, evt=None): self.area.create_text(20, 20,text=self.pt.x) WIDTH, HEIGHT = 400, 400 main_win = Tk() main_win.title('Test') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') graph_area = Canvas(main_win,bg='white',height=380,width=380) graph_area.place(x = 10,y = 10) pt = Point(graph_area) menu_bar = Menu(main_win) menu_file = Menu(menu_bar, tearoff=0) menu_bar.add_cascade(label="Nouveau", underline=0, menu=menu_file) menu_file.add_command(label="Dossier", command=pt.add) main_win.config(menu=menu_bar) graph_area.bind("<Button-1>", pt.show) main_win.mainloop()
Le code est à revoir, mais l'idée globale est là.
Bah il suffit de mettre la création dans la méthode add.
class Point: def __init__(self, area): self.area = area self.pt = None def add(self, *args): self.pt = Point_3D(10.0, 12.0, 30.0) def show(self, evt=None): if self.pt is not None: self.area.create_text(20, 20,text=self.pt.x)
Si ça ne va pas, faut mieux expliquer comment doit se comporter ton script.
14 déc. 2023 à 18:15
bonjour,
suggestion:
def new_point(): graph_area.phil_pt = Point_3D(10.0, 12.0, 30.0) def show_point(evt): graph_area.create_text(20,20,text = str(graph_area.phil_pt.x))
14 déc. 2023 à 18:29
alternative:
def new_point(): pt = Point_3D(10.0, 12.0, 30.0) graph_area.bind("<Button-1>", lambda e : show_point(e,pt)) def show_point(evt,p): graph_area.create_text(20,20,text = str(p.x))
14 déc. 2023 à 18:49
Pourquoi utilises-tu une variable globale (graph_area) et écris-tu que tu veux t'en passer?
Sans variable globale:
from tkinter import * class Point_3D: "Definition d'un point 3D" def __init__(self,x = 0.0,y = 0.0,z=0.0): self.__x = x self.__y = y self.__z = z self.x=x def __repr__(self): return "X %f Y %f Z %f"%(self.__x,self.__y,self.__z) def new_point(g): pt = Point_3D(10.0, 12.0, 30.0) g.bind("<Button-1>", lambda e : show_point(e,g,pt)) def show_point(evt,gr,p): gr.create_text(20,20,text = str(p.x)) WIDTH, HEIGHT = 400, 400 main_win = Tk() main_win.title('Test') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') menu_bar = Menu(main_win) menu_file = Menu(menu_bar, tearoff=0) menu_bar.add_cascade(label="Nouveau", underline=0, menu=menu_file) main_win.config(menu=menu_bar) graph_area = Canvas(main_win,bg='white',height=380,width=380) graph_area.place(x = 10,y = 10) menu_file.add_command(label="Dossier", command=lambda : new_point(graph_area)) main_win.mainloop()
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionModifié le 15 déc. 2023 à 12:08
Bonjour,
J'ai trop simplifié mon exemple, je vais donc reformuler ma demande
from tkinter import * class Object(): def __init__(self,param_1, param_2): self.__param_1 = param_1 self.__param_2 = param_2 def new_object(obj_type): global obj pos1 = obj_type.index('x') p1, p2 = float(obj_type[:pos1]), float(obj_type[pos1+1:]) obj = Object(p1, p2) objects_types = ['170x80', '100x50'] WIDTH, HEIGHT = 400, 400 main_win = Tk() main_win.title('Test') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') menu_bar = Menu(main_win) menu_file = Menu(menu_bar, tearoff=0) menu_bar.add_cascade(label="Nouveau", underline=0, menu=menu_file) for k in range(len(objects_types)): menu_file.add_command(label='Objet '+str(k), command = lambda obj = objects_types[k] : new_object(obj)) main_win.config(menu=menu_bar) graph_area = Canvas(main_win,bg='white',height=380,width=380) graph_area.place(x = 10,y = 10) main_win.mainloop()
Je crée une instance en lançant une fonction lambda avec mon menu
On peut lui passer des arguments mais pas récupérer de valeur de retour
Or, je dois ensuite utiliser mon instance dans plusieurs fonctions de mon
application réelle, j'ai donc écrit global obj dans cette fonction, mais
je voudrais bien m'en passer
(la fonction principale contient aussi ce global et ensuite, je passe
l'instance en argument aux autres fonctions)
Pour résumer:
créer une instance suite à une action dans un menu, ou avec un bind
sur une touche du clavier, par exemple (donc pas de return possible)
puis utiliser cette instance dans plusieurs fonctions du code sans
global
15 déc. 2023 à 12:37
L'utilisation de obj en ligne 27, c'est uniquement pour créer de la confusion?
Peux-tu fournir un exemple plus complet, et testable?
15 déc. 2023 à 13:16
Un exemple, qui, sans global, fait un print, après la boucle, du dernier objet choisi.
from tkinter import * class Object(): def __init__(self,param_1, param_2): self.__param_1 = param_1 self.__param_2 = param_2 def new_object(m,obj_type): pos1 = obj_type.index('x') p1, p2 = float(obj_type[:pos1]), float(obj_type[pos1+1:]) m.phil_obj = Object(p1, p2) objects_types = ['170x80', '100x50'] WIDTH, HEIGHT = 400, 400 main_win = Tk() main_win.title('Test') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') menu_bar = Menu(main_win) menu_file = Menu(menu_bar, tearoff=0) menu_bar.add_cascade(label="Nouveau", underline=0, menu=menu_file) for k in range(len(objects_types)): menu_file.add_command(label='Objet '+str(k), command = lambda ot = objects_types[k] : new_object(main_win,ot)) main_win.config(menu=menu_bar) graph_area = Canvas(main_win,bg='white',height=380,width=380) graph_area.place(x = 10,y = 10) main_win.mainloop() print(main_win.phil_obj._Object__param_1,main_win.phil_obj._Object__param_2)
15 déc. 2023 à 13:22
un autre exemple
from tkinter import * class M(): pass class Object(): def __init__(self,param_1, param_2): self.__param_1 = param_1 self.__param_2 = param_2 def new_object(mm,obj_type): pos1 = obj_type.index('x') p1, p2 = float(obj_type[:pos1]), float(obj_type[pos1+1:]) mm.obj = Object(p1, p2) m=M() objects_types = ['170x80', '100x50'] WIDTH, HEIGHT = 400, 400 main_win = Tk() main_win.title('Test') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') menu_bar = Menu(main_win) menu_file = Menu(menu_bar, tearoff=0) menu_bar.add_cascade(label="Nouveau", underline=0, menu=menu_file) for k in range(len(objects_types)): menu_file.add_command(label='Objet '+str(k), command = lambda ot = objects_types[k] : new_object(m,ot)) main_win.config(menu=menu_bar) graph_area = Canvas(main_win,bg='white',height=380,width=380) graph_area.place(x = 10,y = 10) main_win.mainloop() print(m.obj._Object__param_1,m.obj._Object__param_2)
15 déc. 2023 à 13:30
Holà yg_be
Merci pour ça
Dans le 1er exemple, l'objet est donc un attribut de la fenêtre principale ?
Je pense que je vais opter pour le 2eme exemple avec la classe M() vide
Je teste tout ça dans mon code réel ...
Pourquoi une classe vide ?
Tout simplement passer en autres arguments de ta fonction anonyme, les références des fonctions ayant besoin de travailler avec tes valeurs.
class Object: def __init__(self, param_1, param_2): self._param_1 = param_1 self._param_2 = param_2 def new_object(obj_type, call_func): pos1 = obj_type.index('x') p1, p2 = float(obj_type[:pos1]), float(obj_type[pos1+1:]) call_func(Object(p1, p2)) def func(obj): print(obj._param_1, obj._param_2)
Et donc
for k in range(len(objects_types)): menu_file.add_command( label=f'Objet {k})', command = lambda : new_object(objects_types[k], func), )
Modifié le 15 déc. 2023 à 14:18
Non, ça ne va pas:
en fait je ne veux pas lancer func() tout de suite
avec mon menu, je choisi seulement un objet pour initialiser une instance
ensuite, je remplis des Entry boxes et j'appuie sur la touche Entrée du clavier
main_win.bind("<Return>", calculation)
J'ai donc ceci:
def new_object(obj_type): global obj ........
et:
def calculation(evt): global obj #on lance les fonctions utiles en passant obj en argument
Donc, 2 global à éliminer ...
15 déc. 2023 à 17:49
Tu n'as pas expliqué pourquoi tu voulais travailler sans "global".
"global" est souvent un indice d'un programme mal conçu. Cependant, il ne suffit pas de supprimer "global" pour obtenir un programme bien conçu.
La présence d'un objet attaché à rien et utilisé un peu partout, que ce soit via "global", ou pas, me semble un mauvais signe quant à la qualité de la structure des données du programme.
16 déc. 2023 à 11:19
Bonjour yg_be,
Oui, tu as surement raison, je vais prendre un peu de recul et revoir
tout ça.
Cependant, avant de clore cet appel, je voudrais te poser une dernière
question
Dans un certain nombre d'applications professionnelles, on trouve ce type
de menu:
Ne parlons pas de Word ou Excel, qui proposent un nom par défaut lorsque l'on
clique Fichier -> Nouveau
Lorsque j'étais en activité, j'utilisais un soft de CFAO, et l'on entrait
tout de suite le nom du fichier pièce à créer, ensuite, on travaillait à modéliser
une pièce, faire des plans, etc ..
A la fin on cliquait Fichier -> Enregistrer (on on cliquait l'icone que l'on
appelait familièrement "la biscotte")
Moi en Python, je fais comme ceci:
menu_bar = Menu(main_win) file_menu = Menu(menu_bar, tearoff=0) menu_bar.add_cascade(label="Fichier", menu=file_menu) file_menu.add_command(label="Nouveau", command=new_file) file_menu.add_command(label="Ouvrir...", command=open_file) file_menu.add_command(label="Sauvegarder", state = DISABLED, command=save_file) file_menu.add_command(label="Sauvegarder sous ...", state = DISABLED, command=save_file_as) file_menu.add_command(label="Fermer", state = DISABLED, command=close_file) file_menu.add_separator() file_menu.add_command(label="Quitter", command=main_win.destroy)
J'ai donc ces 2 fonctions:
def new_file(): ''' Creates a new file''' current_file = filedialog.asksaveasfilename(initialdir = os.getcwd(),title = "Nouveau fichier",filetypes =(("Fichiers modèles", "*.prt"),("Tous fichiers","*.*")))
def save_file(): ''' Saves the current file ''' with open(current_file,'wb') as fo: pickle.dump(objects_list, fo)
Et il faut bien récupérer current_file créé dans new_file()
Comment faisaient-ils donc, ces castars de chez Siemens, pour traiter
ce cas-là ?
(et je pense que dans une boite comme ça, ce n'était pas des amateurs)
16 déc. 2023 à 14:57
Je pense que la façon dont Siemens traitait cette situation dépendait du langage et de la modularité de leur programme.
En Python, je ferais quelque chose du genre:
class Univers(): pass def new_file(): Univers.current_file = input("fn?") def save_file(): print(Univers.current_file) new_file() save_file()
16 déc. 2023 à 15:16
Pas mal ...
Pour info, le soft avait été développé initialement en C, puis retaillé en C++ au milieu
des années 80...
16 déc. 2023 à 20:34
J'ai regardé le code de l'éditeur "ed", éditeur très ancien sous Unix. Il est écrit en C, et le nom du fichier en cours est simplement enregistré via une variable déclarée hors des fonctions, donc une variable dont la portée est globale.
Les déclarations de variables sont cependant tellement différentes en Python par rapport au C (et C++, C#), je n'en déduirais pas que c'est une bonne idée d'utiliser "global" en Python.
Je trouve que Python est peu intuitif, et crée des confusions sources d'erreurs, en permettant implicitement d'utiliser des variables globales sans les déclarer explicitement comme telles.
Donc je préfère, en Python, éviter toute utilisation, explicite ou implicite, de variable globale.
Modifié le 14 déc. 2023 à 13:15
Merci pour cette réponse
mais pt est créé en ligne 40 en dehors de toute fonction
Moi, je dois le créer dans une fonction dès l'appui sur le menu
pas au lancement du programme