連休中は先に公開したPLLの話のほか、Qtによるプログラミングについて調べていました。Qtに関しては15年ほど前に少し本を読んだのを初めとして、その数年後にもいじってみたことがありますが、いずれも匙を投げています。
今回はそこそこ動くところまでいじりました。
これまで匙を投げていたのは、あまりにプログラミングが難しそうだと考えたからです。もともとMacAppにあこがれていたところからGUIに入り、TurboVisionでプログラムを組み、NextStepの講習会に参加し、自分で買ったDelphiで遊んでいたというのが私の経歴です。あまりに早い時期に非常によいGUIフレームワークに触ったため、
(生産性の低いフレームワークで時間を無駄にしたくない)
という気持ちがつよくて.Netframework以外は忌避していました。Qtも何度か触りましたが、独特の改造文法やGUIの設計ツールが未熟に思えた(雑な主観)こともあってあまり真面目に取り組まなかったのでした。
さて、今回改めて調べてみたところ、かなり完成度が高いように思えたので思い切って自分でプログラムを組んでみました。
最近のクロス・プラットフォーム開発
いまやクロス・プラットフォームの開発環境も星の数ほどありますが、私が抱いているのは以下のような感想です。
- Microsoftのクロス開発環境:思い出したようにすごい技術が話題になるがそのたびに違うものに変化している、あるいは肥大化しているように思えて遠い世界のことに感じる。実時間実行に不安を感じる。
- Java:実時間実行に不安を感じる。
- Electron のようなブラウザ実行型:GUIのビルダー例がどれも素っ頓狂におしゃれすぎて腰が引ける。C++をバインドして実時間実行できるが、木に竹を接いだ状態でどうやってクロスプラットフォームに配布するのか。
- Python:ターゲットのプラットフォームで実行環境を作るのが面倒。GUIに関しては情報が少なそう。実時間実行は無理では。
- MATLAB / Simulink :最近使いだした。C言語のコード生成やGUI開発もパッケージングもできる。Windows / Linux / MacOSで動作するコードを生成できるらしい。Audio ToolBoxを使うとリアルタイムで音声入出力できる。ただし、無限にツールボックスを買い続けなければんらないような恐怖を感じる。
さてQtですが、独自のIDEをもったフレームワークであり、ターゲット言語は原則としてC++です。また、GUIに限らずマルチスレッド、ファイル・システムやオーディオ、通信といった機能へのラッパーも持っており、包括的なクロス・プラットフォームのアプリケーション開発環境となっています。
ライセンスに関してはかなり複雑に感じますが、オープンソース用の開発パッケージがフリーでダウンロード可能であり、それを使う限りライセンスについてはそれほど心配しなくてよさそうです(私はソースコードをMITライセンスで後悔することを前提に調査しています)。
オーディオ領域の実時間信号処理を行うちょっとしたツールの作成であれば、Qtが最も敷居が低そうです。
GUI周りの構造と設計方法
少し視点を高くする話になりますが、私が知っているGUI開発フレームワークはどれも古典的なMVCモデルに即した構造になっています。
つまり、ユーザーは画面を通してデータのグラフィカルな表現(ビュー)を見ており、これらを画面上のボタンやスライドバー(コントロール)を使って操作します。
実際にはユーザーは画面上のデータを操作しているわけではなく、ビューやコントロールの後ろにあるモデルが、ビュー及びコントロールとデータをやり取りしながらユーザーとの対話を行います。
つまり、GUIアプリケーションにおける作業とはユーザーとコンピュータ内部のモデルの対話であり、この対話はビューとコントロールを通して行われます。
ビューやコントロールの設計は、専用のGUIビルダーを通して設計する方法が便利です。古典的にはApollo Dialogが採用したテキストファイル上の宣言的なパーツ配置や、TurboVisionのような座標のハードコードも存在しましたが。しかしながら、30年以上前にNeXTのInterface BuilderがGUIによるインターフェース設計に先鞭をつけ、四半世紀前にDelphiがVCLを普及させています。今更もっとめんどくさい方法をとる気にもなりません。
さて、設計ツールの使い勝手はもちろん重要ですが、ビュー、コントロールとモデルの間のやりとりも大変重要です。
コントロールはモデルに対してユーザーによる操作の情報を与えなければなりません。これは何らかのイベントの形になるかもしれませんし、コールバックの形になるかもしれません。変数への書き込みかもしれません。
いずれにせよ、コントロールはモデルの機能を使うわけですが、GUI開発の段階においてはモデル自体も開発中だということが大きな問題になります。つまり、まだリンクもコンパイルもされていないモデルとコントロールに対して、コントロールがモデルにどうアクセスするかをツールが対話的に組み立てていく必要があります。
同様に、まだリンクされていないモデルとビューの間で、モデルがビューに対してどのようにアクセスするかを開発ツールは対話的に組み立てていかなければなりません。
これはコンパイル言語にとって大変な問題です。Delphiではオブジェクト型にプロパティという新しい言語要素を持ち込み、モデルとビュー及びコントロールのやり取りをプロパティに制限することでコードをビルドせずに(おそらくは簡単なパーシングだけ行って)対話的な両者の編集を可能にしました。
多分インタープリター型言語の場合は敷居が低くなるのではないかと想像しますが、いずれにせよ対話型GUI設計ツールの開発はここがポイントのようです。
そういうわけで、GUIアプリケーションの開発に使うツールは
- 対話型GUI開発ツールはあるか
- モデルとビュー及びコントロールの間の通信はどうなっているか
がポイントになります。
Qtの場合
さて、大雑把に触っただけですが、Qtに関してはおおむね状況をつかめました。注意すべき点としてQtにはUIの開発モデルが二つあります。
一つは古典的なQtの手法であり、Signal / SlotというC++の言語拡張機能をつかってモデルとビュー・コントロールの間のやり取りを行うものです。
Qtの開発ツールであるQt Creatorはビューやコントロールの配置をGUI上で行うことができるだけではなく、モデルとビュー&コントロールのSignalをそれぞれのSlotにGUI上に接続することができます。
もう一つの方法は比較的新しく、QML( Qt Modeling Language)によって記述されたファイルを挟んでモデルがビュー&コントロールと通信するものです。この場合の通信はやはりC++言語を拡張したプロパティを使います。
QMLは宣言型だと解説されていますが、JavaScriptをベースにした式や実行文を含むことができます。
一見、QMLを間に挟むことは冗長に感じます。しかしながらQMLを挟むことでモデルとビュー&コントロールのやりとりの抽象度を上げることができます。
例えば、「何らかのチェックボックスに呼応して隣接するGUI要素がグレーアウトする」UIはよく見かけるものです。”Use DMA”をチェックするとDMAのパラメータ入力が可能になる、などです。その場合グレーアウトの制御を誰がするのかを考えてみましょう。
Qtの古いやり方ではグレーアウトはモデルが行います。ですので、チェックボックスが操作されるたびにコントロールからモデルのスロットにシグナルが飛び、モデル内部の状態に応じて新しい状態に遷移し、それに応じてモデルがシグナルを投げてビューの状況を変える、といった操作をすべてモデル主体で行うことが必要です。
一方、QMLを使うと以上のようなグレーアウト制御のための状態遷移をすべてQMLの内部で行うことができます。ですので、モデルにはユーザーとの対話が終わった結果だけを渡せば済みます。むろん、逐一結果をモデルに知らせてモデルにビューを変化させることもできます。要するに柔軟性があります。
QMLを使ったやり方が本当に良いのかどうかは、ちょっと触っただけなので正直判断がつきません。確かにC++のモデルで全部制御するのは筋が悪そうに思えますが、一方でC++以外のところにステート・マシンがあってソース・コードから見えないというのはリスキーにも思えます。いずれにせよ、Qt開発チームはQMLによるワークフローを今でも改善しているうえにドキュメントも豊富ですので、こちらを使う方が将来性がありそうです。
まとめ
ということで、この週末ざっといじってみたQtについてざっとまとめてみました。
ほかにやることがたくさんあるので、Qtについては少しずつ勉強していこうと思っています。