9.5 KiB
9.5 KiB
统一渲染架构快速入门
概述
本项目采用统一的渲染架构设计,通过抽象基类 RenderWidgetBase 实现对 Vulkan 和 QPainter 两种渲染方式的统一管理。
核心设计
三层架构
┌─────────────────────────────────────┐
│ MainWindow │ ← 使用统一接口
│ (RenderWidgetBase* m_renderWidget) │
└──────────────┬──────────────────────┘
│
↓
┌─────────────────────────────────────┐
│ RenderWidgetBase (基类) │ ← 定义统一接口
│ - initializeRenderer() │
│ - setRenderingEnabled() │
│ - getRenderFrameCount() │
│ - getRendererType() │
└──────────────┬──────────────────────┘
│
┌───────┴────────┐
↓ ↓
┌─────────────┐ ┌─────────────┐
│VulkanWidget │ │CustomWidget │ ← 具体实现
│ (Vulkan) │ │ (QPainter) │
└─────────────┘ └─────────────┘
编译选项
使用 Vulkan(默认,如果可用)
cd ScreenLockDetector
mkdir -p build && cd build
cmake .. -DENABLE_VULKAN=ON
make -j4
结果:应用将使用 VulkanWidget 进行硬件加速渲染
使用 QPainter(后备方案)
cd ScreenLockDetector
mkdir -p build && cd build
cmake .. -DENABLE_VULKAN=OFF
make -j4
结果:应用将使用 CustomWidget 进行 CPU 绘制
自动回退
如果 Vulkan 头文件不可用,CMake 会自动回退到 QPainter:
cmake ..
# 输出:Vulkan headers not found, disabling Vulkan support
主要改进
之前的设计问题
// ❌ 旧设计:需要维护两个独立的组件
private:
CustomWidget *m_customWidget;
#ifdef ENABLE_VULKAN_WIDGET
VulkanWidget *m_vulkanWidget;
#endif
QTabWidget *m_tabWidget; // 使用 Tab 切换
新的统一设计
// ✅ 新设计:单一组件指针
private:
RenderWidgetBase *m_renderWidget; // 统一接口
// 构造函数中根据编译选项创建
#ifdef ENABLE_VULKAN_WIDGET
m_renderWidget = new VulkanWidget(this);
#else
m_renderWidget = new CustomWidget(this);
#endif
统一接口使用示例
1. 初始化渲染器
// 对于 VulkanWidget:内部调用 initializeVulkan()
// 对于 CustomWidget:直接返回 true(无需初始化)
bool success = m_renderWidget->initializeRenderer();
if (!success) {
qDebug() << "Error:" << m_renderWidget->getLastError();
}
2. 控制渲染
// 启用渲染(适用于任何渲染器)
m_renderWidget->setRenderingEnabled(true);
// 禁用渲染(适用于任何渲染器)
m_renderWidget->setRenderingEnabled(false);
// 查询状态
bool isRendering = m_renderWidget->isRenderingEnabled();
3. 获取状态信息
// 获取渲染器类型
QString type = m_renderWidget->getRendererType();
// 返回 "Vulkan" 或 "QPainter"
// 获取帧数统计
int frames = m_renderWidget->getRenderFrameCount();
// 检查初始化状态
bool initialized = m_renderWidget->isInitialized();
4. 错误处理
if (!m_renderWidget->isInitialized()) {
if (!m_renderWidget->initializeRenderer()) {
QMessageBox::warning(
this,
"初始化失败",
m_renderWidget->getLastError()
);
}
}
锁屏检测集成
无论使用哪种渲染器,锁屏检测的处理逻辑完全一致:
void MainWindow::onLockStateChanged(bool locked)
{
// 统一的处理逻辑
if (m_renderWidget) {
m_renderWidget->setRenderingEnabled(!locked);
}
updateStatusDisplay();
updateButtonStates();
}
添加新渲染器
假设要添加 OpenGL 支持:
1. 创建新类
// 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
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 构造函数
#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:
cmake .. -DENABLE_VULKAN=OFF
make -j4
Q: 两种渲染器性能差异大吗?
A:
- Vulkan: 硬件加速,GPU 渲染,CPU 占用低,适合复杂场景
- QPainter: CPU 渲染,CPU 占用较高,但兼容性最好
Q: 可以在运行时切换渲染器吗?
A: 当前版本不支持,但架构设计已经为此功能预留了空间。
相关文档
贡献指南
如果您想添加新的渲染后端:
- 创建新类继承
RenderWidgetBase - 实现所有虚函数
- 在 CMakeLists.txt 中添加编译选项
- 在 MainWindow 中添加创建逻辑
- 编写测试用例
- 更新文档
欢迎提交 Pull Request!