이 페이지에서

Qt 캔버스 페인터 - 컴팩트한 상태 예제

QWindow 에서 QCanvasPainter 의 사용을 보여줍니다.

이 예제는 순수한 QWindow 애플리케이션에서 Qt Canvas Painter를 사용하는 것을 보여줍니다. Qt Quick 또는 QWidget 는 전혀 사용되지 않으며, Core, Gui, Canvas Painter 이외의 Qt 모듈에 대한 의존성이 없습니다.

이 애플리케이션은 QRhi 을 사용하여 가속화된 3D 렌더링을 설정하고 QCanvasPainter 을 사용하여 창에 있는 모든 콘텐츠를 렌더링합니다. 렌더링과 QCanvasPainterQRhi 의 통합은 QCanvasRhiPaintDriver 를 통해 관리됩니다.

워크스루

애플리케이션은 플랫폼에 따라 사용할 3D API를 선택하는 동시에 명령줄 인수를 사용하여 요청할 수 있는 기능도 제공합니다.

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    app.setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents);

    QRhi::Implementation graphicsApi;
#if defined(Q_OS_WIN)
    graphicsApi = QRhi::D3D11;
#elif QT_CONFIG(metal)
    graphicsApi = QRhi::Metal;
#elif QT_CONFIG(vulkan)
    graphicsApi = QRhi::Vulkan;
#else
    graphicsApi = QRhi::OpenGLES2;
#endif

    QCommandLineParser cmdLineParser;
    cmdLineParser.addHelpOption();
    QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null"));
    cmdLineParser.addOption(nullOption);
    QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL"));
    cmdLineParser.addOption(glOption);
    QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
    cmdLineParser.addOption(vkOption);
    QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
    cmdLineParser.addOption(d3d11Option);
    QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
    cmdLineParser.addOption(d3d12Option);
    QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
    cmdLineParser.addOption(mtlOption);

    cmdLineParser.process(app);

    if (cmdLineParser.isSet(nullOption))
        graphicsApi = QRhi::Null;
    if (cmdLineParser.isSet(glOption))
        graphicsApi = QRhi::OpenGLES2;
    if (cmdLineParser.isSet(vkOption))
        graphicsApi = QRhi::Vulkan;
    if (cmdLineParser.isSet(d3d11Option))
        graphicsApi = QRhi::D3D11;
    if (cmdLineParser.isSet(d3d12Option))
        graphicsApi = QRhi::D3D12;
    if (cmdLineParser.isSet(mtlOption))
        graphicsApi = QRhi::Metal;

#if QT_CONFIG(opengl)
    QSurfaceFormat fmt;
    fmt.setDepthBufferSize(24);
    fmt.setStencilBufferSize(8);
#ifdef Q_OS_MACOS
    fmt.setVersion(4, 1);
    fmt.setProfile(QSurfaceFormat::CoreProfile);
#endif
    QSurfaceFormat::setDefaultFormat(fmt);
#endif

    MainWindow window(graphicsApi);
    window.resize(1920 / 2, 1080 / 2);
    window.show();

    return app.exec();
}

MainWindow는 QWindow 를 통해 렌더링된 콘텐츠를 표시하는 창을 구현하는 PainterWindow의 서브클래스이며, Qt의 3D 그래픽 추상화인 QRhi 을 구현합니다. 이 클래스의 임무는 노출 이벤트를 수신할 때, 즉 창이 표시될 때 QRhi 인스턴스를 초기화하고, 스왑체인과 깊이 스텐실 버퍼를 관리하고, 창 크기가 조정될 때 동작을 처리하고, MainWindow에 구현된 가상 paint() 함수를 호출하는 것입니다.

페인터윈도우 구현을 더 잘 이해하려면 RHI 창 예제를 확인하는 것이 좋습니다. 본질적으로 이 예제의 RhiWindow 클래스와 매우 유사하기 때문입니다.

QCanvasPainter-특정 단계 중 하나는 QRhi 가 성공적으로 초기화되면 QCanvasPainterFactory 인스턴스를 검색하는 것입니다:

    if (!m_factory) {
        m_factory = new QCanvasPainterFactory;
        m_factory->create(m_rhi.get());
    }

새 프레임 렌더링은 창이 표시되고 크기가 조정될 때, 그리고 requestUpdate()를 통해 예약된 업데이트 요청에 대한 응답으로 호출되는 render() 함수에서 이루어집니다.

