多线程 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 标签

为啥我的 python 串行代码不起作用,而从 arduino 串行监视器发送相同的数据?

使用 tkinter 在 python 中进行多处理