python编写的串口调试工具,待完善......

根据python编写的串口调试工具,学习布局中,待完善…
界面如下:
在这里插入图片描述
跳转到整体实现代码

根据sscom的界面进行实现,首先实现界面的整体布局,之后再实现不同部件的功能,下列创建画布的实现代码:

import tkinter as tk
from tkinter import ttk

class SerialDebugTool:
    def __init__(self, root):
        self.root = root
        self.root.title("串口调试工具")    # 设置工具名称
        self.root.geometry("620x600")    # 设置窗口大小
        self.root.resizable(False, False)  # 禁止调整窗口大小

if __name__ == "__main__":
    root = tk.Tk()
    app = SerialDebugTool(root)
    root.mainloop()

之后就可以进行界面布局插件的插入了
创建一个 create_widgets() 函数,用于布局用:

        self.create_widgets()
    def create_widgets(self):
       pass

创建数据接收框

这段代码是用来创建一个带有滚动条的文本框,用于显示串口的输出。这里使用了 tkinter 库来创建用户界面。首先创建了一个 Text 组件 self.serial_output,然后创建了一个 Scrollbar 组件 scrollbar_output,并将其与 Text 组件绑定,实现滚动功能。

  self.serial_output = tk.Text(self.root, height=25, width=85)
  self.serial_output.place(x=15, y=10)

  # 添加滚轴
  scrollbar_output = tk.Scrollbar(self.root, command=self.serial_output.yview)
  scrollbar_output.place(x=600, y=10, height=329)
  self.serial_output.config(yscrollcommand=scrollbar_output.set)

在测试过程中,会出现卡顿现象,所以在这里将收到的数据添加到一个任务中,如下所示:

class SerialReaderThread(threading.Thread):
    def __init__(self, serial_port, callback, gui):
        super().__init__()
        self.serial_port = serial_port
        self.callback = callback
        self.gui = gui
        self._is_running = threading.Event()

    def stop(self):
        self._is_running.clear()

    def run(self):
        self._is_running.set()
        while self._is_running.is_set():
            if self.serial_port.in_waiting > 0:
                data = self.serial_port.readline()
                self.callback(data)
                self.gui.update_serial_output(data)

并在class SerialDebugTool中调用

    def update_serial_output(self, data):
        try:
            if self.hex_display_var.get():  # 如果选择了以十六进制显示接收的数据
                raw_data = ' '.join(format(byte, '02X') for byte in data)
            else:
                # 尝试使用 UTF-8 编码解码字节数据
                raw_data = data.decode('utf-8').strip()
        except UnicodeDecodeError:
            # 如果解码失败,则使用 errors='ignore' 参数忽略无法解码的字节
            #raw_data = data.decode('utf-8', errors='ignore').strip()
            # 如果解码失败,则使用 errors='replace' 参数替换无法解码的字节
            raw_data = data.decode('utf-8', errors='replace').strip()
            # 记录乱码数据到日志
            logging.warning("Received malformed data: %s", raw_data)

        if raw_data:
            if self.add_timestamp.get():  # 如果勾选了添加时间戳,则在数据前面添加时间戳
                timestamp = time.strftime("[%Y-%m-%d %H:%M:%S] ", time.localtime())
                raw_data = timestamp + raw_data

            # 显示接收到的数据
            self.serial_output.insert(tk.END, f"{raw_data}\n")
            self.serial_output.see(tk.END)  # 滚动到最后一行

串口和波特率选择部分的用户界面
这段代码实现了一个简单的串口选择界面,允许用户从可用的串口列表中选择一个串口,并提供了一个刷新按钮来更新可用串口列表。get_available_ports() 方法用于获取当前系统中可用的串口列表,并将其返回给 ports。然后,创建了一个 Combobox 组件 port_combobox,将可用的串口列表 ports 作为选项值,设置 state=“readonly” 表示用户只能选择而不能编辑。

        # 串口标签
        self.port_label = ttk.Label(self.root, text="端口号:")
        self.port_label.place(x=15, y=355)

        # 获取可用端口并设置组合框
        ports = self.get_available_ports()
        self.port_combobox = ttk.Combobox(self.root, values=ports, state="readonly")
        self.port_combobox.place(x=70, y=355)
        # 默认显示第一个可用端口
        if ports:
            self.port_combobox.set(ports[0])

        self.refresh_button = ttk.Button(self.root, text="刷新", command=self.refresh_ports)
        self.refresh_button.place(x=245, y=353)

