pythonGUI之10: dearpygui实现tcp客户端调试工具
Dear PyGui 是一个用于构建图形用户界面(GUI)的 Python 开源库,具有以下特点和优势:
核心特点
- 即时模式 GUI:与传统的保留模式 GUI 框架不同,Dear PyGui 采用即时模式,界面元素在每一帧都会被重新绘制。
- 简单易用:API 设计简洁直观,学习曲线平缓,开发者可以快速上手。
- 高性能:基于 C++ 编写,使用 OpenGL 进行图形渲染,支持 GPU 加速,适合处理图形密集型任务。
- 跨平台支持:支持 Windows、Linux 和 macOS 等主流操作系统。
- 丰富的 GUI 组件:包含按钮、文本框、滑块、菜单、表格、绘图、节点编辑器等高级组件。
- 无依赖:安装后无需额外依赖,即可使用。
1.安装包
pip install dearpygui
Collecting dearpygui
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/26/2f/6cf64bfc46d0aac54273be8182a8ac185cea9028a323b01d43a27c5ee33e/dearpygui-2.1.0-cp39-cp39-win_amd64.whl (1.8 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 1.7 MB/s eta 0:00:00
Installing collected packages: dearpygui
Successfully installed dearpygui-2.1.0
2.TCP客户端源码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
TCP Client 网络调试助手(Dear PyGui 版)
2025-07-16
"""
import dearpygui.dearpygui as dpg
import socket
import threading
import binascii
import time
BUFFER = 4096
class TCPClient:
def __init__(self):
self.sock = None
self.alive = False
self.connected = False # 添加连接状态标志
self.hex_recv = False
self.hex_send = False
self.enable_tcl = False
self.create_gui()
def recv_thread(self):
while self.alive:
try:
data = self.sock.recv(BUFFER)
if not data:
break
if self.hex_recv:
text = binascii.hexlify(data).decode('utf-8') + '\n'
else:
text = data.decode('utf-8', errors='ignore')
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"<-- {text}\n")
except socket.timeout:
continue
except Exception as e:
if self.alive:
dpg.set_value("recv_text", dpg.get_value("recv_text") + f'[!] 接收异常: {e}\n')
break
dpg.set_value("recv_text", dpg.get_value("recv_text") + '[-] 连接已断开\n')
self.close_conn()
def on_connect(self):
if self.connected:
self.close_conn()
return
host = dpg.get_value("host_input")
port = dpg.get_value("port_input")
if not host or not port:
dpg.set_value("recv_text", dpg.get_value("recv_text") + "请输入地址和端口\n")
return
try:
port = int(port)
except ValueError:
dpg.set_value("recv_text", dpg.get_value("recv_text") + "端口必须为数字\n")
return
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(5) # 设置超时时间为5秒
try:
self.sock.connect((host, port))
self.alive = True
self.connected = True # 设置连接状态为 True
dpg.set_item_label("connect_button", "断开")
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"[+] 已连接 {host}:{port}\n")
threading.Thread(target=self.recv_thread, daemon=True).start()
except socket.timeout:
dpg.set_value("recv_text", dpg.get_value("recv_text") + "连接超时\n")
self.sock.close()
self.sock = None
except Exception as e:
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"连接失败: {e}\n")
self.sock.close()
self.sock = None
def on_send(self):
if not self.connected: # 检查是否已连接
dpg.set_value("recv_text", dpg.get_value("recv_text") + "请先连接服务器\n")
return
text = dpg.get_value("send_input")
if not text:
return
try:
if self.enable_tcl:
text = text # 需要加入TCL引擎,#TODO
if self.hex_send:
data = bytes.fromhex(text.replace(' ', ''))
else:
data = text.encode('utf-8', errors='ignore')
self.sock.sendall(data)
dpg.set_value("send_input", "")
except Exception as e:
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"[!] 发送失败: {e}\n")
self.close_conn()
def on_quick_send(self, sender, app_data, user_data):
if not self.connected: # 检查是否已连接
dpg.set_value("recv_text", dpg.get_value("recv_text") + "请先连接服务器\n")
return
text = dpg.get_value(user_data["text_ctrl"])
if not text:
return
delay = int(dpg.get_value(user_data["delay_ctrl"])) if dpg.get_value(user_data["delay_ctrl"]).isdigit() else 0
try:
if self.enable_tcl:
text = text # 需要加入TCL引擎,#TODO
if self.hex_send:
data = bytes.fromhex(text.replace(' ', ''))
else:
data = text.encode('utf-8', errors='ignore')
if dpg.get_value(user_data["delay_checkbox"]):
if delay > 0:
time.sleep(delay / 1000.0) # 延时单位为毫秒
self.sock.sendall(b'cmd:' + data)
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"-->>: cmd:{text}\n")
else:
self.sock.sendall(data)
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"-->: {text}\n")
except Exception as e:
dpg.set_value("recv_text", dpg.get_value("recv_text") + f"[!] 快捷发送失败: {e}\n")
self.close_conn()
def close_conn(self):
self.alive = False
if self.sock:
try:
self.sock.close()
dpg.set_item_label("connect_button", "连接")
dpg.set_value("recv_text", dpg.get_value("recv_text") + "[-] 连接已断开\n")
except:
pass
self.sock = None
self.connected = False # 设置连接状态为 False
def clear_recv_text(self):
dpg.set_value("recv_text", "")
def create_gui(self):
try:
with dpg.font_registry():
with dpg.font(r"C:\Windows\Fonts\simsun.ttc", 18) as default_font:
dpg.add_font_range_hint(dpg.mvFontRangeHint_Default)
dpg.add_font_range_hint(dpg.mvFontRangeHint_Chinese_Full)
except Exception as e:
print(f"字体加载失败: {e}")
with dpg.window(label="TCP Client 调试助手 V1.0", width=1200, height=800):
# 左侧:接收区和发送区
with dpg.group(horizontal=True):
# 左侧接收区和发送区
with dpg.child_window(width=720, height=-1, border=True) as left_panel:
# 连接区
with dpg.group(horizontal=True):
dpg.add_text("Host:")
dpg.add_input_text(tag="host_input", default_value="127.0.0.1", width=100)
dpg.add_text("Port:")
dpg.add_input_text(tag="port_input", default_value="5002", width=100)
dpg.add_button(tag="connect_button", label="连接", callback=self.on_connect)
# 接收区
dpg.add_text("接收")
dpg.add_input_text(tag="recv_text", multiline=True, readonly=True, height=560, width=700)
with dpg.group(horizontal=True):
dpg.add_checkbox(label="HEX 显示", tag="hex_recv_checkbox", callback=lambda sender: setattr(self, 'hex_recv', dpg.get_value(sender)))
dpg.add_button(label="清空接收区", callback=self.clear_recv_text)
dpg.add_checkbox(label="启用TCL", tag="enable_tcl_checkbox", callback=lambda sender: setattr(self, 'enable_tcl', dpg.get_value(sender)))
# 发送区
dpg.add_text("发送")
with dpg.group(horizontal=True):
dpg.add_input_text(tag="send_input", width=580, on_enter=True, callback=self.on_send)
dpg.add_checkbox(label="HEX", tag="hex_send_checkbox", callback=lambda sender: setattr(self, 'hex_send', dpg.get_value(sender)))
dpg.add_button(label="发送", callback=self.on_send)
# 右侧:快捷发送区
with dpg.child_window(width=480, height=-1, border=True) as right_panel:
with dpg.tab_bar():
for tab_idx in range(8):
with dpg.tab(label=f"指令区域{tab_idx + 1}"):
for row_idx in range(30):
with dpg.group(horizontal=True):
dpg.add_text(f"{row_idx + 1:02d}")
text_ctrl = dpg.add_input_text(width=250, tag=f"text_ctrl_{tab_idx}_{row_idx}")
delay_checkbox = dpg.add_checkbox(label="", tag=f"delay_checkbox_{tab_idx}_{row_idx}")
delay_ctrl = dpg.add_input_text(default_value="0", width=60, tag=f"delay_ctrl_{tab_idx}_{row_idx}")
dpg.add_button(label="发送", callback=self.on_quick_send, user_data={
"text_ctrl": f"text_ctrl_{tab_idx}_{row_idx}",
"delay_checkbox": f"delay_checkbox_{tab_idx}_{row_idx}",
"delay_ctrl": f"delay_ctrl_{tab_idx}_{row_idx}"
})
# 应用字体
dpg.bind_font(default_font)
def main():
dpg.create_context()
client = TCPClient()
dpg.create_viewport(title="TCP Client 调试助手 V1.0", width=1200, height=800)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
if __name__ == "__main__":
main()
3.运行效果


浙公网安备 33010602011771号