多线程 Python Tkinter 串行监视器中的按钮问题
Posted
技术标签:
【中文标题】多线程 Python Tkinter 串行监视器中的按钮问题【英文标题】:Button problem in multi-threading Python Tkinter Serial Monitor 【发布时间】:2021-01-25 15:44:38 【问题描述】:我尝试创建一个串行监视器,它可以使用 Tkinter 作为 GUI 从串行端口发送和接收消息。当程序搜索新数据时,我为没有冻结的 GUI 做了两个线程。
Tkinter GUI 很简单:
1 个条目用于放置要发送的文本 1 个标签用于显示收到的消息 1 个按钮用于发送条目消息我的问题是当我运行程序时,我点击了按钮,没有任何反应。我认为当我开始我的两个线程时按钮不再加载。我该如何解决这个问题?
import threading
from tkinter import *
import tkinter as tk
import serial
root = tk.Tk()
COM = "COM3"
ser = serial.Serial(port=COM, baudrate=9600, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=2)
ser.isOpen()
msg = ""
# read Serial
def ReadSerial():
global msg
msg = ""
msg = ser.readline()[:-2].decode("utf-8")
if msg != "":
print(msg)
return msg
# write Serial
def WriteSerial(sendmsg):
print("send")
ser.write(bytes(sendmsg, 'utf-8'))
ReadSerial()
# Tkinter
root.title("WIP NAME")
root.geometry("650x400")
inputData = Entry(root, text="<Slave1&p>") # input for enter the message to write
entrymsg = inputData.get() # get the massage
buttonMsg = Button(root, text="send", command = WriteSerial(entrymsg)) # create a send button for send the message
readData = Label(root, text=msg) # show message in Tkinter
ReadSerial()
# show items
inputData.grid()
readData.grid()
buttonMsg.grid()
# GUI thread
def TkinterGui():
while 1==1:
global msg
entrymsg = inputData.get()
# Serial thread
def SerialProgram():
while 1==1:
ReadSerial()
readData.update_idletasks()
x = threading.Thread(target=TkinterGui, args=())
y = threading.Thread(target=SerialProgram, args=())
x.start()
y.start()
root.mainloop()
【问题讨论】:
在我看来,您不应该使用threading
模块,而是重写您的函数以使用 tkinters after
方法。 tkinter 中的子线程通常不是一个好主意,而且很容易出错
command = WriteSerial(entrymsg)
应该是 command = lambda: WriteSerial(entrymsg)
或 command = lambda: WriteSerial(inputData.get())
。稍后使用将不需要运行TkinterGui()
。
我已经尝试过了,但问题是如果没有多线程,Tkinter 屏幕会冻结太多,因为它必须执行功能然后重新模拟屏幕。 @oskros
谢谢@acw1668,它有效!
【参考方案1】:
非常感谢@acw1668,我已经为这个项目工作了一周。 那正确的命令:
buttonMsg = Button(root, text="send", command = lambda: WriteSerial(inputData.get()))
以及整个代码:
import threading
from tkinter import *
import tkinter as tk
import serial
root = tk.Tk()
COM = "COM3"
ser = serial.Serial(port=COM, baudrate=9600, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=2)
ser.isOpen()
msg = ""
# read Serial
def ReadSerial():
global msg
msg = ""
msg = ser.readline()[:-2].decode("utf-8")
if msg != "":
print(msg)
return msg
# write Serial
def WriteSerial(sendmsg):
print("send")
ser.write(bytes(sendmsg, 'utf-8'))
ReadSerial()
# Tkinter
root.title("WIP NAME")
root.geometry("650x400")
inputData = Entry(root, text="<Slave1&p>") # input for enter the message to write
entrymsg = inputData.get() # get the massage
buttonMsg = Button(root, text="send", command = lambda: WriteSerial(inputData.get())) # create a send button for send the message
readData = Label(root, text=msg) # show message in Tkinter
ReadSerial()
# show items
inputData.grid()
readData.grid()
buttonMsg.grid()
# GUI thread
def TkinterGui():
while 1==1:
global msg
entrymsg = inputData.get()
# Serial thread
def SerialProgram():
while 1==1:
ReadSerial()
readData.update_idletasks()
x = threading.Thread(target=TkinterGui, args=())
y = threading.Thread(target=SerialProgram, args=())
x.start()
y.start()
root.mainloop()
P.S.:对不起,如果我的英语不是很容易理解,我是法国人:)
【讨论】:
其实你不需要运行TkinterGui()
。以上是关于多线程 Python Tkinter 串行监视器中的按钮问题的主要内容,如果未能解决你的问题,请参考以下文章
python——Tkinter图形化界面及threading多线程
将串行数据发送到 arduino 可以在串行监视器中使用,但不能在 python 中使用
使用带有事件循环和 QSocketNotifiers 的线程的问题串行端口监视
每当有来自串行端口 python 3.x 的新数据时,从串行数据更新 tkinter 标签