一. 前言
这1-2个月太忙了 ,完全没有时间做整理 ,所剩无几的时间也在维护开源项目在,所以这一篇就简简单单的分析一个工具吧。
这个工具是在写开源的时候找了半天找到的 ,虽然还不完美 ,但是已经有很大的帮助了。
二. PyQtInspect 基础使用
写过 PyQT 项目的兄弟 ,应该都有感觉 ,不像开发前端 ,可以在Chrome 上面进行调整。 在纯代码写 PyQT 项目的时候 ,界面上的组件对应代码哪个部分 ,纯粹靠经验和猜。
早期自己的代码可能问题不大 ,但是时间一久 ,就很麻烦了。
PyQtInspect 是什么 ?
@ PyqtInspect | PyqtInspect, a Chrome DevTool-like inspector for PyQt/PySide.
PyQtInspect 是一个强大的 PyQt/PySide 应用程序调试和检查工具 ,其效果如下 :

效果如上 ,通过 Select 可以选择窗口里面的组件 ,就可以查找到对应的代码位置以及相关信息 ,便于调试。
同时会展示出组件的各种信息 ,属性树 ,便于问题的分析。
使用方式 :
我是 VSCode 里面添加 Task :
js
{
"label": "Run with PyQtInspect",
"type": "shell",
"command": "python",
"args": [
"-m",
"PyQtInspect",
"--direct",
"--qt-support=PyQt6",
"--file",
"${workspaceFolder}/main.py"
],
"group": {
"kind": "build",
"isDefault": false
},
"problemMatcher": []
}
- python -m PyQtInspect --direct --qt-support=PyQt6 --file D:\code\python\ant-tools/main.py
三. 原理浅学一下
主要流程 :
- 阶段1: 系统启动 ,核心类 :
ArgHandlerWithParam
,PQIWindow
,PQYWorker
- 功能: 解析启动参数,创建服务器主窗口,开始监听指定端口等待客户端连接。支持服务器模式和直连模式。
- 阶段2: 网络连接 ,核心类 :
PyDB
,Dispatcher
,ReaderThread
,WriterThread
- 功能: 客户端连接服务器,建立双向通信通道。每个连接创建独立的调度器和读写线程,实现并发处理。
- 阶段3: Qt补丁注入,核心类 :
ThreadWrapper
,QProcessWrapper
,HighlightController
- 功能: 动态检测Qt版本,对QThread、QProcess等核心类进行运行时包装,注入调试跟踪功能和事件监听器。
- 阶段4: 事件监听,核心类 :
EventListener
,EnteredWidgetStack
,QWidgetInfo
- 功能: 实时监听鼠标进入控件事件,维护控件栈,提供红色半透明高亮效果,收集并发送控件详细信息。
- 阶段5: GUI交互,核心类 :
HierarchyBar
,WidgetPropertiesGetter
,CodeWindow
- 功能: 更新层级导航栏,展示控件属性树,支持远程Python代码执行,提供完整的可视化调试界面。
3.1 注入与Monkey Patching机制
👉 在 pqi_monkey.py
中 ,会通过猴子补丁拦截所有进程创建相关的系统调用,比如 :
os.execl
,os.execv
,os.execve
系列函数os.spawnl
,os.spawnv
,os.spawnve
系列函数subprocess.Popen
和相关函数- Windows 平台的
CreateProcess
👉 同时pqi_monkey_qt_helpers.py
还会对函数进行拦截 ,对 Qt 控件的构造函数进行补丁,实现控件创建时的自动注册
- _new_QWidget_init : 其中会调用原始构造函数,初始化全局事件过滤器
3.2 事件拦截技术
- 全局事件过滤器 (
pqi_monkey_qt_helpers.py:188-351
)- EventEnum.Enter / EventEnum.Leave /EventEnum.MouseButtonPress
- 原生事件过滤器 : 针对不同平台的原生事件处理
- self.WM_NCHITTEST /
3.3 动态代码执行
在目标进程中动态执行 Python 代码,用于实时调试和控件操作 , 核心代码在 pqi_monkey_qt_helpers.py:564-575
。
通过这部分逻辑 ,可以访问以下资源 :
- 全局命名空间: Python 内置函数和模块
- 局部命名空间 : 当前控件实例 (
self
) - Qt 模块: PyQt/PySide 的所有功能
- 调试器 API: PyQtInspect 提供的调试接口
四. 待扩展的点
- 由于我是通过 VSCode 编写的 Python , 这里本来可以通过双击定位到代码行的 ,VSCode 则不行。
- 整体界面的效果还有很大的优化空间
后续时间空出来了 ,就会主要针对这两点在大佬的基础上进行一定的改造。
总计
这一块没什么知识积累 ,看起来很吃力 ,为了后面去二次改造这个,还是磨了一下源码 ,也不知道对不对。
我个人现在只找到这一种方式 ,也不知道有没有更好的工具 ,欢迎大佬推荐。
最后的最后 ❤️❤️❤️👇👇👇
- 👈 欢迎关注 ,超200篇优质文章,未来持续高质量输出 🎉🎉
- 🔥🔥🔥 系列文章集合,高并发,源码应有尽有 👍👍
附录
类名 | 作用 |
---|---|
FuncWrapper | 函数包装器,为信号连接注入跟踪功能 |
StartedSignalWrapper | QThread.started信号包装器,注入跟踪逻辑 |
ThreadWrapper | QThread包装器,注入调试跟踪和信号监听 |
RunnableWrapper | QRunnable包装器,为线程池任务注入跟踪 |
QProcessWrapper | QProcess包装器,拦截进程启动并修改参数 |
HighlightController | 控件高亮显示管理器,实现红色半透明覆盖 |
EnteredWidgetStack | 鼠标进入控件的堆栈跟踪管理器 |
EventListener | Qt事件监听器,处理鼠标和键盘事件 |
服务器端核心 | |
PQIWindow | 服务器主窗口,GUI管理和线程交互中心 |
DirectModePQIWindow | 直连模式窗口,自动监听指定端口 |
PQYWorker | 服务器工作线程,监听连接并创建调度器 |
DummyWorker | 占位符类,空对象模式避免空指针检查 |
Dispatcher | 单客户端通信处理器,管理完整通信生命周期 |
DispatchReader | 调度器专用读取线程,处理URL解码和转发 |
客户端核心 | |
PyDB | 客户端核心调试器,管理远程调试会话 |
TrackedLock | 线程感知锁,跟踪线程锁状态防止死锁 |
通信层 | |
CommunicationRole | 通信角色常量类,定义客户端服务器角色 |
PyDBDaemonThread | 守护线程基类,管理所有后台线程 |
ReaderThread | 通信读取线程基类,处理Socket数据接收 |
WriterThread | 通信写入线程,处理消息队列和发送 |
NetCommandFactory | 网络命令工厂,创建各种协议消息 |
数据结构 | |
QWidgetInfo | 控件信息数据类,存储完整Qt控件信息 |
QWidgetChildrenInfo | 控件子元素信息数据类,存储层级关系 |
WidgetPropertiesGetter | 控件属性获取器,支持50+种Qt控件类型 |
配置和工具 | |
SetupHolder | 全局配置持有器,定义所有配置键常量 |
DataCenter | 数据中心类,管理GUI数据状态和缓存 |
DataHolder | 数据持有器,存储GUI运行时数据 |
KeyboardHookHandler | 键盘钩子处理器,处理全局快捷键事件 |
KeyboardHookWin | Windows键盘钩子实现,底层键盘事件捕获 |
StackFrameInfo | 堆栈帧信息类,存储单个堆栈帧数据 |
一些比较重要的代码
服务器端监听
python
class PQYWorker(QtCore.QObject):
def run(self):
self._socket = socket(AF_INET, SOCK_STREAM)
self._socket.bind(('', self.port))
self._socket.listen(1)
while self._isServing:
newSock, _addr = self._socket.accept()
dispatcher = Dispatcher(None, newSock, dispatcherId)
dispatcher.start()
客户端连接
python
class PyDB:
def connect_to_server(self):
self.writer = WriterThread(sock)
self.reader = ReaderThread(sock)
# 建立双向通信通道
通信通道建立
- 核心类 :
Dispatcher
,DispatchReader
,WriterThread
,ReaderThread
- 消息工厂 :
NetCommandFactory