【问题标题】:how to stack two widgets and switch between them?如何堆叠两个小部件并在它们之间切换?
【发布时间】:2025-01-14 12:05:01
【问题描述】:

我想编写两个将被堆叠的小部件的脚本,然后我会用一个键从一个切换到另一个。每个小部件都是一个Frame,包含几个Labels。到目前为止,我有以下代码(每个 Frame 只有一个 Label):

import Tkinter as tk
import ttk
import datetime

def main():
    # initialize root
    root = tk.Tk()
    # initialize widgets
    dash = Dashboard(root)
    notepad = Notepad(root)
    # set key actions
    root.bind('<F11>', root.lift)
    root.bind('<F1>', dash.raiseme)
    root.bind('<F2>', notepad.raiseme)
    root.mainloop()

class Dashboard(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # voodoo
        self.dashframe = tk.Frame(parent)
        self.labone = tk.Label(self.dashframe, text="lab1", fg='black', bg='blue')
        self.labone.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme dash"
        self.labone.configure(text=datetime.datetime.now())
        self.dashframe.lift()

class Notepad(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # also voodoo
        self.noteframe = tk.Frame(parent)
        self.laboneone = tk.Label(self.noteframe, text="lab11", fg='white', bg='red')
        self.laboneone.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme notepad"
        self.laboneone.configure(text=datetime.datetime.now())
        self.noteframe.lift()

if __name__ == '__main__':
    main()

F1F2 会到达正确的例程,但我唯一得到的是主窗口,空的。没有显示错误,所以我猜代码运行良好(只是不是 O 想要的方式:))。

可以用上面的骨架实现切换吗?

【问题讨论】:

  • 看起来这里可能有一些有用的信息:[*.com/questions/11503324/… [1]:*.com/questions/11503324/…
  • @Totem:是的,我看到了这个问题(并从那里了解了lift),但没有帮助。
  • 您没有将任何一个框架放置在任何带有packgrid 或其他任何东西的地方,所以……您希望它们出现在哪里?
  • 好的,我能想到的唯一可能有帮助的事情是使用 focus_set 研究可能性..
  • 另外,为什么你的每个框架子类在同一个父级上创建一个 second 框架(也没有放置在任何地方),然后将标签添加到第二个框架,而不是对自己?

标签: python tkinter


【解决方案1】:

您的代码至少存在两个大问题。

首先,您要创建所有这些新框架,但不会将它们放置在任何地方,因此它们永远不会出现在任何地方。如果您有一个没有放置任何东西的主窗口,那么您当然只会“获取主窗口,为空”。您需要在任何小部件上调用 pack 或其他一些布局方法以使其显示在其父级上。在这种情况下,听起来您想将它们放在完全相同的位置,所以 gridplace 可能是您想要的。

其次,你的DashboardNotepad 类本身就是Frames,但它们不做任何Frame-ish 的东西;相反,他们各自创建另一个兄弟Frame 并为该兄弟附加标签。因此,即使您打包了 DashboardNotepad,它们也只是空框架小部件,因此没有任何好处。

如果你同时解决了这两个问题,我认为你的代码可以满足你的要求:

class Dashboard(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # voodoo
        self.labone = tk.Label(self, text="lab1", fg='black', bg='blue')
        self.labone.grid(row=0, column=0)
        self.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme dash"
        self.labone.configure(text=datetime.datetime.now())
        self.lift()

class Notepad(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # also voodoo
        self.laboneone = tk.Label(self, text="lab11", fg='white', bg='red')
        self.laboneone.grid(row=0, column=0)
        self.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme notepad"
        self.laboneone.configure(text=datetime.datetime.now())
        self.lift()

但是,您可能还想为所有内容设置固定大小;否则你最终可能会抬起红色小部件,例如,只覆盖蓝色小部件的 96%,因为当前时间比前一个小...


您链接到的代码试图这样做:

    newFrame = tkinter.Frame(root).grid()
    newFrame_name = tkinter.Label(newFrame, text="This is another frame").grid()

这行不通,因为grid 返回None,而不是小部件。但至少它调用grid;你的甚至不这样做。

【讨论】:

  • 谢谢。我看到我 lifted 错误的元素,这是一回事(除了没有意义的子框架,现在我开始了解它们是如何工作的)。你提到我没有使用grid()——我使用了它们,但只在Label元素上使用。现在我知道我还需要框架上的grid(),这确实很有意义。至于固定大小 - 你是对的,我给出的代码只是一个小例子。再次感谢!
  • 附带一个问题:您知道ttk.Frame.__init__(self, parent) 行的作用吗? (我在一个例子中发现了这一点,但这条线的含义让我无法理解)
  • @WoJ:This blog post 试图解释它。如果仍然不清楚,请随时提出后续问题。 (顺便说一句,这是升级到 Python 3.x 后会变得更简单的许多事情之一。)