Python - Tkinter - 在继承自Toplevel()的类中创建的小部件出现在OUTSIDE类的不同框架中,Toplevel()类为空 [英] Python - Tkinter - Widgets created inside a class inherited from Toplevel() appear in a different frame OUTSIDE the class, Toplevel() class is empty

查看:268
本文介绍了Python - Tkinter - 在继承自Toplevel()的类中创建的小部件出现在OUTSIDE类的不同框架中,Toplevel()类为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm attempting to create a class and inherit from Toplevel() so that the GUI elements of the class can be contained within a separate window. Usually I would just inherit from Frame() but for my purpose I need everything to be in a window. I'm writing the code in my GUI template script just so I can figure out how to get it working before I stick it in the actual script I want to use it in. Here is the code:

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() function并创建 HostGameWindow() ,但是创建的窗口的大小尽可能小,而且应该包含在 HostGameWindow()中的所有GUI元素而是出现在主 Application()框架中。而对我来说真的很奇怪的是它不会给出任何错误,它只是将所有小部件放在主应用程序框架内而不是 Toplevel()中得到了。

Now for some reason when I click the 'Host a Game' Button, it calls the HostGameDialog() function and it creates the HostGameWindow(), BUT the window that gets created is sized down as small as it can be and all the GUI elements that should be contained in the HostGameWindow() class instead appear in the main Application() frame. And the thing which is really wierd to me is that it doesn't give any errors, it just puts all the widgets inside the main application frame instead of the Toplevel() that gets created.

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

What the heck am I doing wrong? Why aren't any the widgets placed inside the Toplevel()? I've been at it for hours now and nothing is making sense. Please if you know anything that could be of some help to me let me know.

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

Wow, I've never had to wait so long for reply here before, this must be a pretty nifty problem, I still don't know what to do. Any ideas are greatly appreciated!

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

I guess no one know what to make of this... I'll keep checking here though!

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

SOLVED! turns out its not a good idea to create AND pack a widget on the same line if you create a reference to it. Creating and packing a widget on the same line only works if you just call the Widget(args*).pack(args*) without creating a reference to it.

推荐答案

当你做 x = a()。b()时,什么是存储在x中是 b()的结果。

When you do x=a().b(), what is stored in x is the result of b().

考虑以下代码行:

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

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

If we collapse all of the options (for clarity) we're left with this:

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

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

Can you see what's happening? hostgameframe is being set to the result of pack(...). pack always returns None, so hostgameframe is None. When you later create another widget and set this as it's master, that widget ends up going in the main window.

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

So, to solve your problem you need to separate the creation of the widget from the layout. Personally I think this is a best practice that you should always adhere to. For cases where you don't need to keep a reference to the widget, combining them into one statement is harmless. Even so, I think your code will be easier to manage if you get in the habit of always separating widget creation from widget layout.

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

这篇关于Python - Tkinter - 在继承自Toplevel()的类中创建的小部件出现在OUTSIDE类的不同框架中,Toplevel()类为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