python - 在 tkinter 窗口中禁用退出(或 [ X ])

标签 python python-3.x tkinter progress-bar exit

我发布这个是因为我自己一直在努力寻找这个问题的明确答案。 . .

在尝试为我的程序创建进度条时,我发现使用 tkinter 很难做到。要在不进入可怕的“主循环”的情况下完成创建进度条,I opted to make a class out of the progress bar using threads .通过大量的试错,我发现由于使用了多线程(tkinter 喜欢在主线程),可以定制的东西不多。以下是我尝试过的两个选项,然后是最适合我需要的第三个选项:

方案一:使用回调函数

给定以下代码:

import tkinter as tk
import tkinter.ttk as ttk
import threading


class ProgressbarApp(threading.Thread):

    def __init__(self, max_value: int):
        self.max_value = max_value

        self.root = None
        self.pb = None

        threading.Thread.__init__(self)
        self.lock = threading.Lock()    # (1)
        self.lock.acquire()             # (2)
        self.start()

        # (1) Makes sure progressbar is fully loaded before executing anything
        with self.lock:
            return

    def close(self):
        self.root.quit()

    def run(self):

        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.__callback)

        self.pb = ttk.Progressbar(self.root, orient='horizontal', length=400, mode='determinate')
        self.pb['value'] = 0
        self.pb['maximum'] = self.max_value
        self.pb.pack()

        self.lock.release()             # (2) Will release lock when finished
        self.root.mainloop()

    def update(self, value: int):
        self.pb['value'] = value

    @staticmethod
    def __callback():
        return

if __name__ == '__main__':
    interval = 100000
    my_pb = ProgressbarApp(interval)

    for i in range(interval):
        my_pb.update(i)

    my_pb.close()

    # Other stuff goes on . . .

在哪里

self.root.protocol("WM_DELETE_WINDOW", self.__callback)

防止窗口被关闭。但是,如果退出或 [ X ] 按钮被按住,进度条将卡住,直到用户释放按钮。 (不断调用__callback函数,阻止其他任务完成)。

选项 2:使用 root.overriderdirect(True)

给定以下代码:

import tkinter as tk
import tkinter.ttk as ttk
import threading


class ProgressbarApp(threading.Thread):

    def __init__(self, max_value: int):
        self.max_value = max_value

        self.root = None
        self.pb = None

        threading.Thread.__init__(self)
        self.lock = threading.Lock()    # (1)
        self.lock.acquire()             # (2)
        self.start()

        # (1) Makes sure progressbar is fully loaded before executing anything
        with self.lock:
            return

    def close(self):
        self.root.quit()

    def run(self):

        self.root = tk.Tk()
        self.root.overrideredirect(True)

        self.pb = ttk.Progressbar(self.root, orient='horizontal', length=400, mode='determinate')
        self.pb['value'] = 0
        self.pb['maximum'] = self.max_value
        self.pb.pack()

        self.lock.release()             # (2) Will release lock when finished
        self.root.mainloop()

    def update(self, value: int):
        self.pb['value'] = value

if __name__ == '__main__':
    interval = 100000
    my_pb = ProgressbarApp(interval)

    for i in range(interval):
        my_pb.update(i)

    my_pb.close()

    # Other stuff goes on . . .

在哪里

self.root.overrideredirect(True)

清除所有 tkinters 窗口选项。然而,进度条不仅在一个奇怪的位置,而且还遮挡了用户窗口。进度条应该对用户友好。

选项 3:使用 root.attributes('-disabled', True)

给定以下代码:

import tkinter as tk
import tkinter.ttk as ttk
import threading


class ProgressbarApp(threading.Thread):

    def __init__(self, max_value: int):
        self.max_value = max_value

        self.root = None
        self.pb = None

        threading.Thread.__init__(self)
        self.lock = threading.Lock()    # (1)
        self.lock.acquire()             # (2)
        self.start()

        # (1) Makes sure progressbar is fully loaded before executing anything
        with self.lock:
            return

    def close(self):
        self.root.quit()

    def run(self):

        self.root = tk.Tk()
        self.root.attributes('-disabled', True)

        self.pb = ttk.Progressbar(self.root, orient='horizontal', length=400, mode='determinate')
        self.pb['value'] = 0
        self.pb['maximum'] = self.max_value
        self.pb.pack()

        self.lock.release()             # (2) Will release lock when finished
        self.root.mainloop()

    def update(self, value: int):
        self.pb['value'] = value

if __name__ == '__main__':
    interval = 100000
    my_pb = ProgressbarApp(interval)

    for i in range(interval):
        my_pb.update(i)

    my_pb.close()

    # Other stuff goes on . . .

在哪里

self.root.attributes('-disabled', True)

防止用户与窗口进行任何交互。这最适合我对该程序的需求,因为它可以防止窗口关闭并且仍然具有漂亮的外观。 (我唯一的小问题是用户不能再最小化进度条或移动它)。

如果有任何更好的解决方案,我很乐意看到它们。希望这对某人有所帮助。

最佳答案

您可以创建一个只使用 pass 什么都不做的函数。

请看下面:

import tkinter as tk


root=tk.Tk()

def close_program():
    root.destroy()

def disable_event():
    pass

btn = tk.Button(root, text = "Click me to close", command = close_program)
btn.pack()

root.protocol("WM_DELETE_WINDOW", disable_event)

root.mainloop()

您还可以连同 root.overrideredirect(True) 一起删除工具栏,这将阻止用户使用任何工具栏。离开 root.protocol("WM_DELETE_WINDOW", disable_event) 也会阻止使用 ALT + F4

import tkinter as tk


root=tk.Tk()
root.geometry("400x400")
root.overrideredirect(True)

def close_program():
    root.destroy()

def disable_event():
    pass

btn = tk.Button(root, text = "Click me to close", command = close_program)
btn.pack()

root.protocol("WM_DELETE_WINDOW", disable_event)

root.mainloop()

关于python - 在 tkinter 窗口中禁用退出(或 [ X ]),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45467143/

相关文章:

python - Tkinter:抓取 ScrolledText 文本板的内容

python - file.write() 还是打印到文件更好?

python - pandas 在 groupby 级别 2 总和或平均条件上删除行

python - 我应该如何使用列表理解重写这个 map() 示例?

python - 在 Windows 上安装 python3 + lxml

python - 如何在 Tkinter 中更改 Frame 的背景?

python - 用于比较多个数据列的循环 T 检验

python - 看不懂这个定时while循环属性报错

python - 使用 BeautifulSoup Python 3 时遇到问题

python - 在Tkinter中尝试约会-Python