Tkinter -在MVC模式下使用上下文管理器更改时,鼠标光标在屏幕上不会更改。
我试着用MVC模式和tkinter库做了一个应用程序。为了使控制器状态更易于管理,我尝试使用context manager和@property decorator来管理enum类型的控制器状态。此外,我想改变光标类型根窗口时,控制器的状态改变,但由于某种原因,光标没有改变预期的。下面我附上了代表这个问题的示例代码。我的PC上有Windows 10。我还尝试在Controller类的状态设置器方法中更改游标类型,但也不起作用。
from enum import Enum
import tkinter as tk
# enum with controller states
class APP_STATE(Enum):
BUSY = 1
IDLE = 0
# main window of the application
class MainWnd(tk.Tk):
def __init__(self, controller):
self.controller = controller
super(MainWnd, self).__init__()
# initialize
self.title('TEST')
button = tk.Button(self, text="Start Long Running Event", command=self.controller.create_document)
button.pack()
# context manager used to manage states of the controller
class ControllerManager:
def __init__(self, parent):
self.parent = parent
def __enter__(self):
self.parent.state = APP_STATE.BUSY
print("cursor is {0}".format(self.parent.appInstance.cget("cursor")))
self.parent.appInstance.config(cursor="wait")
self.parent.appInstance.update()
print("cursor should be wait and is {0}".format(self.parent.appInstance.cget("cursor")))
def __exit__(self, exc_type, exc_value, traceback):
self.parent.state = APP_STATE.IDLE
print("cursor is {0}".format(self.parent.appInstance.cget("cursor")))
self.parent.appInstance.config(cursor="")
print("cursor should be default and is {0}".format(self.parent.appInstance.cget("cursor")))
class Controller(object):
def __init__(self):
self._state = APP_STATE.IDLE # state
self.appInstance = MainWnd(self) # app window
@property
def state(self):
return self._state
@state.setter
def state(self, new_value):
if new_value == APP_STATE.BUSY:
self._state = new_value
elif new_value == APP_STATE.IDLE:
self._state = new_value
#######################################
def run(self):
self.appInstance.mainloop()
#######################################
def create_document(self): # some long running task
with ControllerManager(self):
import time
time.sleep(2)
print("Task completed")
cl = Controller()
cl.run()
上面提到的代码显示了光标的变化,但在执行代码时,我在屏幕上看不到它。我怀疑有什么东西阻塞了tkinter的config()和update()函数,但我不知道如何改变它使其工作。另外,我用类似的代码做了一些测试:
import tkinter as tk
class CursorManager:
def __init__(self, widget, cursor_type):
self.widget = widget
self.cursor_type = cursor_type
def __enter__(self):
self.widget.config(cursor=self.cursor_type)
def __exit__(self, exc_type, exc_val, exc_tb):
self.widget.config(cursor="") # Reset cursor to default
# Create a Tkinter root window
root = tk.Tk()
def execute_task():
# Use the CursorManager as a context manager to change the cursor
with CursorManager(button, "watch"):
# Simulate a long-running task
import time
time.sleep(2)
print("Task completed")
# Create a button that triggers the task execution
button = tk.Button(root, text="Execute Task", command=execute_task)
# Display the button and start the Tkinter event loop
button.pack()
root.mainloop()
在这种情况下,它像预期的那样工作,但我不完全理解为什么它工作得很好,而前面的例子不工作。我错过了一些东西,但不知道它到底是什么。
1条答案
按热度按时间jobtbby31#
好吧,所以我尝试了线程,并提出了工作解决方案。不幸的是,它不是太优雅,但我没有更好的想法如何使它工作。我仍然不完全理解为什么我的问题中的示例1不起作用,而示例2起作用。所以,我的解决方案是在单独的线程中使用上下文管理器,那么tkinter mainloop显然不会被阻塞。下面是工作示例: