Skip to main content
 首页 » 编程设计

python之Tkinter 应用程序中可能存在锁定问题

2025年05月04日26yjmyzz

我正在尝试为我的 tkinter 应用程序创建一个滑动菜单栏,但我遇到了一个问题,我怀疑是因为我没有正确锁定线程。虽然我已经涉足 Python 一段时间了,但我对 tkinter 和线程应用程序都比较陌生,我希望这里的某个人能够阐明我做错了什么。

我的代码如下:

class MenuBar(): 
 
def slide_out(self, event = None): 
 
    def helper(): 
        while self.canvas.coords(self.bg)[0] > 100 and self.mouseIn: 
            self.canvas.move(self.bg, -5, 0) 
            sleep(0.01) 
 
    self.mouseIn = True 
    Thread(target = helper).start() 
 
def slide_in(self, event): 
    self.mouseIn = False 
    self.canvas.coords(self.bg, 750, 0) 
 
def __init__(self, canvas): 
    self.canvas = canvas 
 
    self.bgImg = ImageTk.PhotoImage(file = "Options Bar.png") 
    self.bg = canvas.create_image(750, 0, anchor = "nw", image = self.bgImg, tags = ("menubar", "menubarbackground")) 
 
    self.mouseIn = False 
 
    self.canvas.tag_bind("menubar", "<Enter>", self.slide_out) 
    self.canvas.tag_bind("menubar", "<Leave>", self.slide_in) 

我在 Canvas 小部件中工作,因为它使样式化更简单。将鼠标悬停在菜单栏上时收到的错误如下:

Exception in thread Thread-1: 
Traceback (most recent call last): 
  File "C:\Python33\lib\threading.py", line 639, in _bootstrap_inner 
    self.run() 
  File "C:\Python33\lib\threading.py", line 596, in run 
    self._target(*self._args, **self._kwargs) 
  File "C:\Users\alex\Desktop\Python - VN Work\readingscreen.py", line 12, in helper 
    while self.canvas.coords(self.bg)[0] > 100 and self.mouseIn: 
  File "C:\Python33\lib\tkinter\__init__.py", line 2264, in coords 
    self.tk.call((self._w, 'coords') + args))] 
  File "C:\Python33\lib\tkinter\__init__.py", line 2262, in <listcomp> 
    return [getdouble(x) for x in 
ValueError: could not convert string to float: 'None' 

现在,当我在线程外调用它时,它提示的 canvas 方法起作用了。还值得一提的是,如果我在 self.canvas.coords 调用之前在辅助函数中引用 self.bg,则不会发生错误。然而,添加一些无用的引用似乎很难解决。我担心如果我现在不解决这个问题,以后只会加剧其他一些问题。

我假设我需要锁定我的线程以便让它毫无问题地引用 self.bg 是正确的,或者这里有什么我遗漏的?我尝试向 MenuBar 类添加一个锁,在辅助方法中获取并释放它,但无济于事。

有人知道吗?谢谢。

请您参考如下方法:

Tkinter 不是线程安全的。您不能从创建小部件的线程以外的任何线程调用小部件上的方法。添加锁定不会有帮助。

对于像滑入和滑出菜单这样简单的事情,您不需要线程。有几个利用事件循环使用 Tkinter 制作动画的示例。算法基本上是这样的:

def animate(...): 
    <move the widget one or two pixels> 
    <if the widget needs to move some more>: 
        self.canvas.after(100, animate) 

它的作用很简单:它将您的小部件移动一到两个像素,检查它是否完全可见,如果不可见,它会重新安排自身在几毫秒后再次运行。您可以通过调整每次迭代移动的像素数以及每帧动画之间的毫秒数来调整动画的速度和平滑度。