Tkinter只对一个按钮点击有效,其他无效?
我正在使用Tkinter窗口通过串口向Arduino发送信息,以控制步进电机转动一定的步数。简单来说,我有一些按钮,每个按钮对应我想让电机转动的步数。当我按下这些按钮时,我希望电机能转动相应的步数。我会贴一些我的代码片段,但基本上我的问题是,窗口在第一次按按钮时运行得很好,但当我点击其他按钮想让电机继续转动时,就没有反应了。感觉好像Tkinter窗口只对一次点击有效,或者在回调函数里卡住了什么。
回调函数:
def firstGrating():
arduino.write('1800')
tkMessageBox.showwarning(title= 'Spectrometer', message = 'I am moving to the 1800 Grating...')
tkMessageBox.showwarning(title= 'Spectrometer', message = 'Please Wait Until I Tell You That I AM FINISHED!!!')
while True:
message = arduino.readline()
if len(message) > 10:
tkMessageBox.showwarning(title= 'Spectrometer', message = message)
return
def secondGrating():
arduino.write('150')
tkMessageBox.showwarning(title= 'Spectrometer', message = 'I am moving to the 150 Grating...')
tkMessageBox.showwarning(title= 'Spectrometer', message = 'Please Wait Until I Tell You That I AM FINISHED!!!')
while True:
message = arduino.readline()
if len(message) > 10:
tkMessageBox.showwarning(title= 'Spectrometer', message = message)
return
def thirdGrating():
arduino.write('3600')
tkMessageBox.showwarning(title= 'Spectrometer', message = 'I am moving to the 3600 Grating...')
tkMessageBox.showwarning(title= 'Spectrometer', message = 'Please Wait Until I Tell You That I AM FINISHED!!!')
while True:
message = arduino.readline()
if len(message) > 10:
tkMessageBox.showwarning(title= 'Spectrometer', message = message)
return
这是我尝试设置Tkinter窗口的部分:
win = Tk()
win.geometry("600x400+500+500")
win.title('Spectrometer Controller')
mlabel = Label(text = 'Select One of The Available Gratings')
mlabel.pack()
mButton1 = Button(win, text = '1800', command = lambda: firstGrating())
mButton1.pack()#.grid(row=0, column=1)
mButton2 = Button(win, text = '150', command = lambda: secondGrating())
mButton2.pack()#.grid(row=0, column=2)
mButton3 = Button(win, text = '3600', command = lambda: thirdGrating())
mButton3.pack()#.grid(row=0, column=3)
win.mainloop()
1 个回答
1
你说得对,程序卡在回调函数里了。Tkinter
的mainloop()
会和while
循环发生冲突,这样程序就会变得无响应,这时候你就无法在while
循环运行的时候按其他按钮。
你可以看看after()
这个方法,它可以帮助你创建一个程序循环,让你的界面保持响应。下面是一个例子:
def callback(flag):
global loop
if flag is True:
print('message')
... other logic ...
# start the after method to call the callback every 100ms
loop = root.after(100, callback, True)
else:
# cancel the after method if the flag is False
root.after_cancel(loop)
root = Tk()
# use a lambda expression to pass arg to callback in button commands
Button(root, text='start', command=lambda: callback(True)).pack()
Button(root, text='stop', command=lambda: callback(False)).pack()
mainloop()
你也可以把界面和业务逻辑放在不同的线程里,但这样设置起来通常比较麻烦。使用after()
方法通常效果也很好。