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 上手动验证光标移动时无闪烁 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"