刷新按钮则是当有新设备接入时,则可点击,对于的事件为:refresh_ports, 实现如下:

    def refresh_ports(self):
        ports = self.get_available_ports()
        self.port_combobox['values'] = ports
        if ports:
            self.port_combobox.set(ports[0])  # 刷新后重新设置为第一个端口

获取端口的函数如下:

    def get_available_ports(self):
        ports = [port.device for port in serial.tools.list_ports.comports()]
        return ports

同理,波特率也是一样实现的

        self.baudrate_label = ttk.Label(self.root, text="波特率:")
        self.baudrate_label.place(x=15, y=390)

        self.baudrate_combobox = ttk.Combobox(self.root, values=["9600", "19200", "38400", "57600", "115200"], state="readonly")
        self.baudrate_combobox.place(x=70, y=390)
        self.baudrate_combobox.set("9600")

当串口打开时,切换波特率和串口,需将原本连接的串口关闭再打开, 则给波特率和port都绑定事件:

        # 绑定事件处理函数到端口号组合框的事件上
        self.port_combobox.bind("<<ComboboxSelected>>", self.on_baudrate_and_port_combobox_change)
 		# 绑定事件处理函数
        self.baudrate_combobox.bind("<<ComboboxSelected>>", self.on_baudrate_and_port_combobox_change)

    def on_baudrate_and_port_combobox_change(self, event):
        # Check if currently connected to a different serial port
        if self.serial_port is not None and self.serial_port.is_open:
            self.disconnect()
            self.connect()

创建打开串口按钮及指示器

代码如下:

        # 连接按钮和状态指示器
        self.connect_button = ttk.Button(self.root, text="打开串口", command=self.toggle_connection)
        self.connect_button.place(x=245, y=390)
        
        # 创建Canvas时,设置其背景颜色与页面背景色相同
        self.status_indicator = tk.Canvas(self.root, width=20, height=20, bg=self.root.cget('bg'), highlightthickness=0)
        # 将状态指示器放置在连接按钮的左侧
        self.status_indicator.place(x=335, y=392)
        self.update_status_indicator(False)

其当打开串口成功后,则指示灯为绿色,之后按钮变为关闭串口,当串口关闭后,则指示灯对应为红色

    def toggle_connection(self):
        if not self.connected:
            self.connect()
        else:
            self.disconnect()

    def connect(self):
        port = self.port_combobox.get()
        baudrate = int(self.baudrate_combobox.get())

        if not port:
            messagebox.showerror("Error", "Please select a serial port.")
            return

        try:
            # 初始化新的串口对象
            self.serial_port = serial.Serial(port, baudrate)
            self.reader_thread = SerialReaderThread(self.serial_port, self.handle_data, self)
            self.reader_thread.start()
            self.serial_port.timeout = 0.1  # 设置读取超时时间
            self.connected = True
            self.connect_button.config(text="关闭串口")
            self.update_status_indicator(True)
            #self.root.after(100, self.read_serial)
        except serial.SerialException as e:
            messagebox.showerror("Error", str(e))

    def handle_data(self, data):
        print("Received:", data)

    def disconnect(self):
        if self.reader_thread:
            self.reader_thread.stop()
            self.reader_thread.join()
        if self.serial_port and self.serial_port.is_open:
            self.serial_port.close()
        self.connected = False
        self.connect_button.config(text="打开串口")
        self.update_status_indicator(False)

创建添加回车换行、时间戳、hex显示及定时发送选项

        self.add_newline_checkbox = tk.Checkbutton(self.root, text="加回车换行", variable=self.add_newline)
        self.add_newline_checkbox.place(x=15, y=420)

        self.add_timestamp_checkbox = tk.Checkbutton(self.root, text="加时间戳", variable=self.add_timestamp)
        self.add_timestamp_checkbox.place(x=100, y=420)

        self.hex_display_checkbox = tk.Checkbutton(self.root, text="Hex显示", variable=self.hex_display_var)
        self.hex_display_checkbox.place(x=180, y=420)

        self.timed_transmission_checkbox = tk.Checkbutton(self.root, text="定时发送:", variable=self.timed_transmission, command=self.toggle_timed_transmission)
        self.timed_transmission_checkbox.place(x=250, y=420)

        self.time_entry = tk.Text(self.root, height=1, width=8)
        self.time_entry.insert("1.0", "1000")  # 插入默认文本
        self.time_entry.place(x=330, y=425)

        self.time_label = ttk.Label(self.root, text="ms/s")
        self.time_label.place(x=390, y=423)

