Skip to main content

Qt 6.12におけるHot Reload

コメント
 このブログは「Hot Reload in Qt 6.12」の抄訳です。 

QML Preview

私たちは長年にわたり 「QML Preview」 と呼ばれる機能を提供してきました。この機能に気付かなかったとしても無理はありません。QML Preview は Qt Design Studio の内部深くにひっそりと組み込まれており、表立って目立つことなく動作してきたからです。QML Preview は、デザインを qml ツールで実行し、関連するファイルが変更されたことを検知します。そして、プロセス全体を再起動することなく、現在表示中のシーンだけを再読み込みして変更内容を反映します。これにより、さまざまなデザインを試作する際の修正から確認までのサイクルを短縮し、より迅速な開発が可能になります。

ただし、ここにはあまり知られていない事実があります: 実は QML Preview は Qt Design Studio 専用の機能ではありません。Qt Creator からも利用できます。メニューの(Build -> QML Preview) を選択することで使用できます。さらに、Qt とともに提供されるコマンドラインツールqmlpreview からも利用できます。また、QML Preview は QML ファイルの実行環境として qmlツールのみを対象としているわけでもありません。Qt Creator や qmlpreviewを使用すれば、既存のアプリケーションに含まれている QML コードをプレビューすることも可能です。つまり、QML Preview は単なるデザイン確認ツールではなく、アプリケーション内で使用されている QML を対象としたプレビュー機能としても利用できます。

Re-loading(再読み込み)

シーン全体を最初から再読み込みする方式には、大きな利点が 1 つあります:それは、何が変更されたのかを理解する必要がない唯一の実装方法であるということです。一度すべてを削除し、もう一度構築し直せば、新しいドキュメントに書かれている内容がそのまま反映されます。そのため、QML Preview はこれまでこの方式で動作していました。具体的には、ファイルが変更されるたびに、QML Preview は次の処理を実行します。作成済みのすべてのオブジェクトを削除する、シングルトンをクリアする、コンポーネントキャッシュをクリアする、ピックスマップキャッシュを消去する、コンポーネントを再インスタンス化する。意図的に保持されるのは、ウィンドウの位置だけです。

もっとも、これですら OS やウィンドウマネージャーが協力してくれる場合に限ります。近年のオペレーティングシステムは、アプリケーションが任意にウィンドウ位置を決定することに対して、以前より制限を強める傾向にあります。以前のシーンを破棄してしまうということは、QML コードとアプリケーションロジックとの接続も切断されることを意味します。その結果、場合によってはアプリケーションがクラッシュすることさえあります。後者については回避策もありますが、ここでその話をする必要はないでしょう。

また、使い勝手の観点から見ても、再読み込み方式には大きな欠点があります。変更が発生するたびに UI の状態がすべて失われ、シーン全体が最初から読み直されるからです。例えば、変更の影響を確認するために 5 つの画面を経由して目的の画面まで移動したとします。その状態でコードを修正すると、再読み込み後には再び最初の画面に戻ってしまいます。そのため、変更結果を確認するには、もう一度 5 つの画面を順番に辿って目的の場所まで移動しなければなりません。

Event replay(イベント再生)

この問題を緩和するための分かりやすい方法があります。実際、Qt 6.11 以降、そのための仕組みはすでに用意されていました。これまで特に告知していなかっただけです。その方法とは、ユーザーの入力イベントを記録し、新しく生成されたシーンに対して再生することで、変更前とほぼ同じ状態まで復元するというものです。QML Profiler サービスは以前から、アプリケーションが受け取る入力イベントを記録する機能を備えています。また、適切なオプションを指定すれば、入力イベント以外の情報を記録しないようにすることもできます。そして Event Replay サービスは、その記録されたイベントを受け取り、実行中のプログラムへ再び送り込むことができます。イベント再生時には、アニメーションは通常の 1000 倍の速度 で実行され、イベントはアプリケーションが処理できる限り高速に再生されます。そのため、この方法を利用すると、深い状態まで戻るためにリアルタイムで操作を再現する必要はなく、短時間で状態を復元できます。Qt Creator では、バージョン 19 以降、この仕組みを利用しています。QML Preview によってシーンが再読み込みされる際、Qt Creator は入力イベントを記録し、再読み込み後にそれらを自動的に再生します。

