Наследование от Frame или нет в приложении Tkinter - PullRequest
27 голосов
/ 04 сентября 2011

Я видел два основных способа настройки программы tkinter. Есть ли причина предпочитать одно другому?

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()

и

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()   

Ответы [ 3 ]

26 голосов
/ 04 сентября 2011

Вариант, который я предпочитаю *, - наследовать от класса Tk. Я думаю, что это более разумный выбор, поскольку окно, по сути, является вашим приложением. Наследование от Frame больше не имеет смысла для меня, чем наследование от Button или Canvas или Label. Поскольку вы можете иметь только один корень, имеет смысл, что это то, что вы наследуете.

Я также думаю, что это сделает код более читабельным, если вы выполните импорт как import Tkinter as tk, а не from Tkinter import *. Тогда во всех ваших звонках явно упоминается модуль tk. Я не рекомендую это для всех модулей, но для меня это имеет смысл с Tkinter.

Например:

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()

* Примечание: с момента первоначального написания этого ответа я изменил свою позицию. Теперь я предпочитаю наследовать от Frame, а не Tk. Там нет реального преимущества, так или иначе, это скорее философский выбор, чем что-либо еще. Несмотря на это, я считаю, что независимо от того, наследуете ли вы от Frame или Tk, я думаю, что любой из этих вариантов лучше, чем первый пример кода, который наследуется из ничего.

Единственное небольшое преимущество, которое унаследовано от Frame, имеет преимущество перед Tk в том случае, если вы хотите, чтобы ваше приложение поддерживало несколько идентичных окон. В этом случае наследование от Frame позволяет создать первое окно как дочерний элемент root, а дополнительные окна - как дочерний экземпляр экземпляров Toplevel. Однако я видел очень мало программ, которые когда-либо нуждались в этом.

Для получения дополнительной информации о том, как я думаю, что программы Tkinter должны быть структурированы, см. мой ответ на вопрос Структура программы Python Tkinter .

12 голосов
/ 04 сентября 2011

Рамка обычно используется как мастер геометрии для других виджетов . Так как в приложении обычно есть множество виджетов, вам часто захочется разместить их все во фрейме или, по крайней мере, использовать фрейм для добавления некоторого borderwidth, отступов или других мелких деталей.

Многие примеры фрагментов, которые вы можете найти в Интернете, не используют фрейм, потому что они просто хотят продемонстрировать некоторую особенность в кратчайшем объеме кода.

Итак, используйте Рамку, если она вам нужна, иначе не используйте.

Редактировать : Я думаю, что лучший способ организовать графический интерфейс приведен в этом Tkinter учебнике :

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()

Это в основном похоже на ваш первый пример, в котором SimpleApp наследуется от object, а не Frame. Я думаю, что это лучше, чем создавать подклассы Frame, поскольку мы не переопределяем методы Frame. Я предпочитаю думать о SimpleApp как о Frame, а не как Frame.

Наличие SimpleApp подкласса object имеет существенное преимущество перед подклассом tk.Tk, однако: оно позволяет легко встраивать SimpleApp в более крупное приложение:

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()

Таким образом, simpleApp.py может быть как автономным скриптом, так и импортируемым модулем. Если вы попробуете это с SimpleApp наследованием от tk.Tk, вы получите дополнительные нежелательные окна.

1 голос
/ 03 декабря 2013

Может быть преимущество установки объекта верхнего уровня для наследования от Tk вместо Frame.Преимущество возникает, когда у вас есть динамический элемент в вашем графическом интерфейсе, например, Label, содержимое которого вы хотите установить с textvariable=foo вместо text= 'Label text'.

В этом случае очень полезно использовать объекты Tkinter.DoubleVar, Tkinter.IntVar и Tkinter.StringVar для хранения данных, поскольку графический интерфейс будет автоматически обновляться всякий раз, когда эти объекты установлены.Однако, чтобы использовать эти объекты, вы должны указать их мастера как работающий корневой экземпляр Tkinter.Tk().Это проще, если вы явно сделаете свой главный объект подклассом Tkinter.Tk,, а затем создадите кадры и виджеты, чтобы вы могли передать экземпляр Tk и правильно настроить переменные.

Воткраткий пример программы для иллюстрации идеи.

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() 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...