其选项对应的实现逻辑如下所示:

     def toggle_timed_transmission(self):
        if self.timed_transmission.get():
            self.start_timed_transmission()
        else:
            self.stop_timed_transmission()

    def start_timed_transmission(self):
        interval = int(self.time_entry.get("1.0", "end-1c")) / 1000  # 将毫秒转换为秒
        self.timed_transmission.set(True)  # 设置标志位,让循环开始
        self.timed_transmission_loop(interval)

    def stop_timed_transmission(self):
        if hasattr(self, 'timed_transmission_id'):
            self.timed_transmission.set(False)  # 设置标志位,让循环退出
            self.root.after_cancel(self.timed_transmission_id)  # 取消之前创建的定时任务

    def timed_transmission_loop(self, interval):
        if self.timed_transmission.get():
            data = self.send_entry.get("1.0", "end-1c")  # 获取输入框中的数据
            if data and self.serial_is_open():  # 如果数据不为空且串口打开
                self.send_data()
            self.timed_transmission_id = self.root.after(int(interval * 1000), self.timed_transmission_loop, interval)

    def serial_is_open(self):
        # 检查串口是否打开,这里假设返回 True 表示串口已打开
        if self.serial_port is not None and self.serial_port.is_open:
            return True
        else:
            return False

创建发送数据输入框

        self.send_entry = tk.Text(self.root, height=10, width=85)
        self.send_entry.place(x=15, y=453)

在其上方添加发送按钮


        self.send_button = ttk.Button(self.root, text="发送", command=self.send_data)
        self.send_button.place(x=525, y=420)

其send_data的实现逻辑如下,并将发送的数据显示在数据接收框内:

    def send_data(self):
        data = self.send_entry.get("1.0", "end-1c")

        timestamp = ""
        if self.add_timestamp.get():  # 如果勾选了添加时间戳,则记录时间戳
            timestamp = time.strftime("[%Y-%m-%d %H:%M:%S] ", time.localtime())
        if self.add_newline.get():  # 如果勾选了添加换行符
            data += "\r\n"
        encoded_data = data.encode('utf-8')  # 将字符串编码为字节形式

        if self.connected and self.serial_port:
            self.serial_port.write(encoded_data)

            if self.hex_display_var.get():  # 如果选择了以十六进制显示发送数据
                hex_data = binascii.hexlify(encoded_data).decode("utf-8")
                hex_data_spaced = ' '.join(hex_data[i:i + 2] for i in range(0, len(hex_data), 2))
                if timestamp:  # 如果有时间戳,则在显示时添加时间戳
                    self.serial_output.insert(tk.END, f"{timestamp}{hex_data_spaced}\n")
                else:
                    self.serial_output.insert(tk.END, f"{hex_data_spaced}\n")
            else:
                if timestamp:  # 如果有时间戳,则在显示时添加时间戳
                    self.serial_output.insert(tk.END, f"{timestamp}{data}\n")
                else:
                    self.serial_output.insert(tk.END, f"{data}\n")

            self.serial_output.see(tk.END)

创建清除数据接收框内容按钮
代码如下:

        self.clear_button = ttk.Button(self.root, text="清除", command=self.clear_data)
        self.clear_button.place(x=435, y=420)

其clear_data的实现逻辑如下:

    def clear_data(self):
        # 清除文本框中的内容
        self.serial_output.config(state="normal")
        self.serial_output.delete(1.0, "end")

因为整体有两个任务,则在直接关闭窗口时可绑定事件,对其进行销毁:

    def __init__(self, root):
        self.root = root
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        self.reader_thread = None
        .....
    def on_close(self):
        if self.reader_thread:
            self.reader_thread.stop()
        self.stop_timed_transmission()
        self.root.destroy()
        sys.exit()  # 退出整个程序

整体的实现代码如下所示

import serial
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import serial.tools.list_ports
import time
import binascii
import threading
import logging
import sys

class SerialReaderThread(threading.Thread):
    def __init__(self, serial_port, callback, gui):
        super().__init__()
        self.serial_port = serial_port
        self.callback = callback
        self.gui = gui
        self._is_running = threading.Event()

    def stop(self):
        self._is_running.clear()

    def run(self):
        self._is_running.set()
        while self._is_running.is_set():
            if self.serial_port.in_waiting > 0:
                data = self.serial_port.readline()
                self.callback(data)
                self.gui.update_serial_output(data)

