光栅窗口范例

此范例展示如何创建最小 QWindow 基应用程序使用 QPainter 为渲染。

应用程序入口点

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 模块中的所有类。类也可以单独包括,若这是首选的。

The RasterWindow class subclasses QWindow directly and provides a constructor which allows the window to be a sub-window of another QWindow . Parent-less QWindows show up in the windowing system as top-level windows.

类声明 QBackingStore which is what we use to manage the window's back buffer for QPainter based graphics.

The raster window is also reused in a few other examples and adds a few helper functions, like renderLater().

RasterWindow 实现

RasterWindow::RasterWindow(QWindow *parent)
    : QWindow(parent)
    , m_backingStore(new QBackingStore(this))
{
    setGeometry(100, 100, 300, 200);
}
						

In the constructor we create the backingstore and pass it the window instance it is supposed to manage. We also set the initial window geometry.

void RasterWindow::exposeEvent(QExposeEvent *)
{
    if (isExposed())
        renderNow();
}
						

Shortly after calling QWindow::show () on a created window, the virtual function QWindow::exposeEvent () will be called to notify us that the window's exposure in the windowing system has changed. The event contains the exposed sub-region, but since we will anyway draw the entire window every time, we do not make use of that.

函数 QWindow::isExposed () will tell us if the window is showing or not. We need this as the exposeEvent is called also when the window becomes obscured in the windowing system. If the window is showing, we call renderNow() to draw the window immediately. We want to draw right away so we can present the system with some visual content.

void RasterWindow::resizeEvent(QResizeEvent *resizeEvent)
{
    m_backingStore->resize(resizeEvent->size());
}
						

The resize event is guaranteed to be called prior to the window being shown on screen and will also be called whenever the window is resized while on screen. We use this to resize the back buffer, and defer rendering to the corresponding/following expose event.

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);
}
						

The renderNow function sets up what is needed for a QWindow to render its content using QPainter . As obscured windows have will not be visible, we abort if the window is not exposed in the windowing system. This can for instance happen when another window fully obscures this window.

We start the drawing by calling QBackingStore::beginPaint () on the region we want to draw. Then we get the QPaintDevice of the back buffer and create a QPainter to render to that paint device.

To void leaving traces from the previous rendering and start with a clean buffer, we fill the entire buffer with the color white. Then we call the virtual render() function which does the actual drawing of this window.

After drawing is complete, we call endPaint() to signal that we are done rendering and present the contents in the back buffer using QBackingStore::flush ().

void RasterWindow::render(QPainter *painter)
{
    painter->drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, QStringLiteral("QWindow"));
}
						

The render function contains the drawing code for the window. In this minial example, we only draw the string " QWindow " in the center.

异步渲染

void RasterWindow::renderLater()
{
    requestUpdate();
}
						

We went through a few places where the window needed to repainted immediately. There are some cases where this is not desirable, but rather let the application return to the event loop and schedule the repaint for later. We achieve this by requesting an update, using QWindow::requestUpdate (), which will then be delivered when the system is ready to repaint.

bool RasterWindow::event(QEvent *event)
{
    if (event->type() == QEvent::UpdateRequest) {
        renderNow();
        return true;
    }
    return QWindow::event(event);
}
						

重实现虚拟 QObject::event () function to handle the update event. When the event comes in we call renderNow() to render the window right away.

范例工程 @ code.qt.io