しかし、イベント再生にもいくつかの課題があります。まず第一に、アプリケーションが「UI 全体が消滅し、その後再生成される」という状況に正しく対応できていない場合、イベント再生を行ってもアプリケーションはクラッシュしてしまいます。さらに、バックエンドから取得するデータについても問題があります。再読み込み前と再読み込み後ではデータの内容が変わっている可能性がありますし、そもそも再取得に大きなコストがかかる場合もあります。また、イベント再生は大きなレイアウト変更に対しては頑健ではありません。例えば、編集によってボタンの位置が移動した場合、記録されていたクリックイベントは本来のボタンの位置ではなく、移動前の位置に送られてしまいます。その結果、クリックはボタンの隣に着弾することになり、期待した動作になりません。さらに、Pong のようなゲームを考えてみてください。そのようなアプリケーションでは、イベント再生によって復元できるのはせいぜい Game Over 画面程度です。Pong のように UI 要素が自発的に動き続けるアプリケーションでは、入力イベントの対象となる位置が時間に依存しています。一方、イベント再生サービスは可能な限り高速にイベントを再生するため、このような時間依存の前提は成立しません。実は、単純な画面遷移アニメーションですら同様の問題に遭遇します。アニメーションは通常、フレームごとに少しずつ進行します。しかしイベント再生では、ユーザーが数十秒かけて行ったクリック操作を 1〜2 フレームの間にまとめて送り込むことができます。その結果、本来は遷移後の画面に対して行われるはずだったクリックが、まだ遷移前の画面に対して送られてしまうことがあります。つまり、イベント再生は運が良ければ、元いた状態にかなり近い場所まで戻してくれます。しかし、それが完全に同じ状態であることを保証するものではありません。

左側のアプリケーションは 5 画面分深い階層まで進んだ状態です。編集中のファイルは右側に表示されており、その下には qmlpreviewが出力する内容が表示されています。色を変更したときに、qmlpreview が高速再生(早送り)のように UI の各状態を順番にたどり直していく様子に注目してください。

Hot reload

状態を再現する方法については以上です。もう一つの方法は、そもそも状態を破棄しないことです: つまり、アプリケーション全体を作り直すのではなく、QML のデータだけを更新し、可能な限り C++ オブジェクトは生かしたままにします。それが Qt 6.12 の Hot Reload が行うことです(ほとんどの場合において)。

Qt 6.12 では、あなたが今編集した内容と、現在アプリケーション上で実行されている内容を比較し、違っている部分だけを更新します。その結果、オブジェクトは生存したまま、ウィンドウは同一インスタンスのまま、変更していない状態はそのまま維持されます。例えば変更内容が、色の変更、サイズの変更、バインディングの変更、関数本体の変更、程度であれば、オブジェクトは一切再生成されません。アプリケーションは動作を継続したまま、ある瞬間から見た目だけが変化します。つまり、先ほどの例で言えば、再読み込み後に最初の画面へ戻されることはありません。あなたはそのまま 5 つ目の画面に留まった状態で、変更結果を確認できます。

左側には先ほどと同じアプリケーションが表示されており、現在も 5 つ目の画面まで遷移した状態になっています。今回は Hot Reload が動作しています。QML コードを変更した際に、アプリケーションが再起動されたり最初の画面に戻ったりすることなく、そのまま 5 つ目の画面に留まり続ける様子に注目してください。