class SerialDebugTool:
    def __init__(self, root):
        self.root = root
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        self.root.title("串口调试工具")
        self.root.geometry("620x600")
        self.root.resizable(False, False)  # 禁止调整窗口大小

        self.serial_port = None
        self.serial_baudrate = 9600
        self.connected = False
        self.add_newline = tk.BooleanVar()  # 用于跟踪是否勾选添加回车换行
        self.add_timestamp = tk.BooleanVar()  # 用于跟踪是否勾选添加时间戳
        self.hex_display_var = tk.BooleanVar()  # 用于跟踪是否勾选hex显示
        self.timed_transmission = tk.BooleanVar()
        self.timed_transmission.set(False)
        self.reader_thread = None

        self.create_widgets()

    def on_close(self):
        if self.reader_thread:
            self.reader_thread.stop()
        self.stop_timed_transmission()
        self.root.destroy()
        sys.exit()  # 退出整个程序

    def create_widgets(self):
        # 数据接收框
        self.serial_output = tk.Text(self.root, height=25, width=85)
        self.serial_output.place(x=15, y=10)

        # 添加滚轴
        scrollbar_output = tk.Scrollbar(self.root, command=self.serial_output.yview)
        scrollbar_output.place(x=600, y=10, height=329)
        self.serial_output.config(yscrollcommand=scrollbar_output.set)

        # 串口和波特率标签
        self.port_label = ttk.Label(self.root, text="端口号:")
        self.port_label.place(x=15, y=355)

        # 获取可用端口并设置组合框
        ports = self.get_available_ports_desc()
        self.port_combobox = ttk.Combobox(self.root, values=ports, state="readonly")
        self.port_combobox.place(x=70, y=355)
        # 默认显示第一个可用端口
        if ports:
            self.port_combobox.set(ports[0])

        # 绑定事件处理函数到端口号组合框的事件上
        self.port_combobox.bind("<<ComboboxSelected>>", self.on_baudrate_and_port_combobox_change)
        self.port_combobox.bind("<Button-1>", self.on_combobox_click)
        self.port_combobox.bind("<Leave>", self.on_combobox_leave)

        self.refresh_button = ttk.Button(self.root, text="刷新", command=self.refresh_ports)
        self.refresh_button.place(x=245, y=353)

        self.baudrate_label = ttk.Label(self.root, text="波特率:")
        self.baudrate_label.place(x=15, y=390)

        self.baudrate_combobox = ttk.Combobox(self.root, values=["9600", "19200", "38400", "57600", "115200"], state="readonly")
        self.baudrate_combobox.place(x=70, y=390)
        self.baudrate_combobox.set("9600")

        # 绑定事件处理函数
        self.baudrate_combobox.bind("<<ComboboxSelected>>", self.on_baudrate_and_port_combobox_change)

        # 连接按钮和状态指示器
        self.connect_button = ttk.Button(self.root, text="打开串口", command=self.toggle_connection)
        self.connect_button.place(x=245, y=390)

        # 创建Canvas时,设置其背景颜色与页面背景色相同
        self.status_indicator = tk.Canvas(self.root, width=20, height=20, bg=self.root.cget('bg'), highlightthickness=0)
        # 将状态指示器放置在连接按钮的左侧
        self.status_indicator.place(x=335, y=392)
        self.update_status_indicator(False)

        self.add_newline_checkbox = tk.Checkbutton(self.root, text="加回车换行", variable=self.add_newline)
        self.add_newline_checkbox.place(x=15, y=420)

        self.add_timestamp_checkbox = tk.Checkbutton(self.root, text="加时间戳", variable=self.add_timestamp)
        self.add_timestamp_checkbox.place(x=100, y=420)

        self.hex_display_checkbox = tk.Checkbutton(self.root, text="Hex显示", variable=self.hex_display_var)
        self.hex_display_checkbox.place(x=180, y=420)

        self.timed_transmission_checkbox = tk.Checkbutton(self.root, text="定时发送:", variable=self.timed_transmission, command=self.toggle_timed_transmission)
        self.timed_transmission_checkbox.place(x=250, y=420)

        self.time_entry = tk.Text(self.root, height=1, width=8)
        self.time_entry.insert("1.0", "1000")  # 插入默认文本
        self.time_entry.place(x=330, y=425)

        self.time_label = ttk.Label(self.root, text="ms/s")
        self.time_label.place(x=390, y=423)

        self.clear_button = ttk.Button(self.root, text="清除", command=self.clear_data)
        self.clear_button.place(x=435, y=420)

        self.send_button = ttk.Button(self.root, text="发送", command=self.send_data)
        self.send_button.place(x=525, y=420)

        self.send_entry = tk.Text(self.root, height=10, width=85)
        self.send_entry.place(x=15, y=453)

    def on_combobox_leave(self, event):
        self.port_combobox.config(width=20)  # 鼠标离开时恢复下拉框的宽度为10

    def on_combobox_click(self, event):  # 注意这里多了一个 self 参数
        self.port_combobox.config(width=38)  # 修改下拉框的宽度为20

    def clear_data(self):
        # 清除文本框中的内容
        self.serial_output.config(state="normal")
        self.serial_output.delete(1.0, "end")
        #self.serial_output.config(state="disable")

    def toggle_timed_transmission(self):
        if self.timed_transmission.get():
            self.start_timed_transmission()
        else:
            self.stop_timed_transmission()

    def start_timed_transmission(self):
        interval = int(self.time_entry.get("1.0", "end-1c")) / 1000  # 将毫秒转换为秒
        self.timed_transmission.set(True)  # 设置标志位,让循环开始
        self.timed_transmission_loop(interval)

    def timed_transmission_loop(self, interval):
        if self.timed_transmission.get():
            data = self.send_entry.get("1.0", "end-1c")  # 获取输入框中的数据
            if data and self.serial_is_open():  # 如果数据不为空且串口打开
                self.send_data()
            self.timed_transmission_id = self.root.after(int(interval * 1000), self.timed_transmission_loop, interval)

    def stop_timed_transmission(self):
        if hasattr(self, 'timed_transmission_id'):
            self.timed_transmission.set(False)  # 设置标志位,让循环退出
            self.root.after_cancel(self.timed_transmission_id)  # 取消之前创建的定时任务

    def serial_is_open(self):
        # 检查串口是否打开,这里假设返回 True 表示串口已打开
        if self.serial_port is not None and self.serial_port.is_open:
            return True
        else:
            return False

    def on_baudrate_and_port_combobox_change(self, event):
        self.port_combobox.config(width=20)  # 修改下拉框的宽度为20

        # Check if currently connected to a different serial port
        if self.serial_port is not None and self.serial_port.is_open:
            self.disconnect()
            self.connect()


    def send_data(self):
        data = self.send_entry.get("1.0", "end-1c")

        timestamp = ""
        if self.add_timestamp.get():  # 如果勾选了添加时间戳,则记录时间戳
            timestamp = time.strftime("[%Y-%m-%d %H:%M:%S] ", time.localtime())
        if self.add_newline.get():  # 如果勾选了添加换行符
            data += "\r\n"
        encoded_data = data.encode('utf-8')  # 将字符串编码为字节形式

        if self.connected and self.serial_port:
            self.serial_port.write(encoded_data)

            if self.hex_display_var.get():  # 如果选择了以十六进制显示发送数据
                hex_data = binascii.hexlify(encoded_data).decode("utf-8")
                hex_data_spaced = ' '.join(hex_data[i:i + 2] for i in range(0, len(hex_data), 2))
                if timestamp:  # 如果有时间戳,则在显示时添加时间戳
                    self.serial_output.insert(tk.END, f"{timestamp}{hex_data_spaced}\n")
                else:
                    self.serial_output.insert(tk.END, f"{hex_data_spaced}\n")
            else:
                if timestamp:  # 如果有时间戳,则在显示时添加时间戳
                    self.serial_output.insert(tk.END, f"{timestamp}{data}\n")
                else:
                    self.serial_output.insert(tk.END, f"{data}\n")

            self.serial_output.see(tk.END)

    def get_available_ports(self):
        ports = [port.device for port in serial.tools.list_ports.comports()]
        return ports

    def get_available_ports_desc(self):
        ports_info = serial.tools.list_ports.comports()
        ports = [f"{port.device} {port.description.replace(port.device, '').replace('(', '').replace(')', '').strip()}"
                 for port in ports_info]
        return ports

    def refresh_ports(self):
        ports = self.get_available_ports_desc()
        self.port_combobox['values'] = ports
        if ports:
            self.port_combobox.set(ports[0])  # 刷新后重新设置为第一个端口

    def toggle_connection(self):
        if not self.connected:
            self.connect()
        else:
            self.disconnect()

    def connect(self):
        modified_port = self.port_combobox.get()
        port = modified_port.split(' ')[0]  # 只获取设备信息,去掉描述信息
        baudrate = int(self.baudrate_combobox.get())

        if not port:
            messagebox.showerror("Error", "Please select a serial port.")
            return

        try:
            # 初始化新的串口对象
            self.serial_port = serial.Serial(port, baudrate)
            self.reader_thread = SerialReaderThread(self.serial_port, self.handle_data, self)
            self.reader_thread.start()
            self.serial_port.timeout = 0.1  # 设置读取超时时间
            self.connected = True
            self.connect_button.config(text="关闭串口")
            self.update_status_indicator(True)
            #self.root.after(100, self.read_serial)
        except serial.SerialException as e:
            messagebox.showerror("Error", str(e))

    def handle_data(self, data):
        print("Received:", data)

    def disconnect(self):
        if self.reader_thread:
            self.reader_thread.stop()
            self.reader_thread.join()
        if self.serial_port and self.serial_port.is_open:
            self.serial_port.close()
        self.connected = False
        self.connect_button.config(text="打开串口")
        self.update_status_indicator(False)

    def read_serial(self):
        if self.connected and self.serial_port:
            try:
                raw_data = self.serial_port.readline()
                if raw_data:
                    if self.hex_display_var.get():  # 如果选择了以十六进制显示接收的数据
                        data = ' '.join(format(byte, '02X') for byte in raw_data)
                    else:
                        try:
                            # 尝试使用 UTF-8 编码解码字节数据
                            data = raw_data.decode('utf-8').strip()
                        except UnicodeDecodeError:
                            # 如果解码失败,则使用 errors='ignore' 参数忽略无法解码的字节
                            data = raw_data.decode('utf-8', errors='ignore').strip()

                    if data:
                        if self.add_timestamp.get():  # 如果勾选了添加时间戳,则在数据前面添加时间戳
                            timestamp = time.strftime("[%Y-%m-%d %H:%M:%S] ", time.localtime())
                            data = timestamp + data

                        # 显示接收到的数据
                        self.serial_output.insert(tk.END, f"{data}\n")
                        self.serial_output.see(tk.END)  # 滚动到最后一行
            except serial.SerialException:
                pass
        # 设置下一次读取串口数据的定时器
        self.root.after(100, self.read_serial)

    def update_serial_output(self, data):
        try:
            if self.hex_display_var.get():  # 如果选择了以十六进制显示接收的数据
                raw_data = ' '.join(format(byte, '02X') for byte in data)
            else:
                # 尝试使用 UTF-8 编码解码字节数据
                raw_data = data.decode('utf-8').strip()
        except UnicodeDecodeError:
            # 如果解码失败,则使用 errors='ignore' 参数忽略无法解码的字节
            #raw_data = data.decode('utf-8', errors='ignore').strip()
            # 如果解码失败,则使用 errors='replace' 参数替换无法解码的字节
            raw_data = data.decode('utf-8', errors='replace').strip()
            # 记录乱码数据到日志
            logging.warning("Received malformed data: %s", raw_data)

        if raw_data:
            if self.add_timestamp.get():  # 如果勾选了添加时间戳,则在数据前面添加时间戳
                timestamp = time.strftime("[%Y-%m-%d %H:%M:%S] ", time.localtime())
                raw_data = timestamp + raw_data

            # 显示接收到的数据
            self.serial_output.insert(tk.END, f"{raw_data}\n")
            self.serial_output.see(tk.END)  # 滚动到最后一行

    def update_status_indicator(self, connected):
        color = "green" if connected else "red"
        self.status_indicator.delete("all")
        oval_size = 15  # 圆形的大小
        oval_x = (20 - oval_size) / 2  # 圆形的x坐标
        oval_y = (20 - oval_size) / 2  # 圆形的y坐标
        outline_color = "black"  # 外轮廓颜色
        self.status_indicator.create_oval(oval_x, oval_y, oval_x + oval_size, oval_y + oval_size, fill=color,
                                          outline=outline_color)  # 使用fill参数填充颜色,并且outline参数设置外轮廓颜色

if __name__ == "__main__":
    root = tk.Tk()
    app = SerialDebugTool(root)
    root.mainloop()


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落淼喵_G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值