QMLでアプリケーション開発しようと試行錯誤していると,プロパティの値が狙い通りになっているか確認したくなった。そこでQMLでのデバッグ方法を調べてまとめた。
目次
はじめに
QMLのデバッグ用API
プロファイル
デバッグ用APIの挿入場所
動作確認
おわりに
はじめに
QMLでのデバッグ方法について調べていたら,以下の記事を発見した。
どうやら,Qt Quick 2になってからQMLのデバッグ用APIが拡充されたようだ。上記の情報を参考にQMLで利用可能なAPIの一覧を整理する。
QMLのデバッグ用API QMLで利用可能なデバッグ用関数を以下の表にまとめた。
QMLデバッグ用API JavaScriptの関数 対応するQt/C++の関数 説明
print(str) qDebug() 引数の文字列strを表示。QtScript由来の関数。
console.log(str) qDebug() 引数の文字列strを表示。
console.debug(str) qDebug() 引数の文字列strを表示。
console.info(str) qDebug() 引数の文字列strを表示。
console.warn(str) qWarning() 引数の文字列strを表示。
console.error(str) qCritical() 引数の文字列strを表示。 console.count(str) 引数の文字列strと関数の呼び出し回数を表示。 console.trace() スタックトレース(呼び出し箇所の関数名,ファイル名,行番号,列番号)を表示する。最大10個まで表示。引数を持てない。 console.exception(str) 引数の文字列strを表示した後に,スタックトレースを表示。 console.assert(expr[, str]) 式exprの結果がfalseの場合,文字列strを表示してスタックトレースを表示。strは省略可能。 console.time(str) 同じ引数の文字列strで指定したtimeとtimeEndの範囲の時間をミリ秒単位で測定し,console.timeEnd呼び出し時にstrと共に表示。 console.timeEnd(str) 同じ引数の文字列strで指定したtimeとtimeEndの範囲の時間をミリ秒単位で測定し,console.timeEnd呼び出し時にstrと共に表示。 console.profile(str) QMLとJavaScriptのプロファイラーを有効にする。プログラムの実行時にオプション-qmljsdebugger=port:ポート番号が必要。 console.profileEnd(str) QMLとJavaScriptのプロファイラーを無効にする。
基本的には,JavaScriptのconsole系の関数群を使えばよさそうだ。特に以下の関数を今後多用することになると感じた。
頻出QMLデバッグAPI
print console.exception console.assert console.time/console.timeEnd printはconsole.logでもいいかと思ったが,printのほうが文字数が短いので,こちらでもよいだろう。
プロファイル デバッグ用APIの中に,プロファイル関係のものがある(console.profileとconsole.profileEnd)。これらを利用する場合は,コンパイルしたバイナリーの実行時に,以下のオプションをつける必要がある。
-qmljsdebugger=port:8080
QtCreatorで実行オプションをつける場合は,[Projects]>[Build & Run]>[Run]>[Command line arguments]に記入すればいい。
QtCreatorでのコマンド実行時オプションの指定場所
上記オプションをつけずに,実行した場合,console.profileとconsole.profileEndの呼び出し時にそれぞれ以下の警告が表示されてしまう。
Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX.
Ignoring console.profileEnd(): the debug service is disabled. プロファイラー機能はよくわかっていない。解説しているページヘのリンクをひとまず掲載しておく。
デバッグ用APIの挿入場所 ここまでで,QMLのデバッグ用APIがわかった。しかし,これらの関数をどこに仕込めばいいかという問題が生じる。自分で作った関数の中に仕込む場合は簡単だ。しかし,特に関数を仕込まない場合は,どこか適当なタイミングで関数を用意してやる必要がある。
Qtの文書を眺めていると,どうやらComponet.onCompleted
やComponent.onDestruction
イベントにデバッグ用関数を仕込めばよさそうだ。それぞれ,QMLのインスタンス生成と破棄のタイミングになる。
特に深い理由がなく,単純に値を確認したいだけであれば,Componet.onCompleted
が順当 だろう。
デバッグログの仕込み例
import QtQuick 2.9
QtObject {
Component.onCompleted: {
print("Completed")
} Component.onDestruction: { print("Destructed") } }
動作確認 実際にQMLにデバッグ用APIを仕込んで動作を確認した。ソースコードを以下に格納した。
QtExample/QMLDebug at master · senooken/QtExample
量は多くないので全文を以下にも掲載する。
QMLDebug.pro
QT += quick
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
main.qml
import QtQuick 2.9
QtObject {
Component.onCompleted: {
print("print")
console.log("log")
console.debug("debug")
console.info("info")
console.warn("warn")
console.error("error")
console.count("count")
console.trace() // stack trace
console.exception("exception: message & stack trace")
console.assert(true, "assert:true")
console.assert(false, "assert:false message & stack trace")
console.time("time")
console.timeEnd("time")
console.profile("profile")
console.profileEnd("profile")
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine("qrc:/main.qml");
return app.exec();
}
このプログラムQMLDebugを実行すると以下が表示される(QMLDebug.logにも格納)。
QMLDebug.log
QML debugging is enabled. Only use this in a safe environment.
QML Debugger: Waiting for connection on port 8080...
qml: print
qml: log
qml: debug
qml: info
qml: warn
qml: error
count: 1
onCompleted (qrc:/main.qml:13)
qml: exception: message & stack trace
onCompleted (qrc:/main.qml:14)
assert:false message & stack trace
onCompleted (qrc:/main.qml:16)
time: 0ms
Profiling started.
Profiling ended.
print系の関数は先頭に,qml:
が表示されるようだ。
おわりに QMLでのデバッグ方法をまとめた。再掲だが,特に以下の関数は今後よく使うことになるだろう。
頻出QMLデバッグAPI
print console.exception console.assert console.time/console.timeEnd QMLでデバッグするときはこれらのAPIを活用して,バグが発生しないように気をつけていきたい。
関連