ただし、先ほど括弧書きで述べた 「ほとんどの場合(most of the time)」 という表現は飾りではありません。変更内容の中には、シーンの一部を再構築しなければ適用できないものがあります。また、適用そのものができない変更もわずかながら存在します。このブログ記事の残りの大部分では、その境界線がどこにあるのかについて説明していきます。さて、ここまでで基本的な考え方は理解できたと思います。

それでは実際の利用方法について見ていきましょう。実際には、どのようにして Hot Reload を使用するのでしょうか?

実際に動かしてみる

Qt Creator を使用している場合、通常は 「Build」→「QML Preview」 をクリックするだけです。これでプレビューが起動し、読み込まれている QML ファイルのいずれかを変更すると、自動的に内容が更新されます。なお、自動的に有効化されていない場合は、ビルド設定で 「QML Debugging and Profiling」 を明示的に有効化する必要があります。デバッグビルドであれば、通常は有効になっているはずです。

Qt Creator を使用していない場合でも、アプリケーションは QML デバッグ機能を有効にしてビルドされている必要があります。そのためには、ビルドディレクトリの構成時に CMake へオプションを渡します:

cmake -DCMAKE_CXX_FLAGS_INIT=-DQT_QML_DEBUG <source-dir>

この方法であれば、実際にプレビューを行うビルド構成にのみ QML デバッグ機能を有効化できます。通常はこちらの方法が望ましいでしょう。一方で、開発用ビルドに常時組み込みたい場合は、CMakeLists.txt に以下のような設定を追加することもできます:

target_compile_definitions(myapp PRIVATE QT_QML_DEBUG)

ただし、どちらの方法を採る場合でも注意が必要です。QML デバッグ機能を有効化すると、デバッグ用ポートが開かれます。アプリケーション起動時には、そのことが明示的に表示されます:

QML debugging is enabled. Only use this in a safe environment.

表示される警告は、そのまま受け取るべきです。この状態のアプリケーションを製品として出荷してはいけません。

その後は、ツールを手動で起動できます:

qmlpreview ./myapp

ただし、この方法は必ずしも良い考えとは言えません。なぜなら、この状態ではアプリケーションから見える QML ファイルはリソースファイルシステム内のものだけになり、qmlpreview もそれらのファイルを監視することになるからです。しかし、実行中のアプリケーションにおいてリソースファイルシステムの内容を変更するのは事実上不可能です。そのため、変更を検知しても更新は一切行われません。(もっとも、QML をリソースファイルシステムではなくホストのファイルシステムから直接読み込んでいるのであれば別ですが、そのような使い方は推奨されません。)この問題に対応するために、qmlpreview には --resource という特別なオプションが用意されています。このオプションを使用すると、リソースファイルシステムの生成元となった .qrc ファイルを qmlpreview に渡すことができます。そうすると、qmlpreview はリソースファイルシステム内の QML ファイルとホストファイルシステム上の実際のファイルとの対応関係を把握し、リソース内のファイルではなく、ホストファイルシステム上のファイルを監視できるようになります。CMake を使用している場合、生成された.qrcファイルを自分で探し出す必要はありません。ビルドシステムに任せることができます。Qt 6.12 では、QML モジュールを含む各実行ファイルに対して、追加のビルドターゲットが自動的に生成されます:

ninja myapp_qmlpreview

qmlpreview_<実行ファイル名> ターゲットをビルドしても、通常の意味で何かがビルドされるわけではありません。その代わりに、アプリケーションが必要とする引数を付けて qmlpreviewを起動します。実際には、その役割の大部分は、QML モジュール用に生成された各.qrcファイルに対して --resourceオプションを渡すことです。

ここで私は「QML モジュール」と書きましたが、その意味は重要です。この仕組みが機能するのは、CMakeLists.txtの中で実際にqt_add_qml_moduleを使用している場合に限られます。QML Preview が理解できない独自の方法や特殊な設定で QML ファイルをパッケージングしている場合、この機能は利用できません。詳細については、以下のドキュメントを参照してください。

https://doc-snapshots.qt.io/qt6-dev/qt-add-qml-preview.html#description

