From 2c7119d190db30d3050ac054929507a8a870243a Mon Sep 17 00:00:00 2001 From: ubuntu1804 Date: Tue, 11 Nov 2025 10:27:06 +0800 Subject: [PATCH] Introduce RenderWidgetBase and unify renderers Add RenderWidgetBase and update CustomWidget and VulkanWidget to implement its interface. Refactor MainWindow to use a single RenderWidgetBase pointer, unify controls and status UI, and remove the dual-tab setup. Add design and quickstart docs and register the new header in CMakeLists.txt. --- CMakeLists.txt | 1 + docs/UNIFIED_RENDERING_QUICKSTART.md | 334 +++++++++++++++++++++++ docs/unified_rendering_design.md | 379 +++++++++++++++++++++++++++ src/customwidget.cpp | 41 ++- src/customwidget.h | 40 ++- src/mainwindow.cpp | 358 +++++++++---------------- src/mainwindow.h | 66 ++--- src/renderwidgetbase.h | 73 ++++++ src/vulkanwidget.cpp | 129 +++++---- src/vulkanwidget.h | 56 +--- 10 files changed, 1061 insertions(+), 416 deletions(-) create mode 100644 docs/UNIFIED_RENDERING_QUICKSTART.md create mode 100644 docs/unified_rendering_design.md create mode 100644 src/renderwidgetbase.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 64f5209..39476a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,7 @@ set(SOURCES set(HEADERS src/mainwindow.h + src/renderwidgetbase.h src/customwidget.h ) diff --git a/docs/UNIFIED_RENDERING_QUICKSTART.md b/docs/UNIFIED_RENDERING_QUICKSTART.md new file mode 100644 index 0000000..a2082bd --- /dev/null +++ b/docs/UNIFIED_RENDERING_QUICKSTART.md @@ -0,0 +1,334 @@ +# 统一渲染架构快速入门 + +## 概述 + +本项目采用统一的渲染架构设计,通过抽象基类 `RenderWidgetBase` 实现对 Vulkan 和 QPainter 两种渲染方式的统一管理。 + +## 核心设计 + +### 三层架构 + +``` +┌─────────────────────────────────────┐ +│ MainWindow │ ← 使用统一接口 +│ (RenderWidgetBase* m_renderWidget) │ +└──────────────┬──────────────────────┘ + │ + ↓ +┌─────────────────────────────────────┐ +│ RenderWidgetBase (基类) │ ← 定义统一接口 +│ - initializeRenderer() │ +│ - setRenderingEnabled() │ +│ - getRenderFrameCount() │ +│ - getRendererType() │ +└──────────────┬──────────────────────┘ + │ + ┌───────┴────────┐ + ↓ ↓ +┌─────────────┐ ┌─────────────┐ +│VulkanWidget │ │CustomWidget │ ← 具体实现 +│ (Vulkan) │ │ (QPainter) │ +└─────────────┘ └─────────────┘ +``` + +## 编译选项 + +### 使用 Vulkan(默认,如果可用) + +```bash +cd ScreenLockDetector +mkdir -p build && cd build +cmake .. -DENABLE_VULKAN=ON +make -j4 +``` + +**结果**:应用将使用 VulkanWidget 进行硬件加速渲染 + +### 使用 QPainter(后备方案) + +```bash +cd ScreenLockDetector +mkdir -p build && cd build +cmake .. -DENABLE_VULKAN=OFF +make -j4 +``` + +**结果**:应用将使用 CustomWidget 进行 CPU 绘制 + +### 自动回退 + +如果 Vulkan 头文件不可用,CMake 会自动回退到 QPainter: + +```bash +cmake .. +# 输出:Vulkan headers not found, disabling Vulkan support +``` + +## 主要改进 + +### 之前的设计问题 + +```cpp +// ❌ 旧设计:需要维护两个独立的组件 +private: + CustomWidget *m_customWidget; + #ifdef ENABLE_VULKAN_WIDGET + VulkanWidget *m_vulkanWidget; + #endif + + QTabWidget *m_tabWidget; // 使用 Tab 切换 +``` + +### 新的统一设计 + +```cpp +// ✅ 新设计:单一组件指针 +private: + RenderWidgetBase *m_renderWidget; // 统一接口 + + // 构造函数中根据编译选项创建 + #ifdef ENABLE_VULKAN_WIDGET + m_renderWidget = new VulkanWidget(this); + #else + m_renderWidget = new CustomWidget(this); + #endif +``` + +## 统一接口使用示例 + +### 1. 初始化渲染器 + +```cpp +// 对于 VulkanWidget:内部调用 initializeVulkan() +// 对于 CustomWidget:直接返回 true(无需初始化) +bool success = m_renderWidget->initializeRenderer(); +if (!success) { + qDebug() << "Error:" << m_renderWidget->getLastError(); +} +``` + +### 2. 控制渲染 + +```cpp +// 启用渲染(适用于任何渲染器) +m_renderWidget->setRenderingEnabled(true); + +// 禁用渲染(适用于任何渲染器) +m_renderWidget->setRenderingEnabled(false); + +// 查询状态 +bool isRendering = m_renderWidget->isRenderingEnabled(); +``` + +### 3. 获取状态信息 + +```cpp +// 获取渲染器类型 +QString type = m_renderWidget->getRendererType(); +// 返回 "Vulkan" 或 "QPainter" + +// 获取帧数统计 +int frames = m_renderWidget->getRenderFrameCount(); + +// 检查初始化状态 +bool initialized = m_renderWidget->isInitialized(); +``` + +### 4. 错误处理 + +```cpp +if (!m_renderWidget->isInitialized()) { + if (!m_renderWidget->initializeRenderer()) { + QMessageBox::warning( + this, + "初始化失败", + m_renderWidget->getLastError() + ); + } +} +``` + +## 锁屏检测集成 + +无论使用哪种渲染器,锁屏检测的处理逻辑完全一致: + +```cpp +void MainWindow::onLockStateChanged(bool locked) +{ + // 统一的处理逻辑 + if (m_renderWidget) { + m_renderWidget->setRenderingEnabled(!locked); + } + + updateStatusDisplay(); + updateButtonStates(); +} +``` + +## 添加新渲染器 + +假设要添加 OpenGL 支持: + +### 1. 创建新类 + +```cpp +// src/openglwidget.h +class OpenGLWidget : public RenderWidgetBase +{ + Q_OBJECT +public: + explicit OpenGLWidget(QWidget *parent = nullptr); + + // 实现所有虚函数 + bool initializeRenderer() override; + void setRenderingEnabled(bool enabled) override; + bool isRenderingEnabled() const override; + int getRenderFrameCount() const override; + void resetFrameCount() override; + bool isInitialized() const override; + QString getLastError() const override; + QString getRendererType() const override { return "OpenGL"; } +}; +``` + +### 2. 修改 CMakeLists.txt + +```cmake +option(ENABLE_OPENGL "Enable OpenGL support" OFF) + +if(ENABLE_OPENGL) + list(APPEND SOURCES src/openglwidget.cpp) + list(APPEND HEADERS src/openglwidget.h) + add_definitions(-DENABLE_OPENGL_WIDGET) +endif() +``` + +### 3. 修改 MainWindow 构造函数 + +```cpp +#ifdef ENABLE_VULKAN_WIDGET + m_renderWidget = new VulkanWidget(this); +#elif defined(ENABLE_OPENGL_WIDGET) + m_renderWidget = new OpenGLWidget(this); +#else + m_renderWidget = new CustomWidget(this); +#endif +``` + +## 运行效果 + +### Vulkan 模式 + +``` +┌──────────────────────────────────────┐ +│ Qt Screen Lock Detection Demo │ +├──────────────────────────────────────┤ +│ │ +│ [Vulkan 硬件加速渲染窗口] │ +│ (旋转的彩色圆圈动画) │ +│ │ +├──────────────────────────────────────┤ +│ [ Enable Rendering ] │ +│ [ Disable Rendering ] │ +│ [ Reset Frame Count ] │ +├──────────────────────────────────────┤ +│ Renderer Type: Vulkan │ +│ Detector Status: Active │ +│ Renderer Status: ✓ Initialized │ +│ Screen Lock Status: 🔓 UNLOCKED │ +│ Rendering Status: ✓ ENABLED │ +│ Frame Count: 1234 frames │ +└──────────────────────────────────────┘ +``` + +### QPainter 模式 + +``` +┌──────────────────────────────────────┐ +│ Qt Screen Lock Detection Demo │ +├──────────────────────────────────────┤ +│ │ +│ [QPainter 2D 渲染窗口] │ +│ (旋转的彩色圆圈动画) │ +│ │ +├──────────────────────────────────────┤ +│ [ Enable Rendering ] │ +│ [ Disable Rendering ] │ +│ [ Reset Frame Count ] │ +├──────────────────────────────────────┤ +│ Renderer Type: QPainter │ +│ Detector Status: Active │ +│ Renderer Status: ✓ Initialized │ +│ Screen Lock Status: 🔓 UNLOCKED │ +│ Rendering Status: ✓ ENABLED │ +│ Frame Count: 1234 frames │ +└──────────────────────────────────────┘ +``` + +## 优势总结 + +### ✅ 代码简化 +- MainWindow 代码减少约 40% +- 消除了大量重复的控制逻辑 +- 减少了条件编译代码 + +### ✅ 统一界面 +- 不再使用 Tab 切换 +- 单一、简洁的用户界面 +- 自动选择最佳渲染方式 + +### ✅ 易于维护 +- 添加新功能只需修改基类接口 +- 所有实现类自动继承新接口 +- 更容易追踪和修复 bug + +### ✅ 高可扩展性 +- 可以轻松添加新的渲染后端 +- 可以在运行时切换渲染器(未来功能) +- 支持插件化架构(未来功能) + +## 常见问题 + +### Q: 如何知道当前使用的是哪种渲染器? + +A: 查看应用程序窗口的 "Renderer Type" 标签,或在日志中查看: +``` +MainWindow initialized with Vulkan renderer +``` + +### Q: Vulkan 初始化失败怎么办? + +A: 应用会自动显示错误信息。可以重新编译使用 QPainter: +```bash +cmake .. -DENABLE_VULKAN=OFF +make -j4 +``` + +### Q: 两种渲染器性能差异大吗? + +A: +- **Vulkan**: 硬件加速,GPU 渲染,CPU 占用低,适合复杂场景 +- **QPainter**: CPU 渲染,CPU 占用较高,但兼容性最好 + +### Q: 可以在运行时切换渲染器吗? + +A: 当前版本不支持,但架构设计已经为此功能预留了空间。 + +## 相关文档 + +- [详细设计文档](./unified_rendering_design.md) - 完整的架构设计说明 +- [API 参考](../src/renderwidgetbase.h) - RenderWidgetBase 接口定义 +- [主 README](../README.md) - 项目总体说明 + +## 贡献指南 + +如果您想添加新的渲染后端: + +1. 创建新类继承 `RenderWidgetBase` +2. 实现所有虚函数 +3. 在 CMakeLists.txt 中添加编译选项 +4. 在 MainWindow 中添加创建逻辑 +5. 编写测试用例 +6. 更新文档 + +欢迎提交 Pull Request! \ No newline at end of file diff --git a/docs/unified_rendering_design.md b/docs/unified_rendering_design.md new file mode 100644 index 0000000..f7066fe --- /dev/null +++ b/docs/unified_rendering_design.md @@ -0,0 +1,379 @@ +# 统一渲染架构设计文档 + +## 概述 + +本文档描述了 ScreenLockDetector 项目中统一渲染架构的设计和实现。通过引入基类 `RenderWidgetBase`,我们实现了对 Vulkan 和 QPainter 两种渲染方式的统一抽象,使得 MainWindow 可以通过统一的接口操作不同的渲染实现。 + +## 设计目标 + +1. **统一接口**:为不同的渲染实现提供统一的操作接口 +2. **编译时选择**:通过 CMake 编译选项自动选择 Vulkan 或 QPainter 实现 +3. **简化 MainWindow**:MainWindow 无需关心具体的渲染实现细节 +4. **易于扩展**:未来可以方便地添加其他渲染后端(如 OpenGL、DirectX 等) + +## 架构设计 + +### 类层次结构 + +``` +QWidget + ↑ + | +RenderWidgetBase (抽象基类) + ↑ + | + +--- VulkanWidget (Vulkan 实现) + | + +--- CustomWidget (QPainter 实现) +``` + +### 核心组件 + +#### 1. RenderWidgetBase (基类) + +**文件位置**: `src/renderwidgetbase.h` + +**职责**: +- 定义统一的渲染组件接口 +- 继承自 QWidget +- 所有方法都是纯虚函数,由子类实现 + +**核心接口**: + +```cpp +// 初始化渲染器 +virtual bool initializeRenderer() = 0; + +// 启用/禁用渲染 +virtual void setRenderingEnabled(bool enabled) = 0; +virtual bool isRenderingEnabled() const = 0; + +// 帧计数管理 +virtual int getRenderFrameCount() const = 0; +virtual void resetFrameCount() = 0; + +// 状态查询 +virtual bool isInitialized() const = 0; +virtual QString getLastError() const = 0; +virtual QString getRendererType() const = 0; +``` + +#### 2. VulkanWidget (Vulkan 实现) + +**文件位置**: `src/vulkanwidget.h`, `src/vulkanwidget.cpp` + +**特点**: +- 使用 Vulkan API 进行硬件加速渲染 +- 通过 volk 动态加载 Vulkan 函数 +- 支持跨平台(Windows, Linux, macOS) +- 实现了 RenderWidgetBase 的所有接口 +- 保留了原有的 `initializeVulkan()` 等方法以保持向后兼容 + +**实现要点**: +- `initializeRenderer()` 内部调用 `initializeVulkan()` +- `getRendererType()` 返回 "Vulkan" +- 提供详细的错误信息通过 `getLastError()` + +#### 3. CustomWidget (QPainter 实现) + +**文件位置**: `src/customwidget.h`, `src/customwidget.cpp` + +**特点**: +- 使用 Qt 的 QPainter 进行 2D 绘制 +- 不需要额外的依赖库 +- 跨平台兼容性最佳 +- 实现了 RenderWidgetBase 的所有接口 +- 保留了原有的 `setPaintingEnabled()` 等方法以保持向后兼容 + +**实现要点**: +- `initializeRenderer()` 始终返回 true(QPainter 不需要初始化) +- `getRendererType()` 返回 "QPainter" +- `getLastError()` 返回空字符串(QPainter 通常不会出错) + +#### 4. MainWindow (主窗口) + +**文件位置**: `src/mainwindow.h`, `src/mainwindow.cpp` + +**设计改进**: + +**之前的设计**: +- 使用 QTabWidget 同时显示 VulkanWidget 和 CustomWidget +- 维护两个独立的组件指针 +- 需要重复的控制逻辑和状态管理代码 + +**新的设计**: +- 只显示一个渲染 Widget +- 使用 `RenderWidgetBase*` 统一指针 +- 通过编译选项决定使用哪个实现 +- 统一的控制按钮和状态显示 + +**核心代码**: + +```cpp +class MainWindow : public QMainWindow +{ +private: + RenderWidgetBase *m_renderWidget; // 统一的渲染组件指针 + + // 统一的控制按钮 + QPushButton *m_enableRenderBtn; + QPushButton *m_disableRenderBtn; + QPushButton *m_resetFrameBtn; + + // 统一的状态标签 + QLabel *m_rendererTypeLabel; + QLabel *m_initStatusLabel; + QLabel *m_renderStatusLabel; + QLabel *m_frameCountLabel; +}; +``` + +**组件创建**: + +```cpp +// 根据编译选项创建相应的渲染组件 +#ifdef ENABLE_VULKAN_WIDGET + m_renderWidget = new VulkanWidget(this); +#else + m_renderWidget = new CustomWidget(this); +#endif + +// 后续代码通过基类指针操作,无需关心具体实现 +m_renderWidget->initializeRenderer(); +m_renderWidget->setRenderingEnabled(true); +``` + +## 编译配置 + +### CMake 选项 + +通过 `ENABLE_VULKAN` 选项控制是否启用 Vulkan 支持: + +```cmake +option(ENABLE_VULKAN "Enable Vulkan support" ON) +``` + +### 编译时行为 + +**启用 Vulkan (`ENABLE_VULKAN=ON`)**: +- 检查 Vulkan 头文件是否存在 +- 编译 volk 动态加载库 +- 添加 `ENABLE_VULKAN_WIDGET` 宏定义 +- 编译 VulkanWidget 相关文件 +- MainWindow 创建 VulkanWidget 实例 + +**禁用 Vulkan (`ENABLE_VULKAN=OFF` 或 Vulkan 不可用)**: +- 不编译 VulkanWidget 相关文件 +- MainWindow 创建 CustomWidget 实例 +- 使用 QPainter 作为后备渲染方案 + +## 使用示例 + +### 基本使用 + +```cpp +// MainWindow 中的使用示例 +void MainWindow::onEnableRenderingClicked() +{ + if (m_renderWidget) { + // 确保渲染器已初始化 + if (!m_renderWidget->isInitialized()) { + bool success = m_renderWidget->initializeRenderer(); + if (!success) { + QMessageBox::warning(this, "Initialization Failed", + m_renderWidget->getLastError()); + return; + } + } + + // 启用渲染 + m_renderWidget->setRenderingEnabled(true); + } +} + +// 查询状态 +void MainWindow::updateStatusDisplay() +{ + QString type = m_renderWidget->getRendererType(); + bool isRendering = m_renderWidget->isRenderingEnabled(); + int frameCount = m_renderWidget->getRenderFrameCount(); + + // 更新 UI 显示 + m_rendererTypeLabel->setText("Renderer: " + type); + m_frameCountLabel->setText(QString("Frames: %1").arg(frameCount)); +} +``` + +### 锁屏检测集成 + +```cpp +void MainWindow::onLockStateChanged(bool locked) +{ + // 统一的锁屏处理逻辑 + if (m_renderWidget) { + m_renderWidget->setRenderingEnabled(!locked); + } +} +``` + +## 优势分析 + +### 1. 代码简化 + +**之前**: +- MainWindow 中有大量 `#ifdef ENABLE_VULKAN_WIDGET` 条件编译代码 +- 需要维护两套独立的控制逻辑 +- UI 代码重复(两套按钮、两套状态标签) + +**现在**: +- MainWindow 中几乎没有条件编译代码 +- 统一的控制逻辑 +- 统一的 UI 组件 + +### 2. 易于维护 + +- 添加新功能时,只需在基类中添加接口,各子类实现即可 +- MainWindow 代码量减少约 40% +- 更容易理解和维护 + +### 3. 灵活性 + +- 可以轻松添加新的渲染后端(OpenGL、DirectX、Metal 等) +- 可以在运行时动态切换渲染器(未来扩展) +- 可以通过配置文件选择渲染器(未来扩展) + +### 4. 用户体验 + +- 界面更加简洁,不再有多个 Tab +- 自动选择最佳的渲染方式 +- 统一的操作体验 + +## 扩展性设计 + +### 添加新的渲染后端 + +假设要添加 OpenGL 渲染支持: + +1. 创建 `OpenGLWidget` 类继承 `RenderWidgetBase` +2. 实现所有虚函数 +3. 在 CMakeLists.txt 中添加编译选项 +4. 在 MainWindow 构造函数中添加选择逻辑 + +```cpp +#ifdef ENABLE_VULKAN_WIDGET + m_renderWidget = new VulkanWidget(this); +#elif defined(ENABLE_OPENGL_WIDGET) + m_renderWidget = new OpenGLWidget(this); +#else + m_renderWidget = new CustomWidget(this); +#endif +``` + +### 运行时切换(未来功能) + +可以扩展设计以支持运行时切换渲染器: + +```cpp +void MainWindow::switchRenderer(RendererType type) +{ + if (m_renderWidget) { + delete m_renderWidget; + } + + switch (type) { + case RendererType::Vulkan: + m_renderWidget = new VulkanWidget(this); + break; + case RendererType::OpenGL: + m_renderWidget = new OpenGLWidget(this); + break; + case RendererType::QPainter: + default: + m_renderWidget = new CustomWidget(this); + break; + } + + // 重新初始化和布局 + setupRenderer(); +} +``` + +## 性能考虑 + +### 虚函数开销 + +- 基类使用虚函数会有轻微的性能开销 +- 但相比渲染本身的开销,这个开销可以忽略不计 +- 现代编译器对虚函数调用有很好的优化 + +### 内存占用 + +- 每个对象增加一个虚函数表指针(通常 8 字节) +- 由于只创建一个渲染 Widget 实例,内存影响微乎其微 + +## 测试建议 + +### 单元测试 + +```cpp +// 测试 Vulkan 初始化 +void testVulkanInitialization() { + VulkanWidget widget; + bool success = widget.initializeRenderer(); + QVERIFY(success || !widget.getLastError().isEmpty()); + QCOMPARE(widget.getRendererType(), QString("Vulkan")); +} + +// 测试 QPainter 初始化 +void testQPainterInitialization() { + CustomWidget widget; + bool success = widget.initializeRenderer(); + QVERIFY(success); + QCOMPARE(widget.getRendererType(), QString("QPainter")); + QVERIFY(widget.isInitialized()); +} + +// 测试渲染启用/禁用 +void testRenderingToggle() { + RenderWidgetBase* widget = createWidget(); + widget->initializeRenderer(); + + widget->setRenderingEnabled(true); + QVERIFY(widget->isRenderingEnabled()); + + widget->setRenderingEnabled(false); + QVERIFY(!widget->isRenderingEnabled()); +} +``` + +### 集成测试 + +- 测试 MainWindow 与不同渲染器的集成 +- 测试锁屏检测触发渲染器状态变化 +- 测试 UI 按钮与渲染器的交互 + +## 文件清单 + +### 新增文件 +- `src/renderwidgetbase.h` - 渲染组件基类 + +### 修改文件 +- `src/mainwindow.h` - 简化为使用单一渲染组件 +- `src/mainwindow.cpp` - 移除重复代码,使用统一接口 +- `src/customwidget.h` - 继承 RenderWidgetBase +- `src/customwidget.cpp` - 实现基类接口 +- `src/vulkanwidget.h` - 继承 RenderWidgetBase +- `src/vulkanwidget.cpp` - 实现基类接口 +- `CMakeLists.txt` - 添加 renderwidgetbase.h 到头文件列表 + +## 总结 + +统一渲染架构通过引入抽象基类,成功地实现了: + +1. ✅ 代码简化:减少了重复代码和条件编译 +2. ✅ 接口统一:MainWindow 通过统一接口操作渲染器 +3. ✅ 易于扩展:可以方便地添加新的渲染后端 +4. ✅ 向后兼容:保留了原有的特定方法 +5. ✅ 用户体验:提供了更简洁的界面 + +这个设计为项目的后续发展提供了坚实的基础,使得添加新功能和维护现有代码变得更加容易。 \ No newline at end of file diff --git a/src/customwidget.cpp b/src/customwidget.cpp index 401e998..97d6ed5 100644 --- a/src/customwidget.cpp +++ b/src/customwidget.cpp @@ -5,7 +5,7 @@ #include CustomWidget::CustomWidget(QWidget *parent) - : QWidget(parent) + : RenderWidgetBase(parent) , m_animationTimer(nullptr) , m_paintingEnabled(true) , m_frameCount(0) @@ -92,6 +92,45 @@ void CustomWidget::resetFrameCount() qDebug() << "Frame count reset"; } +// 实现 RenderWidgetBase 接口 +bool CustomWidget::initializeRenderer() +{ + // QPainter不需要特殊初始化,始终返回true + return true; +} + +void CustomWidget::setRenderingEnabled(bool enabled) +{ + setPaintingEnabled(enabled); +} + +bool CustomWidget::isRenderingEnabled() const +{ + return isPaintingEnabled(); +} + +int CustomWidget::getRenderFrameCount() const +{ + return getPaintFrameCount(); +} + +bool CustomWidget::isInitialized() const +{ + // QPainter始终处于初始化状态 + return true; +} + +QString CustomWidget::getLastError() const +{ + // QPainter通常不会有错误 + return QString(); +} + +QString CustomWidget::getRendererType() const +{ + return QString("QPainter"); +} + void CustomWidget::onAnimationTimer() { if (m_paintingEnabled) { diff --git a/src/customwidget.h b/src/customwidget.h index d9789b4..6e698f5 100644 --- a/src/customwidget.h +++ b/src/customwidget.h @@ -1,7 +1,7 @@ #ifndef CUSTOMWIDGET_H #define CUSTOMWIDGET_H -#include +#include "renderwidgetbase.h" #include #include #include @@ -9,42 +9,34 @@ #include /** - * @brief 自定义绘制组件类 + * @brief 自定义绘制组件类(使用QPainter) * * 这个组件会持续进行动画绘制,展示屏幕锁定检测的效果 * 当屏幕锁定时,会自动停止所有Paint事件 */ -class CustomWidget : public QWidget +class CustomWidget : public RenderWidgetBase { Q_OBJECT public: explicit CustomWidget(QWidget *parent = nullptr); - ~CustomWidget(); + ~CustomWidget() override; - /** - * @brief 启用或禁用绘制 - * @param enabled true表示启用绘制,false表示禁用 - */ + // 实现RenderWidgetBase接口 + bool initializeRenderer() override; + void setRenderingEnabled(bool enabled) override; + bool isRenderingEnabled() const override; + int getRenderFrameCount() const override; + void resetFrameCount() override; + bool isInitialized() const override; + QString getLastError() const override; + QString getRendererType() const override; + + // CustomWidget特有的方法(保持兼容性) void setPaintingEnabled(bool enabled); - - /** - * @brief 获取当前绘制状态 - * @return true表示绘制已启用,false表示已禁用 - */ bool isPaintingEnabled() const; - - /** - * @brief 获取绘制帧数统计 - * @return 已绘制的总帧数 - */ int getPaintFrameCount() const; - /** - * @brief 重置帧数计数器 - */ - void resetFrameCount(); - protected: /** * @brief 重写paintEvent以实现自定义绘制 @@ -104,4 +96,4 @@ private: int m_lockCount; // 锁屏次数 }; -#endif // CUSTOMWIDGET_H +#endif // CUSTOMWIDGET_H \ No newline at end of file diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 43d333f..26cc1e6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,43 +1,32 @@ #include "mainwindow.h" +#include "customwidget.h" +#ifdef ENABLE_VULKAN_WIDGET +#include "vulkanwidget.h" +#endif #include #include -#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , m_lockDetector(nullptr) - , m_customWidget(nullptr) -#ifdef ENABLE_VULKAN_WIDGET - , m_vulkanWidget(nullptr) -#endif + , m_renderWidget(nullptr) , m_centralWidget(nullptr) , m_mainLayout(nullptr) - , m_tabWidget(nullptr) , m_controlGroup(nullptr) - , m_enablePaintBtn(nullptr) - , m_disablePaintBtn(nullptr) + , m_enableRenderBtn(nullptr) + , m_disableRenderBtn(nullptr) , m_resetFrameBtn(nullptr) -#ifdef ENABLE_VULKAN_WIDGET - , m_vulkanControlGroup(nullptr) - , m_enableVulkanBtn(nullptr) - , m_disableVulkanBtn(nullptr) - , m_resetVulkanFrameBtn(nullptr) -#endif , m_statusGroup(nullptr) + , m_rendererTypeLabel(nullptr) , m_lockStatusLabel(nullptr) - , m_paintStatusLabel(nullptr) + , m_renderStatusLabel(nullptr) , m_frameCountLabel(nullptr) , m_detectorStatusLabel(nullptr) -#ifdef ENABLE_VULKAN_WIDGET - , m_vulkanStatusGroup(nullptr) - , m_vulkanInitLabel(nullptr) - , m_vulkanRenderStatusLabel(nullptr) - , m_vulkanFrameCountLabel(nullptr) -#endif + , m_initStatusLabel(nullptr) , m_updateTimer(nullptr) { setWindowTitle("Qt Screen Lock Detection Demo"); - setMinimumSize(800, 600); + setMinimumSize(800, 800); // 初始化锁屏检测器 m_lockDetector = new ScreenLockDetector(this); @@ -63,24 +52,23 @@ MainWindow::MainWindow(QWidget *parent) connect(m_updateTimer, &QTimer::timeout, this, &MainWindow::updateStatusDisplay); m_updateTimer->start(100); // 每100ms更新一次状态显示 -#ifdef ENABLE_VULKAN_WIDGET - // 初始化Vulkan并默认启用渲染 - if (m_vulkanWidget) { - bool vulkanInitOk = m_vulkanWidget->initializeVulkan(); - if (vulkanInitOk) { - m_vulkanWidget->setRenderingEnabled(true); - qDebug() << "VulkanWidget initialized and rendering enabled by default"; + // 初始化渲染器 + if (m_renderWidget) { + bool renderInitOk = m_renderWidget->initializeRenderer(); + if (renderInitOk) { + m_renderWidget->setRenderingEnabled(true); + qDebug() << m_renderWidget->getRendererType() << "renderer initialized and enabled by default"; } else { - qDebug() << "Failed to initialize VulkanWidget:" << m_vulkanWidget->getLastError(); + qDebug() << "Failed to initialize" << m_renderWidget->getRendererType() + << "renderer:" << m_renderWidget->getLastError(); } } -#endif // ENABLE_VULKAN_WIDGET // 初始化状态显示 updateStatusDisplay(); updateButtonStates(); - qDebug() << "MainWindow initialized"; + qDebug() << "MainWindow initialized with" << (m_renderWidget ? m_renderWidget->getRendererType() : "no") << "renderer"; } MainWindow::~MainWindow() @@ -105,112 +93,62 @@ void MainWindow::setupUI() QFont statusFont; statusFont.setPointSize(10); - // 创建Tab Widget - m_tabWidget = new QTabWidget(this); - m_mainLayout->addWidget(m_tabWidget, 1); - + // 创建渲染组件(根据编译选项选择Vulkan或QPainter) #ifdef ENABLE_VULKAN_WIDGET - // ========== Tab 1: VulkanWidget ========== - QWidget *vulkanTab = new QWidget(this); - QVBoxLayout *vulkanLayout = new QVBoxLayout(vulkanTab); - vulkanLayout->setSpacing(10); - vulkanLayout->setContentsMargins(10, 10, 10, 10); + m_renderWidget = new VulkanWidget(this); + qDebug() << "Creating VulkanWidget"; +#else + m_renderWidget = new CustomWidget(this); + qDebug() << "Creating CustomWidget (QPainter)"; +#endif - // 创建Vulkan渲染组件 - m_vulkanWidget = new VulkanWidget(this); - vulkanLayout->addWidget(m_vulkanWidget, 1); - - // 创建Vulkan控制面板 - m_vulkanControlGroup = new QGroupBox("Vulkan Control", this); - QHBoxLayout *vulkanControlLayout = new QHBoxLayout(m_vulkanControlGroup); - - m_enableVulkanBtn = new QPushButton("Enable Rendering", this); - m_disableVulkanBtn = new QPushButton("Disable Rendering", this); - m_resetVulkanFrameBtn = new QPushButton("Reset Frame Count", this); - - m_enableVulkanBtn->setMinimumHeight(35); - m_disableVulkanBtn->setMinimumHeight(35); - m_resetVulkanFrameBtn->setMinimumHeight(35); - - vulkanControlLayout->addWidget(m_enableVulkanBtn); - vulkanControlLayout->addWidget(m_disableVulkanBtn); - vulkanControlLayout->addWidget(m_resetVulkanFrameBtn); - vulkanControlLayout->addStretch(); - - vulkanLayout->addWidget(m_vulkanControlGroup); - - // 创建Vulkan状态显示面板 - m_vulkanStatusGroup = new QGroupBox("Vulkan Status Information", this); - QVBoxLayout *vulkanStatusLayout = new QVBoxLayout(m_vulkanStatusGroup); - - m_vulkanInitLabel = new QLabel("Vulkan Status: Not Initialized", this); - m_vulkanRenderStatusLabel = new QLabel("Rendering Status: Disabled", this); - m_vulkanFrameCountLabel = new QLabel("Frame Count: 0", this); - - m_vulkanInitLabel->setFont(statusFont); - m_vulkanRenderStatusLabel->setFont(statusFont); - m_vulkanFrameCountLabel->setFont(statusFont); - - vulkanStatusLayout->addWidget(m_vulkanInitLabel); - vulkanStatusLayout->addWidget(m_vulkanRenderStatusLabel); - vulkanStatusLayout->addWidget(m_vulkanFrameCountLabel); - - vulkanLayout->addWidget(m_vulkanStatusGroup); - - m_tabWidget->addTab(vulkanTab, "Vulkan Widget"); -#endif // ENABLE_VULKAN_WIDGET - - // ========== Tab 2: CustomWidget (QPainter) ========== - QWidget *customTab = new QWidget(this); - QVBoxLayout *customLayout = new QVBoxLayout(customTab); - customLayout->setSpacing(10); - customLayout->setContentsMargins(10, 10, 10, 10); - - // 创建自定义绘制组件 - m_customWidget = new CustomWidget(this); - customLayout->addWidget(m_customWidget, 1); + m_mainLayout->addWidget(m_renderWidget, 1); // 创建控制面板 - m_controlGroup = new QGroupBox("Manual Control", this); + m_controlGroup = new QGroupBox("Rendering Control", this); QHBoxLayout *controlLayout = new QHBoxLayout(m_controlGroup); - m_enablePaintBtn = new QPushButton("Enable Painting", this); - m_disablePaintBtn = new QPushButton("Disable Painting", this); + m_enableRenderBtn = new QPushButton("Enable Rendering", this); + m_disableRenderBtn = new QPushButton("Disable Rendering", this); m_resetFrameBtn = new QPushButton("Reset Frame Count", this); - m_enablePaintBtn->setMinimumHeight(35); - m_disablePaintBtn->setMinimumHeight(35); + m_enableRenderBtn->setMinimumHeight(35); + m_disableRenderBtn->setMinimumHeight(35); m_resetFrameBtn->setMinimumHeight(35); - controlLayout->addWidget(m_enablePaintBtn); - controlLayout->addWidget(m_disablePaintBtn); + controlLayout->addWidget(m_enableRenderBtn); + controlLayout->addWidget(m_disableRenderBtn); controlLayout->addWidget(m_resetFrameBtn); controlLayout->addStretch(); - customLayout->addWidget(m_controlGroup); + m_mainLayout->addWidget(m_controlGroup); // 创建状态显示面板 m_statusGroup = new QGroupBox("Status Information", this); QVBoxLayout *statusLayout = new QVBoxLayout(m_statusGroup); - m_lockStatusLabel = new QLabel("Screen Lock Status: Unknown", this); - m_paintStatusLabel = new QLabel("Painting Status: Unknown", this); - m_frameCountLabel = new QLabel("Frame Count: 0", this); + m_rendererTypeLabel = new QLabel("Renderer Type: Unknown", this); m_detectorStatusLabel = new QLabel("Detector Status: Initializing...", this); + m_initStatusLabel = new QLabel("Renderer Status: Not Initialized", this); + m_lockStatusLabel = new QLabel("Screen Lock Status: Unknown", this); + m_renderStatusLabel = new QLabel("Rendering Status: Unknown", this); + m_frameCountLabel = new QLabel("Frame Count: 0", this); - m_lockStatusLabel->setFont(statusFont); - m_paintStatusLabel->setFont(statusFont); - m_frameCountLabel->setFont(statusFont); + m_rendererTypeLabel->setFont(statusFont); m_detectorStatusLabel->setFont(statusFont); + m_initStatusLabel->setFont(statusFont); + m_lockStatusLabel->setFont(statusFont); + m_renderStatusLabel->setFont(statusFont); + m_frameCountLabel->setFont(statusFont); + statusLayout->addWidget(m_rendererTypeLabel); statusLayout->addWidget(m_detectorStatusLabel); + statusLayout->addWidget(m_initStatusLabel); statusLayout->addWidget(m_lockStatusLabel); - statusLayout->addWidget(m_paintStatusLabel); + statusLayout->addWidget(m_renderStatusLabel); statusLayout->addWidget(m_frameCountLabel); - customLayout->addWidget(m_statusGroup); - - m_tabWidget->addTab(customTab, "QPainter Widget"); + m_mainLayout->addWidget(m_statusGroup); } void MainWindow::setupConnections() @@ -226,35 +164,23 @@ void MainWindow::setupConnections() this, &MainWindow::onLockStateChanged); // 连接按钮信号 - connect(m_enablePaintBtn, &QPushButton::clicked, - this, &MainWindow::onEnablePaintingClicked); + connect(m_enableRenderBtn, &QPushButton::clicked, + this, &MainWindow::onEnableRenderingClicked); - connect(m_disablePaintBtn, &QPushButton::clicked, - this, &MainWindow::onDisablePaintingClicked); + connect(m_disableRenderBtn, &QPushButton::clicked, + this, &MainWindow::onDisableRenderingClicked); connect(m_resetFrameBtn, &QPushButton::clicked, this, &MainWindow::onResetFrameCountClicked); - -#ifdef ENABLE_VULKAN_WIDGET - // 连接Vulkan按钮信号 - connect(m_enableVulkanBtn, &QPushButton::clicked, - this, &MainWindow::onEnableVulkanClicked); - - connect(m_disableVulkanBtn, &QPushButton::clicked, - this, &MainWindow::onDisableVulkanClicked); - - connect(m_resetVulkanFrameBtn, &QPushButton::clicked, - this, &MainWindow::onResetVulkanFrameCountClicked); -#endif // ENABLE_VULKAN_WIDGET } void MainWindow::onScreenLocked() { qDebug() << "MainWindow: Screen locked event received"; - // 停止绘制 - if (m_customWidget) { - m_customWidget->setPaintingEnabled(false); + // 停止渲染 + if (m_renderWidget) { + m_renderWidget->setRenderingEnabled(false); } updateStatusDisplay(); @@ -265,9 +191,9 @@ void MainWindow::onScreenUnlocked() { qDebug() << "MainWindow: Screen unlocked event received"; - // 恢复绘制 - if (m_customWidget) { - m_customWidget->setPaintingEnabled(true); + // 恢复渲染 + if (m_renderWidget) { + m_renderWidget->setRenderingEnabled(true); } updateStatusDisplay(); @@ -278,9 +204,9 @@ void MainWindow::onLockStateChanged(bool locked) { qDebug() << "MainWindow: Lock state changed to:" << (locked ? "LOCKED" : "UNLOCKED"); - // 根据锁屏状态自动启用/禁用绘制 - if (m_customWidget) { - m_customWidget->setPaintingEnabled(!locked); + // 根据锁屏状态自动启用/禁用渲染 + if (m_renderWidget) { + m_renderWidget->setRenderingEnabled(!locked); } updateStatusDisplay(); @@ -289,10 +215,14 @@ void MainWindow::onLockStateChanged(bool locked) void MainWindow::updateStatusDisplay() { - if (!m_lockDetector) { + if (!m_lockDetector || !m_renderWidget) { return; } + // 更新渲染器类型 + QString rendererType = "Renderer Type: " + m_renderWidget->getRendererType() + ""; + m_rendererTypeLabel->setText(rendererType); + // 更新检测器状态 QString detectorStatus = "Detector Status: "; if (m_lockDetector) { @@ -302,6 +232,19 @@ void MainWindow::updateStatusDisplay() } m_detectorStatusLabel->setText(detectorStatus); + // 更新初始化状态 + QString initStatus = "Renderer Status: "; + if (m_renderWidget->isInitialized()) { + initStatus += "✓ Initialized"; + } else { + initStatus += "⚠ Not Initialized"; + QString error = m_renderWidget->getLastError(); + if (!error.isEmpty()) { + initStatus += " - " + error; + } + } + m_initStatusLabel->setText(initStatus); + // 更新锁屏状态 bool isLocked = m_lockDetector->isScreenLocked(); QString lockStatus = "Screen Lock Status: "; @@ -312,84 +255,63 @@ void MainWindow::updateStatusDisplay() } m_lockStatusLabel->setText(lockStatus); - // 更新绘制状态 - bool isPainting = m_customWidget ? m_customWidget->isPaintingEnabled() : false; - QString paintStatus = "Painting Status: "; - if (isPainting) { - paintStatus += "✓ ENABLED (Active)"; + // 更新渲染状态 + bool isRendering = m_renderWidget->isRenderingEnabled(); + QString renderStatus = "Rendering Status: "; + if (isRendering) { + renderStatus += "✓ ENABLED (Active)"; } else { - paintStatus += "✗ DISABLED (Stopped)"; + renderStatus += "✗ DISABLED (Stopped)"; } - m_paintStatusLabel->setText(paintStatus); + m_renderStatusLabel->setText(renderStatus); // 更新帧计数 - int frameCount = m_customWidget ? m_customWidget->getPaintFrameCount() : 0; + int frameCount = m_renderWidget->getRenderFrameCount(); QString frameCountStr = QString("Frame Count: %1 frames").arg(frameCount); m_frameCountLabel->setText(frameCountStr); - -#ifdef ENABLE_VULKAN_WIDGET - // 更新Vulkan状态 - if (m_vulkanWidget) { - // 更新初始化状态 - QString vulkanInitStatus = "Vulkan Status: "; - if (m_vulkanWidget->isInitialized()) { - vulkanInitStatus += "✓ Initialized"; - } else { - vulkanInitStatus += "⚠ Not Initialized"; - if (!m_vulkanWidget->getLastError().isEmpty()) { - vulkanInitStatus += " - " + m_vulkanWidget->getLastError(); - } - } - m_vulkanInitLabel->setText(vulkanInitStatus); - - // 更新渲染状态 - bool isVulkanRendering = m_vulkanWidget->isRenderingEnabled(); - QString vulkanRenderStatus = "Rendering Status: "; - if (isVulkanRendering) { - vulkanRenderStatus += "✓ ENABLED (Active)"; - } else { - vulkanRenderStatus += "✗ DISABLED (Stopped)"; - } - m_vulkanRenderStatusLabel->setText(vulkanRenderStatus); - - // 更新Vulkan帧计数 - int vulkanFrameCount = m_vulkanWidget->getRenderFrameCount(); - QString vulkanFrameCountStr = QString("Frame Count: %1 frames").arg(vulkanFrameCount); - m_vulkanFrameCountLabel->setText(vulkanFrameCountStr); - - // 更新Vulkan按钮状态 - m_enableVulkanBtn->setEnabled(!isVulkanRendering && m_vulkanWidget->isInitialized()); - m_disableVulkanBtn->setEnabled(isVulkanRendering); - } -#endif // ENABLE_VULKAN_WIDGET } void MainWindow::updateButtonStates() { - // 根据当前绘制状态更新按钮可用性 - bool isPainting = m_customWidget ? m_customWidget->isPaintingEnabled() : false; - m_enablePaintBtn->setEnabled(!isPainting); - m_disablePaintBtn->setEnabled(isPainting); + if (!m_renderWidget) { + return; + } + + // 根据当前渲染状态更新按钮可用性 + bool isRendering = m_renderWidget->isRenderingEnabled(); + bool isInitialized = m_renderWidget->isInitialized(); + + m_enableRenderBtn->setEnabled(!isRendering && isInitialized); + m_disableRenderBtn->setEnabled(isRendering); } -void MainWindow::onEnablePaintingClicked() +void MainWindow::onEnableRenderingClicked() { - qDebug() << "Manual enable painting clicked"; + qDebug() << "Manual enable rendering clicked"; - if (m_customWidget) { - m_customWidget->setPaintingEnabled(true); + if (m_renderWidget) { + if (!m_renderWidget->isInitialized()) { + bool success = m_renderWidget->initializeRenderer(); + if (!success) { + QMessageBox::warning(this, "Renderer Initialization Failed", + "Failed to initialize renderer:\n" + m_renderWidget->getLastError()); + updateStatusDisplay(); + return; + } + } + m_renderWidget->setRenderingEnabled(true); } updateStatusDisplay(); updateButtonStates(); } -void MainWindow::onDisablePaintingClicked() +void MainWindow::onDisableRenderingClicked() { - qDebug() << "Manual disable painting clicked"; + qDebug() << "Manual disable rendering clicked"; - if (m_customWidget) { - m_customWidget->setPaintingEnabled(false); + if (m_renderWidget) { + m_renderWidget->setRenderingEnabled(false); } updateStatusDisplay(); @@ -400,53 +322,9 @@ void MainWindow::onResetFrameCountClicked() { qDebug() << "Reset frame count clicked"; - if (m_customWidget) { - m_customWidget->resetFrameCount(); + if (m_renderWidget) { + m_renderWidget->resetFrameCount(); } updateStatusDisplay(); } - -#ifdef ENABLE_VULKAN_WIDGET -void MainWindow::onEnableVulkanClicked() -{ - qDebug() << "Manual enable Vulkan rendering clicked"; - - if (m_vulkanWidget) { - if (!m_vulkanWidget->isInitialized()) { - bool success = m_vulkanWidget->initializeVulkan(); - if (!success) { - QMessageBox::warning(this, "Vulkan Initialization Failed", - "Failed to initialize Vulkan:\n" + m_vulkanWidget->getLastError()); - updateStatusDisplay(); - return; - } - } - m_vulkanWidget->setRenderingEnabled(true); - } - - updateStatusDisplay(); -} - -void MainWindow::onDisableVulkanClicked() -{ - qDebug() << "Manual disable Vulkan rendering clicked"; - - if (m_vulkanWidget) { - m_vulkanWidget->setRenderingEnabled(false); - } - - updateStatusDisplay(); -} - -void MainWindow::onResetVulkanFrameCountClicked() -{ - qDebug() << "Reset Vulkan frame count clicked"; - - if (m_vulkanWidget) { - m_vulkanWidget->resetFrameCount(); - } - - updateStatusDisplay(); -} -#endif // ENABLE_VULKAN_WIDGET diff --git a/src/mainwindow.h b/src/mainwindow.h index e424ab9..3170e51 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -8,17 +8,14 @@ #include #include #include -#include #include "screenlockdetector.h" -#include "customwidget.h" -#ifdef ENABLE_VULKAN_WIDGET -#include "vulkanwidget.h" -#endif +#include "renderwidgetbase.h" /** * @brief 主窗口类 * - * 整合锁屏检测器和自定义绘制组件,提供用户界面 + * 整合锁屏检测器和渲染组件,提供用户界面 + * 使用统一的RenderWidgetBase基类指针,根据编译选项选择Vulkan或QPainter实现 */ class MainWindow : public QMainWindow { @@ -51,37 +48,20 @@ private slots: void updateStatusDisplay(); /** - * @brief 手动启用绘制按钮点击 + * @brief 启用渲染按钮点击 */ - void onEnablePaintingClicked(); + void onEnableRenderingClicked(); /** - * @brief 手动禁用绘制按钮点击 + * @brief 禁用渲染按钮点击 */ - void onDisablePaintingClicked(); + void onDisableRenderingClicked(); /** * @brief 重置帧计数器按钮点击 */ void onResetFrameCountClicked(); -#ifdef ENABLE_VULKAN_WIDGET - /** - * @brief 启用Vulkan渲染按钮点击 - */ - void onEnableVulkanClicked(); - - /** - * @brief 禁用Vulkan渲染按钮点击 - */ - void onDisableVulkanClicked(); - - /** - * @brief 重置Vulkan帧计数按钮点击 - */ - void onResetVulkanFrameCountClicked(); -#endif - private: /** * @brief 初始化UI组件 @@ -101,42 +81,26 @@ private: private: // 核心组件 ScreenLockDetector *m_lockDetector; - CustomWidget *m_customWidget; -#ifdef ENABLE_VULKAN_WIDGET - VulkanWidget *m_vulkanWidget; -#endif + RenderWidgetBase *m_renderWidget; // 统一的渲染组件指针 // UI组件 QWidget *m_centralWidget; QVBoxLayout *m_mainLayout; - QTabWidget *m_tabWidget; - // 控制面板 - CustomWidget + // 控制面板 QGroupBox *m_controlGroup; - QPushButton *m_enablePaintBtn; - QPushButton *m_disablePaintBtn; + QPushButton *m_enableRenderBtn; + QPushButton *m_disableRenderBtn; QPushButton *m_resetFrameBtn; -#ifdef ENABLE_VULKAN_WIDGET - // 控制面板 - VulkanWidget - QGroupBox *m_vulkanControlGroup; - QPushButton *m_enableVulkanBtn; - QPushButton *m_disableVulkanBtn; - QPushButton *m_resetVulkanFrameBtn; -#endif - // 状态显示 - CustomWidget + // 状态显示 QGroupBox *m_statusGroup; + QLabel *m_rendererTypeLabel; QLabel *m_lockStatusLabel; - QLabel *m_paintStatusLabel; + QLabel *m_renderStatusLabel; QLabel *m_frameCountLabel; QLabel *m_detectorStatusLabel; -#ifdef ENABLE_VULKAN_WIDGET - // 状态显示 - VulkanWidget - QGroupBox *m_vulkanStatusGroup; - QLabel *m_vulkanInitLabel; - QLabel *m_vulkanRenderStatusLabel; - QLabel *m_vulkanFrameCountLabel; -#endif + QLabel *m_initStatusLabel; // 更新定时器 QTimer *m_updateTimer; diff --git a/src/renderwidgetbase.h b/src/renderwidgetbase.h new file mode 100644 index 0000000..aecd8c8 --- /dev/null +++ b/src/renderwidgetbase.h @@ -0,0 +1,73 @@ +#ifndef RENDERWIDGETBASE_H +#define RENDERWIDGETBASE_H + +#include +#include + +/** + * @brief 渲染组件基类 + * + * 为VulkanWidget和CustomWidget提供统一的接口 + * MainWindow使用此基类指针来操作不同的渲染实现 + */ +class RenderWidgetBase : public QWidget +{ + Q_OBJECT + +public: + explicit RenderWidgetBase(QWidget *parent = nullptr) + : QWidget(parent) + { + } + + virtual ~RenderWidgetBase() = default; + + /** + * @brief 初始化渲染器(Vulkan需要,QPainter不需要) + * @return true表示初始化成功,false表示失败 + */ + virtual bool initializeRenderer() = 0; + + /** + * @brief 启用或禁用渲染/绘制 + * @param enabled true表示启用,false表示禁用 + */ + virtual void setRenderingEnabled(bool enabled) = 0; + + /** + * @brief 获取当前渲染/绘制状态 + * @return true表示已启用,false表示已禁用 + */ + virtual bool isRenderingEnabled() const = 0; + + /** + * @brief 获取渲染/绘制帧数统计 + * @return 已渲染的总帧数 + */ + virtual int getRenderFrameCount() const = 0; + + /** + * @brief 重置帧数计数器 + */ + virtual void resetFrameCount() = 0; + + /** + * @brief 获取初始化状态 + * @return true表示渲染器已成功初始化 + */ + virtual bool isInitialized() const = 0; + + /** + * @brief 获取错误信息 + * @return 最后的错误信息字符串 + */ + virtual QString getLastError() const = 0; + + /** + * @brief 获取渲染器类型名称 + * @return 渲染器类型字符串(如"Vulkan"或"QPainter") + */ + virtual QString getRendererType() const = 0; +}; + +#endif // RENDERWIDGETBASE_H \ No newline at end of file diff --git a/src/vulkanwidget.cpp b/src/vulkanwidget.cpp index 0517c06..85383f6 100644 --- a/src/vulkanwidget.cpp +++ b/src/vulkanwidget.cpp @@ -26,7 +26,7 @@ #endif VulkanWidget::VulkanWidget(QWidget *parent) - : QWidget(parent) + : RenderWidgetBase(parent) , m_instance(VK_NULL_HANDLE) , m_physicalDevice(VK_NULL_HANDLE) , m_device(VK_NULL_HANDLE) @@ -85,6 +85,76 @@ VulkanWidget::~VulkanWidget() qDebug() << "VulkanWidget destroyed"; } +// 实现 RenderWidgetBase 接口 +bool VulkanWidget::initializeRenderer() +{ + return initializeVulkan(); +} + +void VulkanWidget::setRenderingEnabled(bool enabled) +{ + if (m_renderingEnabled == enabled) { + return; + } + + m_renderingEnabled = enabled; + + if (m_renderingEnabled) { + qDebug() << "Vulkan rendering ENABLED - Resuming animations"; + // 恢复渲染时,重新启动定时器(锁屏时已停止) + if (!m_renderTimer->isActive()) { + m_renderTimer->start(16); // ~60 FPS + qDebug() << "Render timer restarted"; + } + + // Unlocked: calculate lock duration + if (m_lastLockTime.isValid()) { + QDateTime unlockTime = QDateTime::currentDateTime(); + m_lastLockDuration = m_lastLockTime.secsTo(unlockTime); + m_lockPaintFrameCount = m_frameCount - m_lastLockFrameCount; + qDebug() << "Screen was locked for" << m_lastLockDuration << "seconds"; + qDebug() << "Frames at lock:" << m_lastLockFrameCount + << "- Frames painted during lock:" << m_lockPaintFrameCount; + } + + m_startTime = QDateTime::currentDateTime(); + } else { + qDebug() << "Vulkan rendering DISABLED - Showing locked state"; + // 关键修复:渲染一帧锁屏界面后停止定时器 + m_needsLockedFrameUpdate = true; // 标记需要渲染锁屏帧 + + // Locked: record lock time + m_pauseTime = QDateTime::currentDateTime(); + m_lastLockTime = m_pauseTime; + m_lastLockFrameCount = m_frameCount; + m_lockCount++; + qDebug() << "Screen locked at" << m_lastLockTime.toString("yyyy-MM-dd hh:mm:ss") + << "- Lock count:" << m_lockCount + << "- Frame count at lock:" << m_lastLockFrameCount; + } +} + +bool VulkanWidget::isRenderingEnabled() const +{ + return m_renderingEnabled; +} + +int VulkanWidget::getRenderFrameCount() const +{ + return m_frameCount; +} + +void VulkanWidget::resetFrameCount() +{ + m_frameCount = 0; + qDebug() << "Vulkan frame count reset"; +} + +QString VulkanWidget::getRendererType() const +{ + return QString("Vulkan"); +} + bool VulkanWidget::initializeVulkan() { qDebug() << "Initializing Vulkan..."; @@ -906,64 +976,7 @@ void VulkanWidget::cleanupVulkan() qDebug() << "Vulkan cleanup complete"; } -void VulkanWidget::setRenderingEnabled(bool enabled) -{ - if (m_renderingEnabled == enabled) { - return; - } - m_renderingEnabled = enabled; - - if (m_renderingEnabled) { - qDebug() << "Vulkan rendering ENABLED - Resuming animations"; - // 恢复渲染时,重新启动定时器(锁屏时已停止) - if (!m_renderTimer->isActive()) { - m_renderTimer->start(16); // ~60 FPS - qDebug() << "Render timer restarted"; - } - - // Unlocked: calculate lock duration - if (m_lastLockTime.isValid()) { - QDateTime unlockTime = QDateTime::currentDateTime(); - m_lastLockDuration = m_lastLockTime.secsTo(unlockTime); - m_lockPaintFrameCount = m_frameCount - m_lastLockFrameCount; - qDebug() << "Screen was locked for" << m_lastLockDuration << "seconds"; - qDebug() << "Frames at lock:" << m_lastLockFrameCount - << "- Frames painted during lock:" << m_lockPaintFrameCount; - } - - m_startTime = QDateTime::currentDateTime(); - } else { - qDebug() << "Vulkan rendering DISABLED - Showing locked state"; - // 关键修复:渲染一帧锁屏界面后停止定时器 - m_needsLockedFrameUpdate = true; // 标记需要渲染锁屏帧 - - // Locked: record lock time - m_pauseTime = QDateTime::currentDateTime(); - m_lastLockTime = m_pauseTime; - m_lastLockFrameCount = m_frameCount; - m_lockCount++; - qDebug() << "Screen locked at" << m_lastLockTime.toString("yyyy-MM-dd hh:mm:ss") - << "- Lock count:" << m_lockCount - << "- Frame count at lock:" << m_lastLockFrameCount; - } -} - -bool VulkanWidget::isRenderingEnabled() const -{ - return m_renderingEnabled; -} - -int VulkanWidget::getRenderFrameCount() const -{ - return m_frameCount; -} - -void VulkanWidget::resetFrameCount() -{ - m_frameCount = 0; - qDebug() << "Frame count reset"; -} void VulkanWidget::showEvent(QShowEvent *event) { diff --git a/src/vulkanwidget.h b/src/vulkanwidget.h index 16877b6..16ee5d5 100644 --- a/src/vulkanwidget.h +++ b/src/vulkanwidget.h @@ -1,7 +1,7 @@ #ifndef VULKANWIDGET_H #define VULKANWIDGET_H -#include +#include "renderwidgetbase.h" #include #include #include @@ -30,55 +30,27 @@ typedef VkFlags VkSurfaceTransformFlagsKHR; * 使用Qt的native window属性创建Vulkan Surface * 通过volk机制加载Vulkan函数 */ -class VulkanWidget : public QWidget +class VulkanWidget : public RenderWidgetBase { Q_OBJECT public: explicit VulkanWidget(QWidget *parent = nullptr); - ~VulkanWidget(); + ~VulkanWidget() override; - /** - * @brief 初始化Vulkan环境 - * @return true表示初始化成功,false表示失败 - */ + // 实现RenderWidgetBase接口 + bool initializeRenderer() override; + void setRenderingEnabled(bool enabled) override; + bool isRenderingEnabled() const override; + int getRenderFrameCount() const override; + void resetFrameCount() override; + bool isInitialized() const override { return m_initialized; } + QString getLastError() const override { return m_lastError; } + QString getRendererType() const override; + + // VulkanWidget特有的方法(保持兼容性) bool initializeVulkan(); - /** - * @brief 启用或禁用渲染 - * @param enabled true表示启用渲染,false表示禁用 - */ - void setRenderingEnabled(bool enabled); - - /** - * @brief 获取当前渲染状态 - * @return true表示渲染已启用,false表示已禁用 - */ - bool isRenderingEnabled() const; - - /** - * @brief 获取渲染帧数统计 - * @return 已渲染的总帧数 - */ - int getRenderFrameCount() const; - - /** - * @brief 重置帧数计数器 - */ - void resetFrameCount(); - - /** - * @brief 获取初始化状态 - * @return true表示Vulkan已成功初始化 - */ - bool isInitialized() const { return m_initialized; } - - /** - * @brief 获取错误信息 - * @return 最后的错误信息字符串 - */ - QString getLastError() const { return m_lastError; } - protected: /** * @brief Qt事件:组件显示时