Python - Tkinter - 在继承自Toplevel()的类中创建的小部件出现在OUTSIDE类的不同框架中,Toplevel()类为空

时间:2013-01-14 22:57:48

标签: python python-2.7 inheritance tkinter

我正在尝试创建一个类并从Toplevel()继承,以便该类的GUI元素可以包含在一个单独的窗口中。通常我只会继承Frame(),但出于我的目的,我需要一切都在窗口中。我正在我的GUI模板脚本中编写代码,所以我可以弄清楚如何在我将其用于我想要使用的实际脚本之前使其工作。这是代码:

from Tkinter import *
import socket

myplayername = ''

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()

        class InfoLabel(Frame):
            def __init__(self, name, value, bgc, nfgc, vfgc, master=None):
                Frame.__init__(self, master)
                self.pack()
                Label(master=self, text=name, bg=bgc, fg=nfgc).pack({"side": "left"})
                Label(master=self, text=value, bg=bgc, fg=vfgc).pack({"side": "left"})

        class LabelEntry(Frame):
            def __init__(self, name, variable, bgc, fgc, entrysize, master=None):
                Frame.__init__(self, master)
                self.pack()
                Label(master=self, text=name, bg=bgc, fg=fgc).pack({"side": "left"})
                Entry(master=self, textvariable=variable, bg=bgc).pack({"side": "left"})

        class HostGameWindow(Toplevel):
            def __init__(self):
                global myplayername
                Toplevel.__init__(self)
                self.title('Host a Game')
                hostname = socket.gethostname()
                hostipaddr = socket.gethostbyname(hostname)
                hostport = 11489
                players = 0

                portsv = StringVar(value=str(hostport))
                numofplayers = StringVar(value=str(players))
                myname = StringVar(value=myplayername)

                hostgameframe = Frame(master=self, bg='#999', bd=3, relief=RIDGE, padx=5, pady=5).pack({"side": "left"})
                hoststatusframe = Frame(master=self, bg='white', bd=3, relief=RIDGE).pack({"side": "left"})
                hostbuttonframe = Frame(master=hostgameframe, bd=2, relief=RAISED, padx=5, pady=5).pack({"side": "bottom"})
                InfoLabel(master=hostgameframe, name='Hostname:', value=hostname, bgc='#999', nfgc='blue', vfgc='red').pack({"side": "top"})
                InfoLabel(master=hostgameframe, name='IP Address:', value=hostipaddr, bgc='#999', nfgc='blue', vfgc='red').pack({"side": "top"})
                LabelEntry(master=hostgameframe, name='Host on port:', variable=portsv, bgc='#999', fgc='blue', entrysize=len(str(hostport))).pack({"side": "top"})
                LabelEntry(master=hostgameframe, name='Players Joining:', variable=numofplayers, bgc='#999', fgc='blue', entrysize=2).pack({"side": "top"})
                LabelEntry(master=hostgameframe, name='Player Name:', variable=myname, bgc='#999', fgc='blue', entrysize=16).pack({"side": "top"})
                Button(master=hostbuttonframe, text='Host Game', width=10).pack({"side": "left"})
                Button(master=hostbuttonframe, text='Start Game', width=10).pack({"side": "left"})

            def close():
                self.destroy()

        def HostGameDialog():
            HostGameWindow()

        Button(master=self, text='Host a Game', command=HostGameDialog).pack()




root = Tk()
app = Application(master=root)
#root.wm_iconbitmap(default='INSERT ICON HERE')
#root.wm_title("TITLE OF PROGRAM")
#app.master.maxsize(640, 480)
app.master.minsize(640, 480)
app.master.resizable(0, 0)
app.mainloop()
app.quit()

现在出于某种原因,当我单击“主持游戏”按钮时,它会调用HostGameDialog()函数并创建HostGameWindow(),但是创建的窗口大小与它一样小可以是HostGameWindow()类中应包含的所有GUI元素,而不是出现在主Application()帧中。而对我来说真的很奇怪的是它没有给出任何错误,只是将所有小部件放在主应用程序框架内而不是创建的Toplevel()

我到底做错了什么?为什么Toplevel()内没有放置任何小部件? 我已经在这几个小时了,没有任何意义。如果你知道任何对我有帮助的事情,请告诉我。

哇,我以前从来没有等过这么久的回复,这一定是一个非常漂亮的问题,我仍然不知道该怎么办。非常感谢任何想法!

我想没人知道该怎么做...我会继续在这里查看!

解决了!如果你创建一个对它的引用,那么在同一行上创建AND打包它不是一个好主意。只有在不创建对Widget(args*).pack(args*)的引用的情况下调用{{1}}时,才能在同一行创建和打包小部件。

1 个答案:

答案 0 :(得分:1)

执行x=a().b()时,x中存储的内容是b()的结果。

考虑以下代码行:

hostgameframe = Frame(self, bg='#999', bd=3, 
    relief=RIDGE, padx=5, pady=5).pack({"side": "left"})

如果我们崩溃了所有选项(为了清晰起见),我们就留下了这个:

hostgameframe = Frame(...).pack(...)

你能看到发生了什么吗? hostgameframe被设置为pack(...)的结果。 pack始终返回None,因此hostgameframeNone。当您稍后创建另一个窗口小部件并将其设置为主窗口时,该窗口小部件将在主窗口中结束。

因此,要解决您的问题,您需要将窗口小部件的创建与布局分开。我个人认为这是你应该始终坚持的最佳实践。对于不需要保留对窗口小部件的引用的情况,将它们组合到一个语句中是无害的。即便如此,如果您养成始终将窗口小部件创建与窗口小部件布局分离的习惯,我认为您的代码将更易于管理。

hostgameframe = Frame(self, bg='#999', bd=3, relief=RIDGE, padx=5, pady=5)
hostgameframe.pack({"side": "left"})