Hot Reload 自体はデフォルトで有効になっています。そのため、ファイルを編集して保存すると、実行中のアプリケーションへ変更内容が反映されます。もし Hot Reload を無効にしたい場合は、環境変数を次のように設定してください。QMLPREVIEW_HOTRELOAD=0

それでは実際の使い方はここまでとして、次は少し内部実装を覗いてみましょう。Hot Reload が実際にはどのような仕組みで動作しているのかを見ていきます。

ファイル保存時に何が起こるのか

変更通知を受け取ると、デバッグサービスは変更されたドキュメントを再コンパイルし、その結果を現在アプリケーションで実行中の内容と比較(diff)します。そして、その差分に基づいてどのような処理を行うかを決定します。差分の種類によって、実行される処理は次の 3 パターンに分かれます:

差分が小さい場合: その場でパッチ適用(Patch in place)

これは最も理想的なケースです。この場合、何も破棄されません。QObjectは削除されない、メタオブジェクトも再構築されない、代わりに、実行中の JavaScript 式が再コンパイル後の新しい式へ差し替えられ、再評価されます。処理はそれだけです。差分が「小さい(trivial)」と見なされるのは、既存のバインディングや既存の関数本体のみが変更された場合です。これは UI を調整する際によく行う編集の大部分をカバーします。具体的には次のような変更です:

  • リテラル値の変更: 色、サイズ、マージン、文字列、true や falseなどの値を変更する。

  • バインディング式の変更: あるスクリプト式を別のスクリプト式へ変更する。

  • JavaScript 関数やシグナルハンドラの本体変更: 関数の実装内容を書き換える。

  • フォーマット変更: インデント調整、コメント追加、空白の変更など。ソースコード上の位置情報だけが変わり、実行時の意味が変化しない編集は、アプリケーションの動作には一切影響を与えず、処理コストも発生しません。

以下のようなコードがあると仮定してみましょう:

import QtQuick

Rectangle {
    id: root
    property int ponies: 2

    width: 400; height: 300
    color: "pink"

    Text {
        anchors.centerIn: parent
        text: root.ponies + " ponies"
        font.pixelSize: 20
    }

    MouseArea {
        anchors.fill: parent
        onClicked: root.ponies *= 2
    }
}

何回かクリックしてから、色やフォントサイズ、あるいは onClickedハンドラの本体を変更してみてください。その後でもう一度クリックしてみると、ポニーは引き続き増え続けます(もちろん、あなたが別の動作をするように変更していなければですが)。数値は初期値である 2 に戻りません。

フォントサイズを変更しても、ポニーは増え続けます。コメントを変更しても、プレビューには何の影響もありません。

差分が構造的な場合: コンポーネントを再構築

「構造的(structural)」とは、オブジェクト、プロパティ、シグナル、バインディングを追加または削除する場合を意味します(あるいは、保護メガネが必要になりそうなその他の興味深い変更も含みます)。こうした変更は、単に値を差し替えるだけでは対応できません。オブジェクトの構造自体が変わってしまうからです。そのような場合には、コンポーネント全体を再構築します。コンポーネントのルートオブジェクトは再利用され、その内容だけが再構築されます。つまり、一般的なウィンドウであれば、そのアイデンティティやジオメトリは維持されます。しかし、その配下で QML によって生成されたオブジェクトは新しく作り直されます。

それでも、コンポーネント内のすべてを破棄するわけではありません。再構築の前に、プレビュー機能は更新対象のドキュメント自身が生成したものではない状態を退避しておきます。例えば、C++ 側または別の QML ドキュメントから上書きされたプロパティ値、外部から設定されたバインディング、外部から接続されたシグナルハンドラ、などです。これらを見つけるために、グループ化されたプロパティ、アタッチドオブジェクト、子オブジェクトまでたどって調査し、再構築後に復元します。その結果、再構築されたドキュメントの外側から書き込まれた状態は維持され、ドキュメント自身が生成した状態だけが再生成されます。

