web-dev-qa-db-ja.com

フレームから継承するか、Tkinterアプリケーションで継承しない

Tkinterプログラムを設定する2つの基本的な方法を見てきました。どちらか一方を優先する理由はありますか?

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

私が好むオプションは、クラスTkから継承することです。ウィンドウは実際にはアプリケーションなので、これはより合理的な選択だと思います。 Frameから継承しても、ButtonまたはCanvasまたはLabelから継承しても意味がありません。ルートは1つしか持てないため、それが継承元であることは理にかなっています。

また、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よりもわずかな利点の1つは、アプリケーションで複数の同一のウィンドウをサポートする場合です。その場合、Frameから継承すると、最初のウィンドウをルートの子として、追加のウィンドウをToplevelのインスタンスの子として作成できます。ただし、これを実行する必要があるプログラムはほとんどありません。

Tkinterプログラムをどのように構造化すべきかについての詳細は、質問 Python Tkinterプログラムの構造my answer を参照してください。

26
Bryan Oakley

通常、フレームは 他のウィジェットのジオメトリマスター として使用されます。通常、アプリケーションには多数のウィジェットがあるため、それらをすべてフレームに含めるか、少なくともフレームを使用してborderwidth、パディング、またはその他の便利な機能を追加することがよくあります。

Webで見つかる多くのサンプルスニペットは、最短のコードでいくつかの機能をデモンストレーションしたいだけなので、Frameを使用しません。

したがって、必要な場合はフレームを使用し、そうでない場合は使用しないでください。

編集:GUIを編成する最良の方法はこれで提供されると思います 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()

これは、SimpleAppobjectではなくFrameから継承するという点で、主にfirstの例に似ています。 Frameメソッドをオーバーライドしないため、Frameをサブクラス化するよりも良いと思います。私はSimpleAppFrameではなく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はスタンドアロンスクリプトでもインポート可能なモジュールでもかまいません。 tk.Tkを継承するSimpleAppでこれを試すと、余分な不要なウィンドウが表示されます。

12
unutbu

トップレベルオブジェクトをTkではなくFrameから継承するように設定することには利点があります。利点は、GUIに動的要素がある場合に発生します。 _textvariable=foo_の代わりに_text= 'Label text'_で内容を設定するLabel.

この場合、_Tkinter.DoubleVar_、_Tkinter.IntVar_、および_Tkinter.StringVar_オブジェクトを使用してデータを保持すると、これらのオブジェクトが設定されるたびにGUIが自動的に更新されるため、非常に役立ちます。ただし、これらのオブジェクトを使用するには、実行中のルート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() 
_
1
user3061910