警告

本节包含从C++自动翻译到Python的代码片段,可能存在错误。

光栅窗口示例#

此示例演示了如何使用QWindow构建基于QPainter的渲染功能的简化应用。

应用程序入口点#

if __name__ == "__main__":

    app = QGuiApplication(argc, argv)
    window = RasterWindow()
    window.show()
    sys.exit(app.exec())

基于QWindow的应用程序的入口点是QGuiApplication类。它管理GUI应用程序的流程和主要设置。我们传递命令行参数,这些参数可以用来选择某些系统级别的选项。

从这里,我们继续创建我们的窗口实例,然后调用show()函数来告诉窗口系统,该窗口现在应在屏幕上可见。

一旦完成以上步骤,我们就进入应用程序的事件循环,使应用程序可以运行。

RasterWindow 声明#

from PySide6 import QtGui

class RasterWindow(QWindow):

    Q_OBJECT
# public
    RasterWindow = explicit(QWindow parent = None)
    virtual void render(QPainter painter)
# public slots
    def renderLater():
    def renderNow():
# protected
    bool event(QEvent event) override
    def resizeEvent(event):
    def exposeEvent(event):
# private
m_backingStore = QScopedPointer()

我们首先包含<QtGui>头文件。这意味着我们可以使用Qt GUI模块中的所有类。如果需要,类也可以单独包含。

RasterWindow类直接子类自QWindow,并提供了一个构造函数,该构造函数允许窗口成为另一个QWindow的子窗口。无父窗口的QWindows在窗口系统中显示为顶级窗口。

该类声明了一个QBackingStore,这是我们用来管理窗口的后缓冲区的,以便通过QPainter进行图形渲染。

光栅窗口也在一些其他示例中重复使用,并增加了一些辅助函数,如renderLater()。

RasterWindow 实现#

def __init__(self, parent):
    super().__init__(parent)
    , m_backingStore(QBackingStore(self))

    setGeometry(100, 100, 300, 200)

在构造函数中,我们创建了backingstore,并将其传递给它需要管理的窗口实例。我们还设置了初始窗口几何形状。

def exposeEvent(self, arg__0):

    if isExposed():
        renderNow()

在调用创建的窗口上的 show() 函数后不久,将调用虚函数 exposeEvent() 来通知我们窗口在窗口系统中的曝光状态已更改。该事件包含曝光的子区域,但由于我们每次都要绘制整个窗口,所以我们没有利用这一点。

isExposed() 函数将告诉我们窗口是否显示。这是必需的,因为即使窗口在窗口系统中被遮挡,也会调用 exposeEvent。如果窗口显示,我们调用 renderNow() 立即绘制窗口。我们想立即绘制以向系统提供一些可视化内容。

def resizeEvent(self, resizeEvent):

    m_backingStore.resize(resizeEvent.size())

调整大小事件保证在窗口显示在屏幕上之前被调用,并且也会在窗口在屏幕上调整大小的情况下被调用。我们使用这一点来调整后缓冲区的大小,并将绘制延迟到相应的/后续的 expose 事件。

def renderNow(self):

    if not isExposed():
        return
    rect = QRect(0, 0, width(), height())
    m_backingStore.beginPaint(rect)
    device = m_backingStore.paintDevice()
    painter = QPainter(device)
    painter.fillRect(0, 0, width(), height(), QGradient.NightFade)
    render(painter)
    painter.end()
    m_backingStore.endPaint()
    m_backingStore.flush(rect)

renderNow 函数设置 QWindow 使用 QPainter 渲染其内容所需的所有内容。由于遮挡的窗口将不可见,因此如果窗口在窗口系统中未被暴露,将中止操作。例如,当另一个窗口完全遮挡此窗口时,可能会发生这种情况。

我们通过调用我们想要绘制的区域的 beginPaint() 来开始绘制。然后,我们获取后缓冲区的 QPaintDevice 并创建一个 QPainter 来渲染该绘图设备。

为了避免留下先前渲染的痕迹并从干净的缓冲区开始,我们用白色填充整个缓冲区。然后我们调用虚拟的 render() 函数来实际绘制此窗口。

绘制完成後,我们调用 endPaint() 来表示我们已完成渲染,并使用 flush() 在后缓冲区中提供内容。

def render(self, painter):

    painter.drawText(QRectF(0, 0, width(), height()), Qt.AlignCenter, "QWindow")

render 函数包含窗口的绘制代码。在这个简例中,我们只在中心绘制字符串“ QWindow ”。

异步渲染

def renderLater(self):

    requestUpdate()

我们在几个地方遇到了需要立即重新绘制的窗口。在某些情况下,这并不理想,而是应该让应用程序返回到事件循环并安排稍后重新绘制。我们通过请求更新实现这一点,使用requestUpdate(),系统准备好重新绘制时将会传递。

def event(self, QEvent event):

    if event.type() == QEvent.UpdateRequest:
        renderNow()
        return True

    return QWindow.event(event)

我们重新实现了虚拟QObject::event()函数来处理更新事件。当事件到来时,我们调用renderNow()立即渲染窗口。

示例项目 @ code.qt.io