コンポーネントの構造が変更されると、その内部(例えば crate ボックス)は再生成されます。ルートオブジェクトは保持されます。プログラムによって変更された状態(crate の数)は復元されます。入力イベントの再生は行われません。

どうしてもその場で再構築できないコンポーネントも存在します。例えば、コンポーネントのルート要素の C++ ベース型が変更された場合です。その場合、再利用しようとしているオブジェクトは依然として古いクラスのインスタンスであり、内容を再設定したところで正しいクラスのインスタンスにはなりません。また、遅延バインディング(deferred bindings)を持つ場合も同様です。例えば Controlの background や contentItem がそれに該当します。このようなバインディングは再インストールできません。遅延バインディングの処理は、その型自身が管理する仕組みであり、デバッグサービスからその内部を参照することはできません。このようなケースでは、コンテキスト階層を上方向にたどり、それを内包しているコンポーネント全体を再構築します。そうすることで、問題となるオブジェクトは最初から新しく生成され、正しいクラスのインスタンスとして作成されます。また、遅延バインディングも適切な形で処理されます。

以下は、そのような「扱いが難しいオブジェクトMyButton.qml」の例です:

import QtQuick.Controls

Button {
    background: Rectangle {
        radius: 4
        color: parent.down ? "#c0392b" : "#e74c3c"
    }
}

そして Main.qml がこれを使用します:

import QtQuick

Item {
    MyButton {
        text: "Launch"
        anchors.centerIn: parent
    }
}

今度は MyButton.qml にプロパティや別の要素を追加してみましょう。これは構造的な変更なので、MyButton.qml のコンポーネントを再構築する必要があります。しかし、そのルートオブジェクトは Button であり、background は Button が持つ遅延プロパティ(deferred property)の一つです。そこで見えている Rectangle は、他のオブジェクトと一緒に生成されるわけではありません。Button はそのバインディングをいったん保持しておき、自身の初期化が完了したときに自分で実行します。これにより、スタイルが本来持つ背景オブジェクトを生成せずに済みます。私たちはその処理を外部から再現することができません。そのため、Button 自体を再構築するのではなく、それを生成したコンポーネントを再構築します。つまり、Main.qml のルートItem を再構築します。この場合、Item は再利用されて再初期化されます。その内部にある MyButton は最初から新しく生成されます。そして今度は Button が通常どおり自分自身の background を処理します。

ベース型が変更された場合も同じ考え方になります。例えば、MyButton.qml のルート要素を Buttonから Rectangleに変更したとします。すると Main.qml 内に既に存在しているオブジェクトは依然として QQuickButtonのインスタンスです。このオブジェクトを QQuickRectangleに変えることはできません。そのため、この場合も それを囲んでいるコンポーネントである Item全体を再構築します。

どちらの場合にも代償があります。再構築の範囲が、実際に編集した範囲より広くなってしまうのです。その結果、Main.qmlのルートコンポーネント内に存在する他のオブジェクトも、変更していないにもかかわらず再生成されます。

差分を適用できない場合: アプリケーションの再起動

コンテキスト階層を上方向にたどる方法が失敗するのは、たどれるコンテキストがなくなった場合だけです。これは通常、最も外側のドキュメントのルート要素そのものの C++ ベース型を変更したことを意味します。例えば、ルートの Item をルートの Window に変更したような場合です。この場合、デバッグサービスは適用に失敗したことを報告します。そしてクライアント側は、アプリケーションを再起動し、記録しておいた入力イベントを再生することで、UI を変更前の状態にできるだけ近いところまで戻そうとします。qmlpreview を使用している場合は、その動作を実際に確認できます。

Error: Hot reload failure: Could not apply diff

Qt Creator は適切な処理を自動的に行います。少なくとも、イベント再生というものが目立たずに実行できる範囲においては、それを静かに行います。