RHI 창 예시와 달리 QRhi API를 통해 버텍스 및 균일 버퍼 또는 그래픽 파이프라인을 생성하지 않고 직접 그리기 호출을 발행하지 않습니다. 대신 QCanvasRhiPaintDriver 을 사용하여 QCanvasPainter-생성된 렌더링으로 렌더 패스를 기록합니다.

void PainterWindow::render() { if (!m_factory || !m_factory->isValid() || !m_rhi || !m_sc) return; if (!m_hasSwapChain || m_notExposed) return; if (m_sc->currentPixelSize() !=  m_sc->surfacePixelSize() || m_newlyExposed) { resizeSwapChain(); if (!m_hasSwapChain) return; m_newlyExposed = false; } QRhi::FrameOpResult r =  m_rhi->beginFrame(m_sc.get()); if (r== QRhi::FrameOpSwapChainOutOfDate) { resizeSwapChain(); if (!m_hasSwapChain) return; r =  m_rhi->beginFrame(m_sc.get()); } if (r ! = QRhi::FrameOpSuccess) {        qDebug("beginFrame failed with %d, retry", r);
        requestUpdate(); return; } QRhiCommandBuffer *cb =  m_sc->currentFrameCommandBuffer();    QRhiRenderTarget *rt =  m_sc->currentFrameRenderTarget();    QCanvasRhiPaintDriver *pd =  m_factory->paintDriver();    QCanvasPainter *painter =  m_factory->painter();  pd->resetForNewFrame();  pd->beginPaint(cb, rt, m_fillColor, size(), float(devicePixelRatio())); paint(painter);  pd->endPaint();  m_rhi->endFrame(m_sc.get()); }

MainWindow의 paint() 구현은 QCanvasPainter API와 함께 작동하며 QRhi 과 같은 저수준 세부 사항에 대해 걱정할 필요가 없습니다.

먼저 아직 완료되지 않은 경우 이미지를 로드하고 등록합니다:

void MainWindow::paint(QCanvasPainter *p)
{
    if (!m_initialized) {
        auto flags = QCanvasPainter::ImageFlag::GenerateMipmaps;
        m_b1ImageLight = p->addImage(QImage(":/images/icon_random_light.png"), flags);
        m_b1ImageDark = p->addImage(QImage(":/images/icon_random_dark.png"), flags);
        m_b2ImageLight = p->addImage(QImage(":/images/icon_theme_light.png"), flags);
        m_b2ImageDark = p->addImage(QImage(":/images/icon_theme_dark.png"), flags);
        m_b3ImageLight = p->addImage(QImage(":/images/icon_settings_light.png"), flags);
        m_b3ImageDark = p->addImage(QImage(":/images/icon_settings_dark.png"), flags);
        m_sImageLight = p->addImage(QImage(":/images/icon_run_light.png"), flags);
        m_sImageDark = p->addImage(QImage(":/images/icon_run_dark.png"), flags);
        m_initialized = true;
    }

그 다음에는 경로 채우기, 텍스트 렌더링, 이미지 그리기 등 실제 그리기가 이어집니다. 예를 들어

    // Highlight pressed button
    if (m_selectedButton) {
        p->beginPath();
        p->roundRect(m_views[m_selectedButton].rect, viewRadius);
        p->setLineWidth(2.0f * m_px);
        p->setStrokeStyle(m_theme.highlight());
        p->stroke();
    }

QCanvasPainter 채우기 및 획 그리기 호출은 내부적으로 버텍스, 인덱스, 균일 데이터 및 QRhi 기반 그리기 호출을 준비합니다. 명령 스트림은 endPaint()가 PainterWindow::render()에서 호출될 때 플러시됩니다. 여기서 렌더 패스가 연결된 QRhiCommandBuffer 에 기록됩니다.

반환하기 전에 MainWindow::paint()는 디스플레이의 표시 속도와 동기화된 새 프레임을 요청하는 QWindow 함수인 requestUpdate()를 호출합니다. 이를 통해 창 콘텐츠가 지속적으로 업데이트되고 애니메이션이 적용될 수 있습니다.

자세한 내용은 아래 링크된 전체 예제 소스 코드를 확인하세요.

예제 프로젝트 @ code.qt.io

© 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.