【问题标题】:Python tkinter restarting the mainwindow while its runningPython tkinter 在运行时重新启动主窗口
【发布时间】:2021-01-22 17:37:29
【问题描述】:

我有一个复杂的程序,我在我的 tkinter 主循环中运行多个任务。我的程序正在运行,但是我遇到了一个烦人的问题,除非任务完成,否则我无法停止任务。我开发了一个简单的 tkinter 程序来显示这个问题:

完整代码:

import tkinter as tk
from tkinter import Button,Entry,Canvas,Label,ttk


class Application(tk.Frame): 
    def __init__(self,master=None):
        super().__init__(master)
        self.master = master
    def Create_canvas(self,canvas_width,canvas_height):
        global canvas#described as global because used outside class
        canvas = tk.Canvas(self.master,bg='papaya whip',width=canvas_width,height=canvas_height)
       
    def Application_Intro(self):
        print("starting new app")
        restart_program_button = tk.Button(canvas, text="Restart_program",font='Helvetica 12 bold', width=20, height=2, command =self.Restart)
        start_program_button = tk.Button(canvas, text="Start_program",font='Helvetica 12 bold', width=20, height=2, command =self.Start_program)     
        canvas.create_text(960,20,text="MY PROGRAM",font='Helvetica 16 bold')
        canvas.create_window(710,300,window = restart_program_button)
        canvas.create_window(710,500,window = start_program_button)
        canvas.pack()
        self.master.mainloop()
        
        
        
    def Start_program(self):
        print("Program start")
        self.master.after(1000,self.Start_program)
        
    def Restart(self):
        #self.master.destroy()
        #self.master.quit()
        print("HERE I WANT TO INTERRUPT START PROGRAM AND RETURN TO IDLE STATE")

        #WHAT TO DO IN THIS FUNCTION TO GO BACK TO INITIAL MAINLOOP STATE??
        return


master = tk.Tk()
app = Application(master=master)
app.Create_canvas(1920,1080)

app.Application_Intro()    
        
        

上面的程序将创建一个带有 2 个按钮的简单 GUI。最初,程序将空闲并等待用户启动应用程序。当应用程序启动时,它会递归调用自己(检查各种状态并在我的真实程序中执行其他复杂操作),但是,我希望能够随时中断此操作并停止它。这就是为什么我创建了一个按钮“RESTART”,它应该将程序重新启动到我正在等待用户重新启动和应用程序的初始状态。按下按钮后如何退出 Start_program 函数?

除了 master.destroy() 或 master.quit() 之外,我真的无法在互联网上找到相关信息。

master.destroy() 完全破坏了我的主循环,这不是我想要的,而且调用 master.quit() 似乎什么也没做。

添加图片网址以便您更容易理解: https://ibb.co/djMd5TW

【问题讨论】:

  • 如果“程序运行良好”,那么您的问题是什么?看起来,您已经完成了您想要完成的工作,但需要一般性建议才能做得更好。您必须具体才能真正获得帮助。
  • 正如你所说。我希望从有更多 tkinter 经验的人那里得到建议,并且可以给我一般性建议,这是否是处理窗口的有效方法,因为我觉得每次开始新操作时销毁和重建新窗口的效率都不是很高(可以每 30 秒或类似的时间启动一个新操作)
  • 当应用程序在桌面上运行时,定期销毁窗口不会有什么问题。更令人担忧的是,您似乎正在运行不止一个 Tk() 实例(login_screen 和 window)。
  • 感谢您的回复。我正在使用 Tk() 登录屏幕的单个实例是顶层窗口。它在登录窗口中创建如下:global login_screen login_screen = TopLevel(window)
  • 你应该很高兴。应用程序运行后,您可能需要重新对其进行重构。但首先让它发挥作用,你似乎已经拥有了。

标签: python python-3.x user-interface tkinter raspberry-pi


【解决方案1】:

这取决于你愿意重写多少程序。 IMO,“最佳情况”不会删除主窗口并尽可能少地使用TopLevels。我建议改为创建一系列框架,以便您可以非常轻松地添加和删除窗口的整个内容。这些框架将是您自己的类,其父级为 tkinter.Frame,并包含该屏幕的所有逻辑。

我建议这样做的原因是因为您似乎有大约 700 多行方法(我从经验中知道;-)维护起来真的很痛苦(超过几百行,我将开始使用上面的方法)。如果您想要此方法的示例,请参阅此答案底部的代码。

稍微小一点的变化,我建议你用import tkinter as tk 替换你的from tkinter import *,因为前者会创建一个非常混乱的命名空间:

from tkinter import *:这会将 Tkinter 库导入全局命名空间。这不是最佳实践,因为它会用很多类填充您的命名空间,您可能会不小心覆盖这些类,但对于非常小的脚本来说没关系。 [Creating a Tkinter Hello World - Python GUI programming with Tkinter]

我建议的另一个小更改是停止创建您自己的消息窗口(例如声明“登录成功”),而是查看tkinter.messagebox 模块(在这种情况下,您可以使用showinfo)。

如果您有 很多 时间,请查看 IDLE 源代码,因为它是一个 tkinter 程序,(一般来说)写得很好(我相信 Thonny 也使用 tkinter) .

#/usr/bin/python3

import tkinter as tk

class Login(tk.Frame):

    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
        self.create_widgets()
        self.pack(expand=True, fill="both")

    def create_widgets(self):

        # your login screen widgets ...
        # I use this method to stop __init__ becoming too big and also to
        # give me the option to seperate widget creating from
        # instantiation if I wish

        tk.Button(self, text="Login", command=self.check_creds).pack()

    def check_creds(self):

        # mysql and other logic
        # assuming everything is good to go:

        self.destroy()
        Welcome(self.master)

class Welcome(tk.Frame):

    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
        self.create_widgets()
        self.pack(expand=True, fill="both")

    def create_widgets(self):

        # again, your widgets are created here...

        tk.Button(self, text="Log out", command=self.log_out).pack()

    def log_out(self):
        self.destroy()
        Login(self.master)

root = tk.Tk()
Login(root)
root.mainloop()

【讨论】:

  • 谢谢先生,我一定会看看 GUI 的这种实现,看看我能走多远。
猜你喜欢
  • 1970-01-01
  • 2022-11-20
  • 2017-02-27
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多