PySide6/Qt 桌面 GUI 坑速查
> 由真实桌面应用(PySide6)开发踩坑沉淀整理,按【坑/现象 → 根因 → 解法 → 通用教训】组织。
坑 1:悬浮控件「跟窗居中」总偏离正中十几像素
【症状】把某个按钮改成悬浮在整个界面正中间,窗口拉伸后按钮总是偏下十几像素。窗口 2560×1324、centralWidget() 实际 2560×1297:按 central 算期望 y=619,实测 y=633(正好按窗口全高算出来的值)。
【根因】布局生效是两步:
1. QMainWindow.resizeEvent 触发时,centralWidget() 还带着旧高度;
2. 布局随后把 central 压到新高度,但 central 自己的尺寸变化不会再触发窗口的 resizeEvent。
于是最后一次摆位用的是过期尺寸。
【解法】给 central 装事件过滤器,直接监听它自己的 Resize:
parent.installEventFilter(self) # parent = centralWidget()
...
def eventFilter(self, obj, event):
if obj is self._floating_host and event.type() == QEvent.Resize:
self._reposition_floating()
return super().eventFilter(obj, event)
改后摆位与期望逐像素一致。
【通用教训】任何「跟着窗口尺寸走的悬浮控件」,监听目标必须是它真正锚定的那个 widget,而不是外层窗口。父窗口 resizeEvent ≠ 子控件 resize。
坑 2:QT_QPA_PLATFORM=offscreen 下 show() 直接段错误(exit 139)
【症状】想无头验证 GUI,设了 offscreen 平台:MainWindow() 构造正常,一调 w.show() 就 Fatal Python error: Segmentation fault。
【根因】窗口里有原生组件嵌入(如用 PyObjC 把 WKWebView 塞进 Qt 窗口)。offscreen QPA 没有真实 NSWindow,attach 原生视图时直接崩。这与最近改的布局代码无关——是既有原生嵌入代码在无头环境跑不了。
【判定方法】faulthandler.enable() + 栈里出现 WebKit/原生扩展模块 = 原生组件问题,不是 Qt 布局/业务代码问题。构造能过、show() 才崩,基本锁定 showEvent 里的原生嵌入。
【解法 / 正确验证姿势】
- ❌ 不要用 offscreen 验证含原生 WebView 的 GUI;
- ✅ 用真实 cocoa 平台启动,QTimer.singleShot(3500, 截图) + screencapture -x /tmp/shot.png 拿到肉眼可核的证据,再 app.quit() 收工;
- ✅ 纯 Qt 逻辑(居中/拖拽/边界夹取)可以拆成不 show 窗口的离屏单测:手动 central.resize(w, h) + 调摆位函数后比坐标即可;
- ✅ 控件级截图用 w.grab(),比 screencapture 更适合自动化断言。
坑 3:按钮拖拽结束时误触发 clicked
【症状】QPushButton 子类里按住左键拖动换位,松手时「想挪位置却触发了下载」。
【根因】拖动结束后 mouseReleaseEvent 继续走默认流程,Qt 会把它当一次普通点击发出 clicked。
【解法】拖过就吞掉这次释放:
def mouseReleaseEvent(self, e):
dragged, self._dragged, self._drag_offset = self._dragged, False, None
if dragged:
e.accept(); return # 拖过就不触发 clicked
super().mouseReleaseEvent(e)
配套要点:self.mapToParent(e.pos()) - drag_offset 算目标位置,并对父控件宽高做 min/max 夹取防止拖出界面;双击调居中函数复位。
坑 4:圆形/圆角控件加 QGraphicsDropShadowEffect 出现一圈方形阴影
【症状】圆形按钮外圈出现方形阴影。
【根因】QGraphicsDropShadowEffect 的实现是把控件渲染成一张矩形位图再做高斯模糊,位图四角是满的 → 非矩形控件外面就是方形阴影。旁证:给带该 effect 的按钮 grab(),圆心像素是父控件背景色——effect 改变了控件自身渲染路径。
【解法】圆形按钮不要用图形效果,纯 QSS 圆形 + 描边即可(border-radius 已保证四角透明),另加 setAutoFillBackground(False)。
【通用教训】给非矩形控件加图形效果前,先确认该效果的中间产物是不是矩形位图;Qt 的 QGraphicsDropShadowEffect / QGraphicsBlurEffect 都是。
> 作者:阿光 · 婚恋活动策划 × 摄影摄像 8 年实战。技能定制 / 业务合作:微信 13011137113