C++
Qt
QtQuick2
QML
qt5
QtDay 1

Qt Quickで折れ線グラフ

はじめに

このエントリはQt Advent Calendar 2017の一日目の記事です。
今回は、動的なデータに合わせて折れ線グラフを更新するという想定で、QMLのCanvasで描いた場合とQQuickPaintedItemを継承してQPainterで描いた場合とを比較してみました。
大きな要素としては以下の3つです。

  • なんとなくLive Coding的な仕組み
  • QMLのCanvasで折れ線グラフを描く
  • QQuickPaintedItemを継承して折れ線グラフを描く

コードは全てGitHubにあげてあります

前提

  • データは8系列、各系列300点データ
  • 各系列は0~30の範囲で推移
  • エラー処理などは入っていません
  • マジックナンバー多め

なんとなくLive Coding的な仕組み

QML変更して動作確認、というサイクルを繰り返すことになると思ったので、QMLファイルを更新したら自動で再読み込みする仕組みを先に作っておきました。これはmain.cppに書いてあります。

[1] 指定したルートディレクトリから再帰的に辿って見つかったqmlとjsファイルをQFileSystemWatcherで監視して、変更が見つかったら再読み込みさせています。

Windowsでは変更直後に再読み込みすると失敗することがあったのでSleepを入れています。また2回目以降のfileChangedシグナルが出なかったので毎回addPathしなおしています。
シャドウビルドOFFの前提でQMLのパスを書いてあります。

QMLのCanvasで折れ線グラフを描く

[2] Chart1.qmlのCanvas.onPaintでガリガリと描いています。getContextでContext2Dインスタンスを取得して、strokeStyleとlineWidthで色と線幅を指定し、beginPath, moveTo, lineToでpathを作ってstrokeで描画する流れです。

QQuickPaintedItemを継承して折れ線グラフを描く

[3] QQuickPaintedItemを継承したQPainterChartクラスを作り、paint関数を上書きしてこの中で折れ線グラフを描いています。
[4] main関数でQML側にこのクラスを登録しています。
[5] 登録した型をChart2.qmlで使用しています。

※ 始めはQPainterChartのchartDataプロパティをQList<QList<int>>型にしていてQMLからセットされずに悩んでいました。QMLから受ける時はQVariantListなんですね。

比較

手元の環境(Windows10 + Qt5.9.1MSVC)では、10fpsでQQuickPaintedItemで描くとCPU使用率15%前後、Canvasで描くと9%前後という結果になりました。QPainterで描く方が速いのかと思っていたので意外でした。