Possible locking issue in Tkinter application

老子叫甜甜 提交于 2019-12-23 23:00:57

问题


I'm trying to create a sliding menubar for my tkinter application, but I've run into an issue that I suspect comes from my not locking a thread properly. While I have been dabbling with Python for a while, I'm relatively new to both tkinter and threaded applications, and I hoped someone here might be able to shed a little light on what I'm doing wrong.

My code is as follows:

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)

I'm working within a canvas widget as it makes stylization simpler. The error - which I receive upon mousing over the menu bar - is as follows:

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'

Now the canvas method about which it is complaining works when I call it outside of a thread. It also merits mentioning that if I make any reference to self.bg in the helper function prior to the self.canvas.coords call no error occurs. Adding some useless reference however, hardly seems like a fix. I'm worried that if I don't address this now it will only exacerbate some other issue later on.

I'm I right to assume that I need to lock my thread so as to let it reference self.bg without issue, or is there something here I'm missing? I tried adding a lock to the MenuBar class, acquiring it and releasing it in the helper method, but to no avail.

Any one have any idea? Thanks.


回答1:


Tkinter isn't thread safe. You cannot call methods on widgets from any thread other than the one where the widget was created. Adding locking won't help.

For something as simple as sliding a menu in and out, you don't need threads. There are several examples of doing animation with Tkinter by leveraging the event loop. Basically the algorithm looks like this:

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

What it does is simple: it moves your widget one or two pixels, checks to see if it's fully visible or not, and if not, it reschedules itself to run again in a few milliseconds. You can adjust the speed and smoothness of the animation by adjusting how many pixels you move on each iteration, and how many milliseconds between each frame of animation.



来源:https://stackoverflow.com/questions/17499511/possible-locking-issue-in-tkinter-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!