ウィンドウ自身のベース型を変更してみてください。アプリケーションが再起動され、その後に入力イベントが再生される様子を確認してください。

どちらの場合でも、現在のセッションは失われます。しかし、運が良ければ入力イベントの再生によって、UI を元の状態にかなり近いところまで戻すことができます。

Interactive mode と記録済みセッション

--interactiveオプションを指定して起動すると(CMake が生成するターゲットでは既に指定されています)、Qt 6.12 以降では対話用プロンプトが表示されます。これは、以前から qmlprofiler に搭載されているものをモデルにした仕組みです:

Connected. Type a command ('help' shows the list).
>

コマンドは以下のとおりです:

Command Alias Effect
help h 利用可能なコマンドの一覧を表示します。
output [file] o 記録された入力イベントストリームを.qtdファイルに書き出します。
load [file] l .qtd ファイルを読み込み、再生します。
replay   これまでに記録されたイベントを実行中のターゲットアプリケーションへ再生します。
clear c これまでに記録されたイベントを破棄します。
restart r ターゲットアプリケーションを再起動し、イベントを再生します。
kill k ターゲットアプリケーションを終了します。
quit q 設定されている場合は--outputで指定されたファイルへ保存してから終了します。

qmlprofilerとは異なり、こちらではターゲットアプリケーションを終了したり再起動したりできます。プレビューが何らかの変更に対応できなかった場合は、restartコマンドを使うことで、アプリケーションをクリーンな状態で再起動し、記録されていた操作を再生できます。その結果、変更内容をもう一度試すために、5 画面分の操作を最初からやり直す必要がありません(もちろん Pong をプレイしている場合は別ですが)。

また、セッションはプロセスの終了とともに失われる必要はありません。記録されたイベントは、QML Profiler が以前から使用している.qtd形式で保存できます:

qmlpreview --output session.qtd ./myapp
qmlpreview --replay session.qtd ./myapp

--output を指定すると、終了時に記録されたイベントストリームを書き出します。一方、--replay を指定すると、起動時にそのイベントストリームを読み込み、新しく起動したアプリケーションに対して再生します。記録されたセッションはファイルとして保存されるため、バグレポートに添付したり、テストケースと一緒に保管したりすることもできます。

Hot Reload が成功した場合、記録されたイベントは意図的に再生されません。イベントを再生してしまうと、ユーザーが以前行ったクリック操作がもう一度実行されることになり、Hot Reload の目的に反してしまうからです。イベントの再生が行われるのは、実際にアプリケーションの再起動が発生した場合のみです。

うまく動作しないケース

これはこれらの機能の最初のリリースであり、まだ完成させたかった部分がかなり残っています。

バインディングの種類を変更すると、コンポーネントの再構築が発生します。例えば、リテラル値をスクリプトバインディングに変更したり、そのどちらかを翻訳文字列に変更したりする場合です。このような変更は単なる値の変更ではなく、生きたバインディングを追加または削除することを意味します。しかし、現時点ではそれをその場で適用することはできません。同様に、あるプロパティに設定されていたバインディングを別のプロパティへ移動することもできません。これらの場合はすべて、コンポーネントのルートを再構築する方式にフォールバックします。一般に、その場でパッチを当てる場合と比べると、再構築はエラーが発生しやすくなります。対象オブジェクトに対する変更済みの状態は可能な限り維持するよう努めていますが、それにも限界があります。例えば、実行中に追加の内部オブジェクトを動的に生成していた場合、それらは外側のオブジェクトが元のコンポーネントの宣言的な QML コードから再構築される際に失われます。何かおかしいと感じた場合は、いつでも qmlpreviewコンソールから restartを実行できます。

オブジェクトの C++ ベース型を変更した場合は、その場でパッチを適用することはできません。この場合は必ず何らかの再構築が必要になります。ほとんどの場合、再構築されるのはそのオブジェクトを含むコンポーネントです。その結果として気付くかもしれないのは、その内部にあるオブジェクトが新しいものになっていることです。理想的には、変更されていない内部オブジェクトは保持し、それらを再構築後のオブジェクトへ注入できるとよいのですが、その方法は試された結果、極めて複雑で壊れやすいことが分かりました。

