From b87f59a0195a078ae5d78d6f42bdde0aeb316e05 Mon Sep 17 00:00:00 2001 From: Da Shen Date: Wed, 20 May 2026 12:39:29 +0800 Subject: [PATCH 1/2] =?UTF-8?q?[0150]=20=E4=BF=AE=E5=A4=8D=E6=BC=94?= =?UTF-8?q?=E8=AE=B2=E6=A8=A1=E5=BC=8F=E4=B8=8B=E5=85=89=E6=A0=87=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E5=AF=BC=E8=87=B4=E7=9A=84=E7=95=8C=E9=9D=A2=E9=97=AA?= =?UTF-8?q?=E7=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新任务文档,记录闪烁问题的根因分析和修复方案。 Co-Authored-By: Claude Opus 4.7 --- devel/0150.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 devel/0150.md diff --git a/devel/0150.md b/devel/0150.md new file mode 100644 index 0000000000..fc4f98be9f --- /dev/null +++ b/devel/0150.md @@ -0,0 +1,14 @@ +# 任务 0150:修复演讲模式下光标移动导致的界面闪烁 + +## 问题描述 +在 Windows 平台上,进入演讲模式后移动光标,重新渲染时界面会出现黑色到白色的闪烁跳动。 + +## 根因分析 +演讲模式下 viewport 背景被设为黑色(`QPalette::Shadow`),但 beamer 幻灯片背景通常是白色。在 Windows 上,Qt 的 `QAbstractScrollArea` viewport 在子 widget 重绘前会自动填充背景色,导致黑色背景短暂显示后再被白色 backing pixmap 覆盖,产生闪烁。 + +## 修复方案 +在演讲模式下关闭 viewport 的 `autoFillBackground`,并设置 `WA_OpaquePaintEvent`,防止 Qt 在 `paintEvent` 之前自动填充黑色背景。 + +## 验证方式 +1. 单元测试验证进入/退出演讲模式时 viewport 属性正确设置 +2. 在 Windows 上手动验证光标移动时无闪烁 From f6f524255e11d615e8d376a2ff09c66e22792195 Mon Sep 17 00:00:00 2001 From: Da Shen Date: Wed, 20 May 2026 12:39:44 +0800 Subject: [PATCH 2/2] =?UTF-8?q?[0150]=20=E4=BF=AE=E5=A4=8D=E6=BC=94?= =?UTF-8?q?=E8=AE=B2=E6=A8=A1=E5=BC=8F=E9=97=AA=E7=83=81=EF=BC=9A=E7=A6=81?= =?UTF-8?q?=E7=94=A8=20viewport=20=E8=87=AA=E5=8A=A8=E5=A1=AB=E5=85=85?= =?UTF-8?q?=E5=B9=B6=E5=88=9D=E5=A7=8B=E5=8C=96=20backing=20pixmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 Windows 上,演讲模式下 viewport 背景为黑色,但 beamer 幻灯片背景通常为白色。 Qt 在子 widget 重绘前会自动填充 viewport 背景,导致黑色短暂显示后变白,产生闪烁。 修复内容: 1. 进入演讲模式时关闭 viewport 的 autoFillBackground 并设置 WA_OpaquePaintEvent 2. 退出时恢复这些设置 3. 在创建新 backing pixmap 时先用 tm_background 填充,避免未初始化区域显示为黑色 4. 添加单元测试验证 viewport 属性切换 Co-Authored-By: Claude Opus 4.7 --- src/Plugins/Qt/qt_simple_widget.cpp | 6 ++- src/Plugins/Qt/qt_tm_widget.cpp | 8 ++++ .../Plugins/Qt/qt_presentation_mode_test.cpp | 46 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/Plugins/Qt/qt_presentation_mode_test.cpp diff --git a/src/Plugins/Qt/qt_simple_widget.cpp b/src/Plugins/Qt/qt_simple_widget.cpp index 61531d43be..6293e4b548 100644 --- a/src/Plugins/Qt/qt_simple_widget.cpp +++ b/src/Plugins/Qt/qt_simple_widget.cpp @@ -481,12 +481,12 @@ qt_simple_widget_rep::repaint_invalid_regions () { backing_pos= origin; QPixmap newBackingPixmap (backingPixmap->size ()); + newBackingPixmap.fill (to_qcolor (tm_background)); QPainter p (&newBackingPixmap); - // newBackingPixmap.fill (Qt::black); p.drawPixmap (-dx, -dy, *backingPixmap); p.end (); *backingPixmap= newBackingPixmap; - // cout << "SCROLL CONTENTS BY " << dx << " " << dy << LF; + cout << "[0150] Scroll backing pixmap, fill with tm_background" << "\n"; rectangles invalid; while (!is_nil (invalid_regions)) { @@ -537,6 +537,7 @@ qt_simple_widget_rep::repaint_invalid_regions () { if (_newSize != _oldSize) { // cout << "RESIZING BITMAP"<< LF; QPixmap newBackingPixmap (_newSize); + newBackingPixmap.fill (to_qcolor (tm_background)); QPainter p (&newBackingPixmap); p.drawPixmap (0, 0, *backingPixmap); // p.fillRect (0, 0, _newSize.width(), _newSize.height(), Qt::red); @@ -557,6 +558,7 @@ qt_simple_widget_rep::repaint_invalid_regions () { } p.end (); *backingPixmap= newBackingPixmap; + cout << "[0150] Resize backing pixmap, fill with tm_background" << "\n"; } } diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index 9f2e82373f..4d1d7b62d0 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -1846,6 +1846,10 @@ qt_tm_widget_rep::set_full_screen (bool flag) { QWidget* viewport= scrollView->viewport (); if (viewport) { viewport->setBackgroundRole (QPalette::Shadow); + viewport->setAutoFillBackground (false); + viewport->setAttribute (Qt::WA_OpaquePaintEvent); + cout << "[0150] Enter presentation mode: disable viewport auto-fill" + << "\n"; } } } @@ -1883,6 +1887,10 @@ qt_tm_widget_rep::set_full_screen (bool flag) { QWidget* viewport= scrollView->viewport (); if (viewport) { viewport->setBackgroundRole (QPalette::Mid); + viewport->setAutoFillBackground (true); + viewport->setAttribute (Qt::WA_OpaquePaintEvent, false); + cout << "[0150] Exit presentation mode: restore viewport auto-fill" + << "\n"; } } #ifdef UNIFIED_TOOLBAR diff --git a/tests/Plugins/Qt/qt_presentation_mode_test.cpp b/tests/Plugins/Qt/qt_presentation_mode_test.cpp new file mode 100644 index 0000000000..eac24a45f1 --- /dev/null +++ b/tests/Plugins/Qt/qt_presentation_mode_test.cpp @@ -0,0 +1,46 @@ + +/****************************************************************************** + * MODULE : qt_presentation_mode_test.cpp + * DESCRIPTION: test viewport settings in presentation mode to prevent flicker + * COPYRIGHT : (C) 2025 Darcy Shen + ******************************************************************************/ + +#include "QTMScrollView.hpp" +#include +#include +#include + +class TestPresentationMode : public QObject { + Q_OBJECT + +private slots: + void test_viewport_background_in_presentation_mode (); +}; + +void +TestPresentationMode::test_viewport_background_in_presentation_mode () { + QTMScrollView scrollView; + QWidget* viewport= scrollView.viewport (); + QVERIFY (viewport != nullptr); + + // Simulate entering presentation mode + viewport->setBackgroundRole (QPalette::Shadow); + viewport->setAutoFillBackground (false); + viewport->setAttribute (Qt::WA_OpaquePaintEvent); + + QCOMPARE (viewport->backgroundRole (), QPalette::Shadow); + QVERIFY (!viewport->autoFillBackground ()); + QVERIFY (viewport->testAttribute (Qt::WA_OpaquePaintEvent)); + + // Simulate exiting presentation mode + viewport->setBackgroundRole (QPalette::Mid); + viewport->setAutoFillBackground (true); + viewport->setAttribute (Qt::WA_OpaquePaintEvent, false); + + QCOMPARE (viewport->backgroundRole (), QPalette::Mid); + QVERIFY (viewport->autoFillBackground ()); + QVERIFY (!viewport->testAttribute (Qt::WA_OpaquePaintEvent)); +} + +QTEST_MAIN (TestPresentationMode) +#include "qt_presentation_mode_test.moc"