Qt Canvas Painter - コンパクトなヘルスケアの例
QWindow におけるQCanvasPainter の使用例を示します。

このサンプルでは、純粋なQWindow アプリケーションにおけるQt Canvas Painterの使用方法を示します。 Qt Quick および Qt Widgets スタックは使用されません。
このアプリケーションは、QCanvasPainter を使用して、すべてのコンテンツをQRhi バックエンドを通じてレンダリングします。レンダリングおよびQCanvasPainter とQRhi との統合は、QCanvasRhiPaintDriver を通じて管理されます。つまり、選択されたバックエンドで利用可能な場合は、ハードウェアアクセラレーションが使用されます。
注: QRhi はQt GUI Privateの一部です。そのため、互換性の保証は限定的です。これらのクラスについては、ソース互換性およびバイナリ互換性の保証はなく、APIはアプリケーションが開発されたQtのバージョンでのみ動作することが保証されています。
この例の目的
- QWindow 内で完全にカスタマイズされた UI をレンダリングする。
- QRhi 、スワップチェーン、および深度・ステンシルリソースの作成と管理。
- QCanvasPainter およびQCanvasRhiPaintDriver を通じて描画コマンドを記録する。
- QWindow::requestUpdate() を使用した連続アニメーションの実行。
手順解説
このアプリケーションは、デフォルトでプラットフォームに基づいてレンダリングAPIを選択します。また、コマンドライン引数を使用して特定のバックエンドを指定することもできます:
--null--opengl--vulkan--d3d11--d3d12--metal
バックエンドの作成に失敗した場合、このサンプルは、利用可能な場合、OpenGL ES 2 にフォールバックしようとします。
intmain(intargc, 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
#if QT_CONFIG(vulkan)
QVulkanInstance vulkanInstance;
if(graphicsApi==QRhi::Vulkan) {
vulkanInstance.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
if(!vulkanInstance.create()) {
#if QT_CONFIG(opengl)
qWarning("Vulkan is not usable, falling back to OpenGL");
graphicsApi=QRhi::OpenGLES2;
#else
qWarning("Vulkan is not usable, falling back to the null backend");
graphicsApi=QRhi::Null;
#endif
}
}
#endif
MainWindow window(graphicsApi);
#if QT_CONFIG(vulkan)
if(graphicsApi==QRhi::Vulkan)
window.setVulkanInstance(&vulkanInstance);
#endif
window.resize(1920 / 2, 1080 / 2);
window.show();
returnapp.exec();
}MainWindow は、PainterWindow のサブクラスであり、 はQWindow です。PainterWindow は、Qtのグラフィックス抽象化であるQRhi を介してレンダリングされたコンテンツを表示するウィンドウを実装しています。このクラスは、ウィンドウが公開された際にQRhi インスタンスを初期化し、スワップチェーンと深度・ステンシルバッファを管理し、サイズ変更イベントを処理し、MainWindow によって実装された仮想関数paint() を呼び出します。
PainterWindow の実装をより深く理解するには、RHI Window Exampleを参照することをお勧めします。なぜなら、本質的にはその例にあるRhiWindow クラスと非常に似ているからです。
QCanvasPainter 特有の処理として、QRhi の初期化後にQCanvasPainterFactory のインスタンスを取得する手順があります:
if (!m_factory) {
m_factory = new QCanvasPainterFactory;
m_factory->create(m_rhi.get());
}新しいフレームのレンダリングは `render() ` 関数内で行われます。この関数は、ウィンドウの表示やサイズ変更時、および `requestUpdate()` を通じてスケジュールされた更新要求に応答して呼び出されます。
「RHI ウィンドウの例」とは異なり、ここではQRhi API を使用して頂点バッファやユニフォームバッファ、グラフィックスパイプラインを作成せず、直接描画呼び出しを発行します。その代わりに、QCanvasRhiPaintDriver を使用して、QCanvasPainter によって生成されたレンダリングを含むレンダリングパスを記録します。
voidPainterWindow::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 drawの処理を準備します。PainterWindow::render() 内でendPaint()が呼び出されると、コマンドストリームがフラッシュされます。そこで、関連するQRhiCommandBuffer にレンダリングパスが記録されます。
MainWindow::paint() は、戻り値返す前に、requestUpdate()を呼び出します。これはQWindow の関数であり、ディスプレイの表示レートと同期した新しいフレームを要求します。これにより、アニメーションのためにコンテンツが継続的に更新されます。
実装の詳細については、完全なサンプルソースコードを参照してください。
© 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.