光栅窗口示例
该示例展示了如何使用QPainter 创建一个基于QWindow 的最小应用程序来进行渲染。
应用程序入口点
int main(int argc, char **argv) { QGuiApplication app(argc, argv); RasterWindow window; window.show(); return app.exec(); }
基于QWindow 的应用程序的入口点是QGuiApplication 类。它管理 GUI 应用程序的控制流和主要设置。我们传递命令行参数,这些参数可用于获取某些系统选项。
接着,我们创建窗口实例,然后调用QWindow::show() 函数,告诉窗口系统现在应在屏幕上显示该窗口。
完成后,我们进入应用程序的事件循环,这样应用程序就可以运行了。
光栅窗口声明
#include <QtGui> #include <QScopedPointer> class RasterWindow : public QWindow { Q_OBJECT public: explicit RasterWindow(QWindow *parent = nullptr); virtual void render(QPainter *painter); public slots: void renderLater(); void renderNow(); protected: bool event(QEvent *event) override; void resizeEvent(QResizeEvent *event) override; void exposeEvent(QExposeEvent *event) override; private: QScopedPointer<QBackingStore> m_backingStore; };
首先,我们要加入<QtGui>
头文件。这意味着我们可以使用Qt GUI 模块中的所有类。如果愿意,也可以单独包含类。
RasterWindow 类直接是QWindow 的子类,并提供了一个构造函数,允许窗口成为另一个QWindow 的子窗口。无父 QWindow 在窗口系统中显示为顶级窗口。
该类声明了一个QBackingStore ,我们用它来管理基于QPainter 图形的窗口后端缓冲区。
光栅窗口还在其他一些示例中重复使用,并添加了一些辅助函数,如 renderLater()。
光栅窗口的实现
RasterWindow::RasterWindow(QWindow *parent) : QWindow(parent) , m_backingStore(new QBackingStore(this)) { setGeometry(100, 100, 300, 200); }
在构造函数中,我们创建了后备存储,并将其应管理的窗口实例传递给它。我们还设置了初始窗口几何图形。
void RasterWindow::exposeEvent(QExposeEvent *) { if (isExposed()) renderNow(); }
在创建的窗口上调用QWindow::show() 后不久,虚拟函数QWindow::exposeEvent() 将被调用,以通知我们窗口在窗口系统中的曝光发生了变化。该事件包含已显示的子区域,但由于我们每次都会绘制整个窗口,因此不会使用该事件。
函数QWindow::isExposed() 将告诉我们窗口是否显示。我们需要这个函数,因为当窗口在窗口系统中被遮挡时,exposeEvent 也会被调用。如果窗口正在显示,我们将调用 renderNow() 立即绘制窗口。我们希望立即绘制窗口,以便向系统展示一些可视化内容。
void RasterWindow::resizeEvent(QResizeEvent *resizeEvent) { m_backingStore->resize(resizeEvent->size()); }
调整大小事件保证在窗口显示在屏幕上之前被调用,并且在屏幕上调整窗口大小时也会被调用。我们利用它来调整后端缓冲区的大小,并将渲染推迟到相应的/后续的 expose 事件。
void RasterWindow::renderNow() { if (!isExposed()) return; QRect rect(0, 0, width(), height()); m_backingStore->beginPaint(rect); QPaintDevice *device = m_backingStore->paintDevice(); QPainter painter(device); painter.fillRect(0, 0, width(), height(), QGradient::NightFade); render(&painter); painter.end(); m_backingStore->endPaint(); m_backingStore->flush(rect); }
renderNow 函数使用QPainter 设置QWindow 渲染其内容所需的内容。由于被遮挡的窗口将不可见,因此如果窗口未在窗口系统中曝光,我们就会终止渲染。例如,当另一个窗口完全遮挡住该窗口时就会出现这种情况。
我们在要绘制的区域上调用QBackingStore::beginPaint() 开始绘制。然后,我们会获取后端缓冲区的QPaintDevice ,并创建QPainter 渲染至该绘图设备。
为了避免留下上次渲染的痕迹,并从一个干净的缓冲区开始,我们将整个缓冲区填充为白色。然后,我们调用虚拟 render() 函数来完成窗口的实际绘制。
绘制完成后,我们调用 endPaint() 来提示渲染完成,并使用QBackingStore::flush() 将内容显示在后部缓冲区中。
void RasterWindow::render(QPainter *painter) { painter->drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, QStringLiteral("QWindow")); }
render 函数包含窗口的绘制代码。在这个小例子中,我们只在中间绘制了字符串 "QWindow"。
异步渲染
void RasterWindow::renderLater() { requestUpdate(); }
我们浏览了一些需要立即重新绘制窗口的地方。在某些情况下,这样做并不可取,不如让应用程序返回事件循环,并将重新绘制安排在稍后进行。为此,我们使用QWindow::requestUpdate() 请求更新,当系统准备好重新绘制时,就会发送更新。
bool RasterWindow::event(QEvent *event) { if (event->type() == QEvent::UpdateRequest) { renderNow(); return true; } return QWindow::event(event); }
我们重新实现了虚拟QObject::event() 函数来处理更新事件。当事件发生时,我们调用 renderNow() 立即渲染窗口。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.