Tkinter只对一个按钮点击有效,其他无效?

0 投票
1 回答
1647 浏览
提问于 2025-04-18 07:14

我正在使用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

你说得对,程序卡在回调函数里了。Tkintermainloop()会和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()方法通常效果也很好。

撰写回答