调试初版

This commit is contained in:
xu
2026-10-14 18:22:41 +08:00
parent d3a355bd3f
commit e5efdea06e
26 changed files with 289 additions and 140 deletions
+55 -17
View File
@@ -5,6 +5,7 @@
#include <QPushButton>
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QGraphicsDropShadowEffect>
// 启动 500ms 闪烁:每 500ms 切换一次动态属性,QSS 据此在 40%↔100% 透明度间切换
@@ -49,29 +50,67 @@ QString cancelButtonStyle(int fontPx)
.arg(fontPx).arg(C::DANGER);
}
// ===================== 按钮焦点光圈 =====================
// ===================== 按钮焦点(选中)光圈 =====================
ButtonFocusGlow::ButtonFocusGlow(const QColor& glow, QObject* parent)
: QObject(parent), m_glow(glow)
{
}
// 触摸屏上手指抬起后指针并不会跟着移开,Qt 会把刚点过的按钮一直留在悬停(:hover)态。
// 本项目的悬停样式与选中样式是同一套(蓝底/亮边),残留的悬停看起来就是"还选中着",
// 此时再按 Tab 选中另一个按钮,屏幕上就出现了两个"选中"。选中态一律以焦点为准,
// 故每次产生新的选中(点击/触摸按下、焦点移入)时,把其它按钮残留的悬停态清掉。
static void clearStaleHover(QWidget* keep)
{
// 用 allWidgets 而非 qApp->findChildren:顶层窗口并非 QApplication 的子对象
const QWidgetList all = QApplication::allWidgets();
for (QWidget* w : all) {
if (w == keep || !w->underMouse() || !qobject_cast<QAbstractButton*>(w))
continue;
w->setAttribute(Qt::WA_UnderMouse, false);
w->update();
}
}
bool ButtonFocusGlow::eventFilter(QObject* obj, QEvent* ev)
{
if (ev->type() == QEvent::FocusIn || ev->type() == QEvent::FocusOut) {
QWidget* w = qobject_cast<QWidget*>(obj);
if (w && qobject_cast<QPushButton*>(w)) {
if (ev->type() == QEvent::FocusIn) {
if (!w->graphicsEffect()) { // 挂一圈发光(偏移 0 → 四周光晕)
QGraphicsDropShadowEffect* g = new QGraphicsDropShadowEffect(w);
g->setBlurRadius(40); // 光晕大小(越大越强)
g->setOffset(0, 0);
g->setColor(m_glow);
w->setGraphicsEffect(g);
}
} else {
w->setGraphicsEffect(nullptr); // Qt 会删除旧效果
}
QWidget* w = qobject_cast<QWidget*>(obj);
if (!w)
return QObject::eventFilter(obj, ev);
switch (ev->type()) {
case QEvent::FocusIn:
clearStaleHover(w); // 新的选中出现 → 旧按钮的悬停残影一并清掉
if (qobject_cast<QPushButton*>(w) && !w->graphicsEffect()) {
QGraphicsDropShadowEffect* g = new QGraphicsDropShadowEffect(w); // 挂一圈发光(偏移 0 → 四周光晕)
g->setBlurRadius(40); // 光晕大小(越大越强)
g->setOffset(0, 0);
g->setColor(m_glow);
w->setGraphicsEffect(g);
}
break;
case QEvent::FocusOut:
if (qobject_cast<QPushButton*>(w) && w->graphicsEffect()) {
// 光晕带模糊、偏移为 0,会溢出按钮矩形画到父控件上。
// 只重绘按钮自身清不掉溢出的那圈,Tab 移走焦点后仍会留下蓝色残影,
// 所以把父控件整块标脏,连同按钮一起重绘。
QWidget* parent = w->parentWidget();
w->setGraphicsEffect(nullptr); // Qt 会删除旧效果
w->update();
if (parent)
parent->update(parent->rect());
}
break;
case QEvent::MouseButtonPress:
// 触摸/点击与 Tab 归一到同一个焦点:谁最后操作,谁就是唯一的选中
if (static_cast<QMouseEvent*>(ev)->button() == Qt::LeftButton
&& (w->focusPolicy() & Qt::ClickFocus)) {
w->setFocus(Qt::MouseFocusReason);
clearStaleHover(w);
}
break;
default:
break;
}
return QObject::eventFilter(obj, ev);
}
@@ -95,8 +134,7 @@ bool ArrowKeyGuard::eventFilter(QObject* obj, QEvent* ev)
QWidget* fw = QApplication::focusWidget();
if (fw && qobject_cast<QAbstractButton*>(fw)) {
const int k = static_cast<QKeyEvent*>(ev)->key();
if (k == Qt::Key_Up || k == Qt::Key_Down
|| k == Qt::Key_Left || k == Qt::Key_Right)
if (Keys::up(k) || Keys::down(k))
return true;
}
}