与spinbox控件变量一起使用时的Python线程错误

时间:2015-01-04 16:09:22

标签: python multithreading locking

终于得到了我的第一个线程脚本"有点"在各种教程和在线参考之间来回奔跑。 "有点"因为我在启动时仍然会遇到一些奇怪的错误。

我的计划目标

  1. 使用tkinter构建的积分向上/向下计数器GUI。 (Python 3.4.2)
  2. Spinbox作为用户入口点 - 用户输入" target"整数 或点击其上/下箭头。
  3. 在标签上显示数字时,显示标签上的延迟更新/ 以满足"目标" (2)中提到的整数
  4. 当标签上显示的数字等于时,自动停止更新 目标价值
  5. A" Go"用户输入目标值后,按钮开始上升/下降
  6. A"停止"按钮停止更新随时暂停上升/下降 在达到目标值之前
  7. 在这个简化的调试实现中,你会看到我似乎不必要地使用了spinbox控件变量。控制变量的实际(较长程序)应用于触发用户输入到旋转框中的验证程序。它实际上是控制变量,它给了我一些好奇的错误"在程序启动期间

    我的简化代码如下:

    import tkinter as tk
    import threading
    import time
    
    class controlPanel():
        def __init__(self, master):
            self.root = master
            self.buildWidgets()
    
        def buildWidgets(self):
            self.labelVar = 0
            self.ctrlVar  = tk.StringVar()
            self.ctrlVar.set(str(self.labelVar))
            self.delay = 0.5
            #+++++++++++++++++++++++++++++++++
            self.labelName  = tk.Label(self.root, text="Current Value: ", padx=3, pady=3)
            self.labelName.grid(row=0, column=0)
            self.labelValue = tk.Label(self.root, text=str(self.labelVar), padx=3, pady=3)
            self.labelValue.grid(row=0, column=1)
            #+++++++++++++++++++++++++++++++++
            self.spinboxName = tk.Label(self.root, text="Target: ", padx=3, pady=3)
            self.spinboxName.grid(row=1, column=0)
            self.spinBoxA = tk.Spinbox(self.root, from_=0, to=1000,
                                       textvariable=self.ctrlVar,
                                       width=10, justify=tk.CENTER)
            self.spinBoxA.grid(row=1, column=1)
            #+++++++++++++++++++++++++++++++++
            self.goButton   = tk.Button(self.root, text="Go", width=12,
                                        command=self.goButtonFunction,
                                        padx=3, pady=3)
            self.goButton.grid(row=2, column=1)
            #+++++++++++++++++++++++++++++++++
            self.stopButton = tk.Button(self.root, text="Stop", width=12,
                                        command=self.stopButtonFunction,
                                        padx=3, pady=3)
            self.stopButton.grid(row=2, column=0)
            #+++++++++++++++++++++++++++++++++
            #self.labelValue.update()
            #self.spinBoxA.update()
            self.root.update()
    
        def goButtonFunction(self):
            print('GO button clicked')
            self.flgRun = True
    
        def stopButtonFunction(self):
            print('STOP button clicked')
            self.flgRun = False
    
    
    
    class controlThread(controlPanel):
        def __init__(self, master, name):
            self.root = master
            self.name = name
            controlPanel.__init__(self, self.root)
    
            self.flgRun     = False
            self.flgRunLock = threading.Lock()
            self.pollPeriod = 100 # polling period, in ms
    
            self.thread1 = threading.Thread(target = self.towardsTarget,
                                            name=self.name)
            self.thread1.daemon = False
            self.thread1.start()
            #time.sleep(5)
            self.pollFlgRun()
        #+++++++++++++++++++++++++++++++++
        def pollFlgRun(self): # polls self.flgRun every self.pollPeriod
            if self.flgRun:
                print('<< Entering pollFlgRun >>')
                time.sleep(0.01)
                self.towardsTarget()
                #self.flgRunLock.acquire() # lock thread to reset self.flgRun
                self.flgRun = False       # reset self.flgRun
                #self.flgRunLock.release() # release thread
            self.root.after(self.pollPeriod, self.pollFlgRun)
        #+++++++++++++++++++++++++++++++++    
        def towardsTarget(self):
            delay = 0.01  # delay in seconds
            time.sleep(delay)
    
            print('<< Entering towardsTarget >>')
    
            #self.flgRunLock.acquire()
            print('self.labelVar : ', str(self.labelVar))
                # Problem 1: the following reference to self.ctrlVar gave error everytime the
                # program starts. The error>> "RuntimeError: main thread is not in main loop"
                # subsequent click on controlPanel.goButton will still give the program behavior
                # specified above (i.e. no more error on subsequent clicks on the "Go" button)
                #
                # Problem 2: and when placed in a lock.acquire()/release() block, clicking the 
                # controlPanel.goButton will freeze up program 
            print('self.ctrlVar : ', self.ctrlVar.get()) 
            #self.flgRunLock.release()
    
            # test self.flgRun as well in case reset by controlPanel.stopButton
            while( self.flgRun and str(self.labelVar) != self.ctrlVar.get() ):
                print('WHILE loop')
                if( self.labelVar < int(self.ctrlVar.get()) ):
                    self.labelVar +=1
                    print('self.labelVar before sleep> ', self.labelVar)
                    time.sleep(delay)
                    print('self.labelVar AFTER sleep> ', self.labelVar)
                    self.labelValue["text"] = str(self.labelVar)
                    self.labelValue.update()
                else:
                    self.labelVar -=1
                    print('self.labelVar before sleep> ', self.labelVar)
                    time.sleep(delay)
                    print('self.labelVar AFTER sleep> ', self.labelVar)
                    self.labelValue["text"] = str(self.labelVar)
                    self.labelValue.update()
    
    
    
    if __name__ == '__main__':
        root = tk.Tk()
        ctrl = controlThread(root, "X-thread")
    

    问题1:

    • class controlThread.towardsTarget() print声明中 引用self.ctrlVar每次程序都会引起错误 开始。错误是&#34; RuntimeError:主线程不在main中 环路&#34;
    • 随后点击&#34; Go&#34;按钮(controlPanel.goButton)仍将提供该程序 上面指定的行为(即后续点击&#34; Go&#34;按钮时没有更多错误)

    问题2:

    • 当问题1中提到的print语句放在a中时 lock.acquire()/lock.release()阻止,点击&#34; Go&#34;按键 (controlPanel.goButton)将冻结程序

    我已阅读以下两页和相关链接

    但是上面两页中提到的解决方案对我来说没有多大意义,因为错误信息&#34; RuntimeError:主线程不在主循环中#34;如果引用print引用self.ctrlVar语句完全被删除,则根本不会出现。

    我的问题是

    1. 问题1中导致此错误的原因是什么?
    2. 我期待lock.acquire()/lock.release()块能够解决 问题,但它最终冻结了程序。怎么能 打印&#39;可以避免这个问题。语句引用 self.ctrlVar到位了吗?

0 个答案:

没有答案