fix: v0.4.1 修复主题切换丢 swatch 底色与连接失败长错误串撑爆布局;新增 selftest_theme;重打包
This commit is contained in:
@@ -52,7 +52,8 @@ from PySide6.QtWidgets import (
|
||||
)
|
||||
from qfluentwidgets import (
|
||||
BodyLabel, CardWidget, ComboBox, LineEdit, PlainTextEdit,
|
||||
PrimaryPushButton, PushButton, Slider, StrongBodyLabel, Theme, setTheme,
|
||||
PrimaryPushButton, PushButton, Slider, StrongBodyLabel, Theme,
|
||||
setCustomStyleSheet, setTheme,
|
||||
)
|
||||
|
||||
import config
|
||||
@@ -62,7 +63,7 @@ import edid_parse
|
||||
import patterns
|
||||
|
||||
APP_NAME = "DLPilot"
|
||||
APP_VERSION = "0.4.0"
|
||||
APP_VERSION = "0.4.1"
|
||||
REPO_URL = "https://gitea.hulk.wang/hulk/HW-Debug-Tools"
|
||||
MONO = QFont("Consolas", 10)
|
||||
CHIP_IDLE = "#666666"
|
||||
@@ -266,7 +267,12 @@ class App(QMainWindow):
|
||||
outer.setSpacing(12)
|
||||
header = QHBoxLayout()
|
||||
title = StrongBodyLabel("DLPilot", root)
|
||||
title.setStyleSheet("font-size: 24px; font-weight: 700;")
|
||||
# 标题字号走 QFont:FluentLabelBase 在每次主题切换时会用自带的颜色规则
|
||||
# 重写自定义 qss 槽,setStyleSheet/setCustomStyleSheet 写的字号都会被冲掉
|
||||
title_font = title.font()
|
||||
title_font.setPixelSize(24)
|
||||
title_font.setBold(True)
|
||||
title.setFont(title_font)
|
||||
header.addWidget(title)
|
||||
header.addWidget(BodyLabel("EDID · 测试图案 · RS485 光机控制", root))
|
||||
header.addStretch(1)
|
||||
@@ -355,7 +361,13 @@ class App(QMainWindow):
|
||||
row.addWidget(BodyLabel(f"{channel}: 0x", card))
|
||||
for label, color in items:
|
||||
button = PushButton(label, card)
|
||||
button.setStyleSheet(f"PushButton {{ background: {color}; color: {'black' if color == '#00FF00' else 'white'}; }}")
|
||||
# fluent 控件的样式须走 setCustomStyleSheet:直接 setStyleSheet 的内容
|
||||
# 会在 setTheme 时被库重刷的自带 qss 冲掉;且须覆盖 hover/pressed 态,
|
||||
# 否则悬停瞬间底色仍会被自带态样式盖回
|
||||
fg = 'black' if color == '#00FF00' else 'white'
|
||||
qss = ("PushButton, PushButton:hover, PushButton:pressed, "
|
||||
f"PushButton:disabled {{ background-color: {color}; color: {fg}; border: none; }}")
|
||||
setCustomStyleSheet(button, qss, qss)
|
||||
button.clicked.connect(lambda checked=False, c=color: self._show_solid(c))
|
||||
row.addWidget(button)
|
||||
row.addStretch(1)
|
||||
@@ -414,6 +426,9 @@ class App(QMainWindow):
|
||||
setattr(self, attr, combo)
|
||||
params.addWidget(combo)
|
||||
self.lbl_dlpc_st = BodyLabel("未连接", card)
|
||||
# 状态标签允许换行兜底: 任何长错误串都不得撑大参数行最小宽度(否则窗口拉长,
|
||||
# 刷新/连接按钮被挤出可视区)
|
||||
self.lbl_dlpc_st.setWordWrap(True)
|
||||
params.addWidget(self.lbl_dlpc_st)
|
||||
params.addStretch(1)
|
||||
body.addLayout(params)
|
||||
@@ -770,6 +785,7 @@ class App(QMainWindow):
|
||||
def _dlpc_toggle(self):
|
||||
if self.dlpc.is_connected(): self.dlpc.close(); self._serial_reset_state(); return
|
||||
port = self._dlpc_selected_port()
|
||||
if not port: self.lbl_dlpc_st.setText('未选择串口,请先选择或刷新'); return
|
||||
try: baud, bytesize, stopbits = int(self.cbo_baud.currentText()), int(self.cbo_databits.currentText()), int(self.cbo_stopbits.currentText())
|
||||
except ValueError: self.lbl_dlpc_st.setText("串口参数非法"); return
|
||||
parity = self.cbo_parity.currentText()[:1] or 'N'; config.SERIAL_CFG.update(port=port, baud=baud, bytesize=bytesize, parity=parity, stopbits=stopbits); config.save_slots(self.slots, self.cbo_area.currentText()); self.dlpc.open(port, baud, bytesize=bytesize, parity=parity, stopbits=stopbits)
|
||||
|
||||
@@ -326,11 +326,19 @@ class DLPC485:
|
||||
self.ser = None
|
||||
with self._lock:
|
||||
self._target = None
|
||||
et = str(e)
|
||||
if 'PermissionError' in repr(e) or '拒绝访问' in et \
|
||||
or 'Access is denied' in et:
|
||||
et += '(串口被占用: 检查串口助手/另一个本工具实例)'
|
||||
self.on_status(f'连接失败: {et}')
|
||||
blob = str(e) + repr(e)
|
||||
if 'PermissionError' in blob or '拒绝访问' in blob \
|
||||
or 'Access is denied' in blob:
|
||||
hint = '串口被占用(串口助手/另一实例?)'
|
||||
elif 'FileNotFoundError' in blob or '找不到指定的' in blob \
|
||||
or 'No such file' in blob:
|
||||
hint = '串口不存在,请刷新后重选'
|
||||
else:
|
||||
hint = '无法打开,详情见日志'
|
||||
# 状态标签只放短提示(长异常串会撑爆参数行把窗口拉长),
|
||||
# 完整异常走 on_event 进收发日志
|
||||
self.on_status(f'连接失败: {hint}')
|
||||
self.on_event(f'连接失败: {e!r}')
|
||||
if self.ser is not None:
|
||||
try:
|
||||
item = None
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# coding: utf-8
|
||||
"""主题切换回归自检(无窗口, 离屏渲染)。
|
||||
|
||||
背景: fluent 控件直接 setStyleSheet 的样式会在 setTheme 时被库重刷的自带 qss 冲掉
|
||||
(v0.4.0 RGB swatch 按钮切主题丢底色的根因)。swatch 改走 setCustomStyleSheet、
|
||||
标题字号走 QFont 后,本测试保证:
|
||||
1. Dark -> Light -> Dark -> Light 往返后 9 个 swatch 按钮样式表仍带底色;
|
||||
2. Light 下实际渲染出的按钮中心像素 = swatch 色值(不只样式表字符串存在);
|
||||
3. 标题 24px 加粗(QFont)在往返后不变。
|
||||
|
||||
运行: python selftest_theme.py (依赖 PySide6-Fluent-Widgets)
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QApplication
|
||||
from qfluentwidgets import PushButton, StrongBodyLabel, Theme, setTheme
|
||||
|
||||
import app_fluent
|
||||
import patterns
|
||||
|
||||
|
||||
def check_style_sheet(win, app):
|
||||
swatches = [b for b in win.findChildren(PushButton) if b.text() in {"55", "AA", "FF"}]
|
||||
assert len(swatches) == 9, f"expect 9 swatch buttons, got {len(swatches)}"
|
||||
title = [l for l in win.findChildren(StrongBodyLabel) if l.text() == "DLPilot"]
|
||||
assert len(title) == 1, "title label not found"
|
||||
colored = sum(1 for b in swatches if "background-color: #" in b.styleSheet())
|
||||
f = title[0].font()
|
||||
print(f" swatch 样式表带底色: {colored}/9, 标题 24px 粗体: "
|
||||
f"{f.pixelSize() == 24 and f.bold()}")
|
||||
return colored == 9 and f.pixelSize() == 24 and f.bold()
|
||||
|
||||
|
||||
def check_rendered_pixel(win, app):
|
||||
"""Light 主题下逐个渲染 swatch,与目标色一致的像素须占明显多数(背景为主,
|
||||
中心处是文字字形,不能只采单点)。"""
|
||||
ok = True
|
||||
for channel, items in patterns.SOLID_ROWS:
|
||||
for label, color in items:
|
||||
button = next(b for b in win.findChildren(PushButton)
|
||||
if b.text() == label and f"background-color: {color}" in b.styleSheet())
|
||||
image = button.grab().toImage()
|
||||
target = QColor(color)
|
||||
total, matched = image.width() * image.height(), 0
|
||||
for y in range(image.height()):
|
||||
for x in range(image.width()):
|
||||
if image.pixelColor(x, y) == target:
|
||||
matched += 1
|
||||
ratio = matched / total
|
||||
same = ratio >= 0.2
|
||||
ok &= same
|
||||
if not same:
|
||||
print(f" 渲染不符: {channel}/{label} 期望 {color} 仅占 {ratio:.0%}")
|
||||
print(f" Light 下渲染像素比对: {'一致' if ok else '存在偏差'}")
|
||||
return ok
|
||||
|
||||
|
||||
def main():
|
||||
app = QApplication.instance() or QApplication(sys.argv)
|
||||
setTheme(Theme.AUTO)
|
||||
win = app_fluent.App(0)
|
||||
passed = True
|
||||
for step, theme in (("初始 Dark", Theme.DARK), ("切 Light", Theme.LIGHT),
|
||||
("切回 Dark", Theme.DARK), ("再切 Light", Theme.LIGHT)):
|
||||
setTheme(theme)
|
||||
app.processEvents()
|
||||
print(f"[{step}]")
|
||||
passed &= check_style_sheet(win, app)
|
||||
if theme == Theme.LIGHT:
|
||||
passed &= check_rendered_pixel(win, app)
|
||||
win.close()
|
||||
print("ALL PASS" if passed else "FAILED")
|
||||
return 0 if passed else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user