光栅窗口示例
本示例演示了如何使用QPainter 进行渲染,从而创建一个基于QWindow 的简易应用程序。
应用程序入口点
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
RasterWindow window;
window.show();
return app.exec();
}基于QWindow 的应用程序的入口点是QGuiApplication 类。它负责管理GUI应用程序的控制流和主要设置。我们将命令行参数传递给该类,这些参数可用于获取某些系统级选项。
随后,我们创建窗口实例,并调用QWindow::show() 函数,以此告知窗口系统该窗口应显示在屏幕上。
完成这一步后,我们进入应用程序的事件循环,以便应用程序开始运行。
RasterWindow 声明
#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 的子窗口。没有父窗口的QWindows在窗口系统中会作为顶级窗口显示。
该类声明了一个QBackingStore ,我们用它来管理窗口的后缓冲区,以支持基于QPainter 的图形渲染。
该光栅窗口在其他几个示例中也会被复用,并添加了一些辅助函数,例如 renderLater()。
RasterWindow 的实现
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());
}resize 事件保证会在窗口显示在屏幕上之前被调用,并且每当窗口在屏幕上被调整大小时也会被调用。我们利用这一点来调整后缓冲区的大小,并将渲染推迟到相应的或随后的 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() 立即渲染窗口。
© 2026 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.