J'ai vu deux façons fondamentales de mettre en place un programme tkinter. Y a-t-il une raison de préférer l'un à l'autre?
from Tkinter import *
class Application():
def __init__(self, root, title):
self.root = root
self.root.title(title)
self.label = Label(self.root, text='Hello')
self.label.grid(row=0, column=0)
root = Tk()
app = Application(root, 'Sample App')
root.mainloop()
et
from Tkinter import *
class Application(Frame):
def __init__(self, title, master=None):
Frame.__init__(self, master)
self.grid()
self.master.title(title)
self.label = Label(self, text='Hello')
self.label.grid(row=0, column=0)
app = Application('Sample App')
app.mainloop()
L'option que je préfère * est d'hériter de la classe Tk. Je pense que c'est le choix le plus raisonnable puisque la fenêtre est, en fait, votre application. Hériter de Frame
n'a plus de sens pour moi alors hériter de Button
ou Canvas
ou Label
. Puisque vous ne pouvez avoir qu'une seule racine, il est logique que c'est de cela que vous héritez.
Je pense également que cela rend le code plus lisible si vous effectuez l'importation en tant que import Tkinter as tk
plutôt que from Tkinter import *
. Tous vos appels mentionnent alors explicitement le module tk
. Je ne le recommande pas pour tous les modules, mais pour moi, cela a du sens avec Tkinter.
Par exemple:
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.label = tk.Label(text="Hello, world")
self.label.pack(padx=10, pady=10)
app = SampleApp()
app.mainloop()
* Remarque: depuis la rédaction de cette réponse, j'ai changé de position. Je préfère maintenant hériter de Frame
plutôt que Tk
. Il n'y a pas vraiment d'avantage dans un sens ou dans l'autre, c'est plus un choix philosophique qu'autre chose. Quoi qu'il en soit, je pense que si vous héritez de Frame
ou Tk
, je pense que l'un ou l'autre choix est meilleur que le premier exemple du code qui hérite de rien.
Le seul léger avantage hérité de Frame
a sur Tk
est dans le cas où vous voulez que votre application prenne en charge plusieurs fenêtres identiques. Dans ce cas, l'héritage de Frame
vous permet de créer la première fenêtre en tant qu'enfant de root et des fenêtres supplémentaires en tant qu'enfants d'instances de Toplevel
. Cependant, j'ai vu très peu de programmes qui ont besoin de le faire.
Pour plus d'informations sur la façon dont je pense que les programmes Tkinter devraient être structurés, voir ma réponse à la question Structure du programme Python Tkinter .
Un cadre est généralement utilisé comme maître de géométrie pour d'autres widgets . Puisqu'une application a généralement de nombreux widgets, vous souhaiterez souvent les contenir tous dans un cadre, ou au moins utiliser le cadre pour ajouter un borderwidth
, un rembourrage ou autre élément.
De nombreux exemples d'extraits que vous pourriez trouver sur le Web n'utilisent pas de cadre, car ils veulent simplement montrer une fonctionnalité dans le plus petit nombre de codes.
Donc, utilisez un cadre si vous en avez besoin, sinon, ne le faites pas.
Edit : Je pense que la meilleure façon d'organiser une interface graphique est donnée dans ce Tkinter tutorial :
simpleApp.py:
import Tkinter as tk
class SimpleApp(object):
def __init__(self, master, **kwargs):
title=kwargs.pop('title')
frame=tk.Frame(master, **kwargs)
frame.pack()
self.label = tk.Label(frame, text=title)
self.label.pack(padx=10,pady=10)
if __name__=='__main__':
root = tk.Tk()
app = SimpleApp(root,title='Hello, world')
root.mainloop()
C'est principalement comme votre premier exemple dans lequel SimpleApp
hérite de object
, pas Frame
. Je pense que c'est mieux que de sous-classer Frame
car nous ne remplaçons pas les méthodes Frame
. Je préfère penser à SimpleApp
comme ayant un Frame
plutôt que d'être un Frame
.
Avoir SimpleApp
sous-classe object
présente un avantage significatif sur la sous-classe tk.Tk
, cependant: il facilite l'intégration de SimpleApp
dans une application plus grande:
import simpleApp
import Tkinter as tk
class BigApp(object):
def __init__(self, master, **kwargs):
title=kwargs.pop('title')
frame=tk.Frame(master, **kwargs)
frame.pack()
self.simple = simpleApp.SimpleApp(frame,title=title)
frame.pack(padx=10, pady=10)
self.simple2 = simpleApp.SimpleApp(frame,title=title)
frame.pack()
if __name__=='__main__':
root = tk.Tk()
app = BigApp(root,title='Hello, world')
root.mainloop()
Ainsi, simpleApp.py peut être un script autonome ainsi qu'un module importable. Si vous essayez ceci avec SimpleApp
héritant de tk.Tk
, vous vous retrouvez avec des fenêtres supplémentaires indésirables.
Il peut être avantageux de définir votre objet de niveau supérieur pour hériter de Tk
au lieu de Frame
. L'avantage survient lorsque vous avez un élément dynamique dans votre interface graphique, par exemple un Label
dont vous souhaitez définir le contenu avec un textvariable=foo
au lieu de text= 'Label text'
.
Dans ce cas, il est très utile d'utiliser les objets Tkinter.DoubleVar
, Tkinter.IntVar
Et Tkinter.StringVar
Pour contenir les données, car l'interface graphique se mettra automatiquement à jour chaque fois que ces objets seront définis. Cependant, pour utiliser ces objets, vous devez spécifier leur maître en tant qu'instance racine Tkinter.Tk()
en cours d'exécution. C'est plus facile si vous faites explicitement de votre objet principal une sous-classe de Tkinter.Tk,
Puis que vous générez des cadres et des widgets, vous pouvez donc transmettre l'instance Tk
et configurer correctement vos variables.
Voici un court exemple de programme pour illustrer l'idée.
import Tkinter as tk
class Tkclass(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
app=Application(self)
app.master.title("Animal to Meat")
app.mainloop()
class Application(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
self.meatvar = tk.StringVar(master=parent)
self.meatvar.set("Meat?")
self.createWidgets()
def createWidgets(self):
top=self.winfo_toplevel()
top.rowconfigure(0, weight=1)
top.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(2, weight=1)
self.columnconfigure(3, weight=1)
self.cowButton = tk.Button(self, text='Cow', command=self.setBeef)
self.cowButton.grid(row=0,column=0)
self.pigButton = tk.Button(self, text='Pig',command=self.setPork)
self.pigButton.grid(row=0,column=1)
self.meatLabel = tk.Label(self)
self.meatLabel.configure(textvariable=self.meatvar)
self.meatLabel.grid(row=0,column=2)
self.quit = tk.Button(self, text='Quit',command=self.QuitApp)
self.quit.grid(row=0, column=3)
def setBeef(self):
self.meatvar.set("Beef")
def setPork(self):
self.meatvar.set("Pork")
def QuitApp(self):
top=self.winfo_toplevel()
top.quit()
main = Tkclass()