Hot Reload なし の場合、起動後に最初に行われるのは、デバッグサービスがアプリケーションのシーンを非表示にし、自身が完全に管理できる複製シーンを作成することです。この方式では、別のドキュメントを読み込む、シーンを明示的に再生成する、といったことが可能です。また、デバッグサービスとクライアントの間で使用されるプロトコルには、そのためのコマンドも存在します。

一方、Hot Reload あり の場合は状況が異なります。アプリケーション自身が生成したシーンが、そのまま更新対象になります。そのため、プレビューに対して無関係なドキュメントを読み込ませたり、現在のシーンを破棄して最初から再生成させたりすることは、あまり意味を持たなくなります。そのため、サービスはそのどちらも拒否します。

qmlpreviewツールはそもそもそのような要求を行わないため、通常は問題になることはありません。しかし、そのような要求を送るプレビュークライアントは正しく動作しません。Qt Creator には、実行中の QML Preview に対して特定のドキュメントを読み込ませるための UI が存在します。あなたは今、その機能が実際に何をしているのか理解した最初の人です。そして、おそらく私がここで「foot gun」という言葉を書くのを待っていたことでしょう。

最も重要な問題は次のものです: 複数スレッド上に QML エンジンが存在する場合、QML Preview は安全ではありません。その場でパッチを適用する処理では、複数のエンジンから参照される可能性のあるコンパイルユニットを操作します。しかし、その中に含まれる型参照(type references)はデータ競合に対して保護されていません。

すべての QML エンジンが同じスレッド上で動作している場合は問題なく動作します。あるいは、更新中に他の処理が型参照へアクセスしないことを保証できる場合も問題ありません。現時点ではこの制限を受け入れています。概念的には型参照は不変であるべきものであり、QML Preview のためだけに必要なロック処理をすべてのユースケースへ課すことを避けたかったからです。

もしこれらの問題によって作業が妨げられる場合は、ぜひバグレポートを作成してください。パッチ適用ロジックは編集内容の形状に非常に強く依存しています。そのため、問題が発生する前後の QML ファイルのペアは、説明文よりもはるかに価値があります。さらに、それに加えて.qtdの記録ファイルが添付されていれば、なお有用です。

また、問題が Hot Reload に起因するものか確認したい場合は、プレビュー対象アプリケーションの環境変数にQMLPREVIEW_HOTRELOAD=0 を設定してください。そうすると、比較用として Qt 6.11 と同じ動作に戻すことができます。

今後の予定

現時点では、実際にはその場でのパッチ適用で対応できるにもかかわらず、コンポーネントの再構築を引き起こしてしまう編集がまだ数多く存在します。例えば、プロパティの追加・削除、関数の追加・削除、バインディングの追加・削除、などは、本質的にはコンポーネント全体の再構築を必要としません。しかし、これらを適切に処理するためには、まずそのような変更によって生成される差分量を削減し、そのうえで QML が生成するメタオブジェクトが構造(shape)の変化を許容できるようにするための基盤整備が必要です。その方向に向けた作業は、すでに一部進められています。

また、現在は VS Code との統合 にも取り組んでいます。さらに、AI コーディングエージェント自身がプレビューループを操作できる AI スキル の開発も進めています。

コメント

ブログを購読

Qt 6.12 を
今すぐ試そう!

最新リリースはこちらからダウンロードできます。 www.qt.io/download

Qt 6.12 LTS がリリースされました!アプリケーション開発者やデバイス開発者向けに、多くの新機能と改善が追加されています。 

採用情報 

現在、さまざまなポジションで採用を行っています。募集職種はこちら をご覧ください。また、Instagram をフォローして #QtPeople の働き方もぜひチェックしてください。