【问题标题】:Python Tkinter - closing a child window with an exit buttonPython Tkinter - 使用退出按钮关闭子窗口
【发布时间】:2014-04-07 07:31:59
【问题描述】:

我有一个带有 Piface 适配器板的 Raspberry Pi。我制作了一个 GUI 来控制 Piface 板上的 LED。 GUI 上的一个按钮会打开一个新窗口,按下按钮后,该窗口会启动和停止运行一小段代码,以使 LED 连续上下运行,就像 Knight Riders 的汽车一样,使用线程中的 While 循环。 在这个新窗口中,我添加了一个退出按钮。我想添加一段代码,当我单击 EXIT 按钮时将关闭新窗口,然后返回主窗口。 我查了很多例子,但不太明白我应该放什么或放在哪里。我试过“退出”,但它关闭了整个程序。 在查看了许多示例后,我可能以不太正确的方式创建新窗口,因此请随时告诉我是否有更好的方法。

那么有没有更好的方法呢?任何指针将不胜感激。

提前致谢。

这是一段代码......

   def new_window(self):
        print('New Window')
        self.newWindow = tk.Toplevel(self.master)
        self.app = App2(self.newWindow)
        self.newWindow.grab_set()   # I added this line to stop opening multiple new windows

class App2:


    def __init__(self, master):

            frame = Frame(master)
            frame.pack()
            Label(frame, text='Turn LED ON').grid(row=0, column=0)
            Label(frame, text='Turn LED OFF').grid(row=0, column=1)

            self.button0 = Button(frame, text='Knight Rider OFF', command=self.convert0)
            self.button0.grid(row=2, column=0)
            self.LED0 = Label(frame, image=logo2)
            self.LED0.grid(row=2, column=1)

            self.button9 = Button(frame, text='Exit', command=self.close_window)
            self.button9.grid(row=3, column=0)


    def convert0(self, tog=[0]):

        tog[0] = not tog[0]
        if tog[0]:
            print('Knight Rider ON')
            self.button0.config(text='Knight Rider ON')
            t=threading.Thread(target=self.LED)
            t.start()
            self.signal = True    #added to stop thread
            self.LED0.config(image = logo)
        else:
            print('Knight Rider OFF')
            self.button0.config(text='Knight Rider OFF')
            self.signal = False   #added to stop thread
            self.LED0.config(image = logo2)

    def LED(self):
            while self.signal:   #added to stop thread

                a=0

                while self.signal:   #added to stop thread
                        pfio.digital_write(a,1) #turn on
                        sleep(0.05)
                        pfio.digital_write(a,0) #turn off
                        sleep(0.05)
                        a=a+1

                        if a==7:
                                break

                while self.signal:   #added to stop thread

                        pfio.digital_write(a,1) #turn on
                        sleep(0.05)
                        pfio.digital_write(a,0) #turn off
                        sleep(0.05)
                        a=a-1

                        if a==0:
                                break

    def close_window(self):
        print('Close Child window')
        #self.newWindow.destroy()   Not sure what to put here?

【问题讨论】:

    标签: python windows tkinter raspberry-pi exit


    【解决方案1】:

    如果您将new_window 放入您的 App2 中,那么您应该没问题。

    self.newWindow.destroy() 
    

    销毁窗口。这是正确的选择。然后窗口关闭,窗口中的所有小部件也被销毁。

    quit() 将停止mainloop() 在这种情况下,程序在最后一行结束,并且还破坏了所有内容。

    你肯定想使用destroy

    class App2:
    
        newWindow = None
    
        def close_window(self):
            print('Close Child window')
            if self.newWindow:
                try: self.newWindow.destroy()   
                except (): pass # fill in the error here
                self.newWindow = None
    
       def new_window(self):
            print('New Window')
            self.close_window()
            self.newWindow = tk.Toplevel(self.master)
            self.app = App2(self.newWindow)
            self.newWindow.grab_set()
    
        @classmethod
        def start_app(cls):
            window = tk.Tk(self.master)
            app = App2(window)
            return app
    

    你不应该从线程访问 Tkinter。 Have a look at alternatives

    当我开始使用 Tkinter 时,我也被 quitdestroy 弄糊涂了。

    【讨论】:

    • 我正在使用 new_window 代码来启动 App2。如果我将它移到 App2 中,则 App2 不会启动。我觉得我可能使用了错误的方式来启动 App2。
    • 我添加了一个启动应用程序的新方法。 App2.start_app() 让应用程序自行启动的有趣想法。我不会想到这一点。
    • 对不起,我现在迷路了,新手综合症。不幸的是,我把自己弄糊涂了,我没有解释清楚。感谢您的建议和线程替代的链接。
    【解决方案2】:

    在 Tk 中,窗口使用 destroy 方法销毁。因此,如果你有一个对话框顶层并且你想摆脱它,你可以调用它的 destroy() 方法。或者您可以撤回它,在这种情况下对象继续存在但不再出现在屏幕上并重新显示它,您 deiconify() 顶层框架。但更常见的是摧毁它们。下面是一个创建和销毁子对话框的简单示例:

    import sys
    from Tkinter import *
    
    class App(Frame):
        def __init__(self, parent = None):
            Frame.__init__(self, parent)
            self.grid()
    
            self.button = Button(self, text = "Create Dialog", command=self.CreateDialog)
            self.button.grid()
    
        def CreateDialog(self):
            dialog = Toplevel(self)
            dialog.wm_title("Dialog window")
            dialog.wm_transient(self)
            dialog.wm_protocol("WM_DELETE_WINDOW", lambda: self.onDeleteChild(dialog))
            button = Button(dialog, text="Close", command=lambda: self.onDeleteChild(dialog))
            button.grid()
    
        def onDeleteChild(self, w):
            w.destroy()
    
    
    def main():
        app = App()
        app.mainloop()
    
    if __name__ == "__main__":
        sys.exit(main())
    

    您还应该考虑在代码中使用计时器来驱动 LED 循环而不是 while 循环。看看this answer 使用 Tk 的 after 函数在间隔后运行代码。如果您在处理程序中重新安排另一个 after call,那么您可以安排一个函数定期运行,避免阻塞事件处理而不需要额外的线程。

    【讨论】:

    • 我见过很多这样的例子,但我不知道如何在我的代码中使用它。我想我需要看看我是如何启动新窗口的,新窗口是从上一课开始的,而我看到的例子都在一个类中。
    猜你喜欢
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多