GUI開発に関する世界観です。
Linuxでは、Linuxカーネルと少数のCUIプログラムによるベースシステムには、グラフィックスを表示する機構は存在せず、キャラクタベースの入出力による、コマンドライン操作のインターフェースしか用意されていない。
こうしたCUIのインターフェースでは、コマンド入力を読み取って、標準入出力やファイルシステムに対して、コマンドプログラムを実行して操作することしかできない。
だが、今のパソコンの全盛時代、こうしたCUIの操作端末だけを使う人は少ない。GUIのアプリケーションをマウスやキーボードを使って操作し、ビットマップをモニターに表示しながら、アイコンやメニューをダブルクリックして、ボタンクリックやダイレクトなテキスト入力によってアプリケーションを操作したい。
Linuxでは、こうしたグラフィックス操作を実現するために、X11あるいはwaylandと呼ばれるソフトウェアを使う。X11とはウィンドウシステムと呼ばれるソフトウェアで、UNIXでは伝統的にX11を使うことで、マウスやキーボードを使ってポインタを上下左右に動かし、グラフィックスをモニターに表示する「Xサーバー」と、そのXサーバーでユーザーが行ったイベントをメッセージとしてクライアントに伝える「Xクライアント」すなわち「GUIアプリケーション」の操作環境を実現する。
XサーバーとXクライアントはネットワーク上で接続されており、Xプロトコルと呼ばれる通信規格で通信を行うが、Xプロトコルの詳細を知らなくてもXクライアントがXサーバーとやり取りできるように、Xlibと呼ばれるライブラリが用意されている。
Xlibだけを使っても低レベルなグラフィックス処理はできるのだが、Xlibにはひとつ問題がある。Xlibには、WindowsやMacでのGUIアプリエーションに用意されているような、ボタン、メニュー、リストビュー、ツリービューなどの「便利なウィジェット」が用意されていない。Xlibによるインターフェースは下層レイヤーでは必ず必要だが、Xlibよりも上位のレイヤーとして、Motif、GTKあるいはQtといった「ウィジェットツールキット」と呼ばれるライブラリがXには多くの場合存在する。こうしたツールキットを使うことで、フォームにボタンやメニューあるいはテキストボックスやラベルを簡単に張り付けたり、ボタンがクリックされたりメニューがクリックされた場合に応じて実行されるコードを別々の場所に記述する「イベント駆動のプログラミング」を行うことができる。
また、GTKを使う場合は、Gladeというアプリケーションを使うことで、フォームデザイナーで画面を見ながらウィジェットを配置し、その結果をXMLで吐き出してlibgladeライブラリを用いて読み込むことができる。また、GTKにはたくさんの言語バインディングがあり、標準のC以外にC++やPythonやRubyやmonoなどさまざまな言語で開発ができる。Qtでは、QtDesignerやPyQt/QtRubyなどが同様に存在する。
デスクトップ環境のGNOMEではGTK、KDEではQtが使われている。そのため、GNOME向けのアプリケーションを書くのであればGTK、KDE向けのアプリケーションを書くのであればQtを利用することで、システムと見栄えや操作感(ルック&フィール)を統一させたアプリケーションを作ることができる。GTKアプリケーションはGNOMEと調和し、QtアプリケーションはKDEと調和する。GTKやQtにはテーマエンジンも搭載されており、テーマを変更することで全てのアプリケーションの見た目を一括で変えられる。(アプリケーションのデザイン自由度が下がるというデメリットもある。また、テーマエンジンを介する分、表示も重くなる。)
また、ツールキットだけではなく、デスクトップアプリケーションを書くのであれば、設定・コンフィグのためのデータベースや、仮想ファイルシステムなどのインターフェースも必要となる。GNOMEでは、こうしたGTK以外の必要なコンポーネントライブラリも開発・提供しており、GNOMEアプリケーションを書くのであればそうした仕様に則ることが望ましい。また、KDEでもKDEフレームワークと呼ばれるフレームワークを開発しており、さまざまなデスクトップアプリケーションのためのAPIを提供している。これにはHTMLレンダリングエンジン(KHTML)のようなとても高度なものも含まれる。
これに対して、Windowsではカーネルにグラフィック・ウィンドウ表示機構が統合されている。低レベルなWindows APIを使うことでも、メッセージループによるウィンドウメッセージを中心としたGUIアプリケーションの開発ができる。また、MFC、ATL/COM、GDI、DirectXのようなC/C++向けのフレームワークを使うことで、Windowsネイティブなアプリケーションを開発できる。
また、Windowsでは近年.NET Frameworkと呼ばれるJava VMと良く似た機構が搭載されており、.NET Framework向けの言語であるC#やVisual Basicを用いて、グラフィカルな「フォームデザイナー」を用いた開発が可能である。
Windowsでは、COMと呼ばれる分散コンポーネント技術が存在し、これを使うことで、アプリケーションの中に別のアプリケーションのビューやコンポーネントを埋め込んで再利用したり、分散コンポーネントとしてそれぞれのアプリケーションを配置し、ネットワークを通じてインターフェースから操作することができる。
これはとても先進的な仕組みだったため、GNOMEはこのCOMに影響されて開発が始まった。GNOME 2ではCORBA、GNOME 3ではD-Busを用いたネットワーク・オブジェクト・モデルを採用しており、Bonoboを用いることでアプリケーションの中にさまざまなコンポーネントを搭載することができる。そのため、表計算機能もPDF表示機能も簡単にGUIアプリケーションの中に組み込むことができる。KDEではKPartsと呼ばれる同様の機構がある。
その他のGUIプラットフォームとしては、JavaのSwingやMozillaのXULなどがある。
WindowsやGTKで使われる主なウィジェットについては、Visual BasicやGTKを参照のこと。
GUIアプリケーションは、現代的なOSの場合、低水準な「メッセージループ」と、GUIフレームワークを用いた「イベント駆動」や「コンポーネントの継承」によって行います。
IDE(統合開発環境)によるGUIフレームワークでの開発は、以下のようになります。
開発手順 | 説明 |
---|---|
フォームデザイナーによる配置 | フォームデザイナーにより、 フォームにGUIコンポーネントを配置する。 |
イベント駆動のコードを書く | コードエディタにより、あるイベントでどのメソッドが実行されるか、 という「イベントに応じた処理」をイベント駆動で記述する。 |
コンポーネントの継承 | テキストエディタならテキストボックス、 WebブラウザならWebKitコンポーネントなど、 コンポーネントを継承して独自のコンポーネントを拡張する。 |
オーバーライド | コンポーネントのメソッドをオーバーライドし、 「あるイベントが実行される際のメソッドの処理」を上書き・追加する。 |
こうしたGUIアプリケーションで必要となるのが、自分の使うプラットフォームで使用されるGUIフレームワークの仕様の知識です。特に、OSや言語・ライブラリだけではなく、MFC, Windows.Forms, GTK, QtなどのGUIフレームワークについての知識に習熟する必要があります。
また、こうしたGUIアプリケーションを作る際に、巨大な会社のプロジェクトであれば、「自分でコンポーネントフレームワークを作る」といった方法がとられることもあります。Adobeのような巨大企業なら、そうする必要があるでしょう。そのためには、Windows APIやXlibなどの低水準のAPIを用います。
色んなやり方や色んなプログラムがあるため、一概に「このように開発しろ」とは言わないが、アプリケーションの設計と実装の手順の一例として、以下が参考になるかもしれない。
まず、どのような処理が必要になるか、明確化する。
・データ(あるいはデータ属性)をどのように保管し、参照し、読み書きするのか?ビューの表示機能にどのようにデータを与えるのか?そのためにどのように変換・保持するのか?
・ビューをどのように表示し、レイアウトや再描画をどのようにするのか?ユーザーは表示されたアートワークをどのように(マウスやボタンによって)操作するのか?
・ユーザーが操作するインターフェース(UI)は、どのようなものにし、どのように表示・参照・変更・適用するのか?どのようなフォームやパネルやダイアログを表示するのか?
・プログラム自体の設定は、どのように保持・参照・変更・適用するのか?プログラムの処理の中でどのように設定を適用するのか?
・プログラムの主要な機能は何か?
・プログラムの主要な機能をどのように実現し、実装するのか?
・機能の呼び出しインターフェース(API)は、どのような規約(ルール)に基づいて構築するのか?
・APIに基づいて、機能をどのように分割・相互参照・モジュール化するのか?
・プログラムの開発のベースとして、どのような技術を採用するのか?(コンソール、Windows、Web、フレームワークなど)
・どのようなプログラムにしたいのか?(多機能、軽量、簡単、プロ仕様など)
また、こうして出てきた「漠然とした全体像」を、明確に、それ以上細分化できないところまで細分化し、決まっていないことが何もないぐらい明確化する。
そして、明確化した内容を、実際のプログラムにするために、「クラス」と呼ばれる単位に分割し、クラスとクラスの関係性を記述する「クラス図」と処理の流れを記述する「シーケンス図」を描く。
最後に、これらに基づいてコードを書く。ここで、初めて、プログラミング言語の知識の内容を活かすことができる。
後日注記:実際のところ、上記はMFCのドキュメント・ビューのような場合に限られる。もっとより一般的には、「処理の流れをどうするか」「内部的な設定情報をどのように保持するか」「ライブラリや再利用可能なコンポーネントをどのように利用・構築するか」などといった具合になる。
GUI開発というと、コマンドラインよりも難しくて、高度で複雑なフレームワークの知識が必要であるかのように思うかもしれません。
ですが、実際のところ、DelphiやC#のようなGUIに適したプログラミング言語を選んでしまえば、ほとんど「コントロールの操作」ができれば、作れてしまいます。
たとえば、テキストエディタに検索・置換機能をつけるなら、エディタコントロールの入力テキストをバッファを格納する文字列型の変数にコピーし、そのバッファ文字列に検索・置換をかけて、元のコントロールに戻すだけで作ることができます。
他にも、Shift+Spaceを押したら、さまざまな顔文字やアスキーアートの一覧を出すように、小さなリストビューウィンドウを表示して、そこからEnterを押せば顔文字を挿入できる、といった「2ちゃんねるに必須の機能」は、DelphiやC#なら簡単に作れます。
ネットワークからHTMLデータをダウンロードし、正規表現で整形して表示する、などといったことも、IEコンポーネントなどを使えば、そんなに難しくはありません。独自のテキストビューに表示したいなら、独自コンポーネントを作る必要があり、少し難易度は上がりますが、そこまで困難ではありません。HTMLを整形してツリービューにひとつひとつのアイテムを格納するためには、ある一定の「テンプレート」や「記述規則」があれば、DelphiやC#で簡単に作れます。
ここまで言って気付かれた方も居るかもしれませんが、これらは全て2ちゃんねる専用ブラウザの機能です。僕は昔そうした専用ブラウザを研究・開発していたことがあります。理由は2ちゃんねるが好きだったからです。ですが、その時はDelphiやC#などの知識がなく、バグだらけになってしまいました。それでも、単純なHTML整形機能やメモ帳からのShift+Enterによる投稿機能などはそんなに困難でなく作れました。
僕が思うに、Windowsプログラミングの問題とは、「自分で何も作っていなくて、結局OSを作らなければ意味がない」ということです。
C#やVBなどで、コントロールを操作するプログラムを開発することは簡単です。APIさえ分かってしまえば、プロパティとイベントとメソッドを最低限書くだけで、どんなフォームやダイアログでも表示できますし、その中のさまざまな要素を変更したり、追加したりすることはとても簡単です。
仕事でプログラムを開発するのであれば、この「簡単にウィンドウプログラミングができる」という利点は優れています。特に.NETでは豊富で使いやすい整理されたクラスライブラリがあるため、イベント駆動とライブラリだけで、簡単に何でもできます。
ですが、ここにある問題はひとつです。「自分で何も作っていないから、何もしていないだけ」ということです。
確かに、既にあるクラスを継承した独自のコンポーネントクラスを作ったり、デバイスコンテキストを操作してグラフィックスをGDIなどで描くためには、たくさんのコードが必要であり、必ずしも自分では何もしない、というわけではありませんが、C++の機能とWindowsのAPIをいくらか使うだけで、「自分では何もしていなくて、中身の仕組みも一つも分からず、何一つ面白くない」ということになってしまうのです。
これは、僕が今でもオープンソースのUNIX系のOSが愛される理由ではないかと思います。プログラミングを行う上で、APIを「使う側」だけではなく、「使われる側」のコードもプログラマは読みたいのです。
そういうわけで、X11やGTKやQtのコードを見たい、という方は多く居ますが、あまりきちんと理解できたという人は見受けられません。それは「そもそもUNIXでGUIなんかありえない」からです。UNIXはコマンドラインで使うのが基本であり、GUIのことは誰も触れず、教えず、使うことはあっても、GTKアプリを開発する機会がほとんどなく、GTKのコードを見たいという人も少ないのです。
最近は.NET Coreという「.NETのコア部分をオープンソース化する試み」もマイクロソフトによって行われていますが、どちらかというと僕はそちらに期待します。マイクロソフトがオープンソースをやるのであれば、僕はマイクロソフトを全力で応援したいです。
リスナとはGUIのイベントに対するコールバック関数のインターフェースのこと。
OnLBClick()とかOnRBClick()のように、イベントに応じたメソッドを定義したインターフェースを用意し、このインターフェースを実装することで、GUIプログラミングにおけるイベントに応じたコールバック関数を実行させる仕組みのこと。
(詳しくはやねうらお氏の「Windowsプロフェッショナルゲームプログラミング」に書かれています。)
後日注記:必ずしもOn*で始まる名前付けをするわけでもなく、JavaのSwingなどでもマウスボタンのプレスなどに対してイベントリスナを登録してGUIプログラミングを行うのが常套手段。.NETやGTKなどでは「シグナルハンドラ」を利用し、あるイベントに対してあるメソッドをコールバック関数として呼び出すようにプロパティ値を設定する。
Java SwingやVisual C++/MFCも参照のこと。
「UI」とよく似た言葉に、「UX」という言葉がある。
UIとは、ユーザーインターフェースのこと。
これに対して、UXとは、ユーザー体験(ユーザーエクスペリエンス)のこと。
UXでは、単に機能ごとにUIを並べるだけではなく、「どのような操作体系を与えたら、ユーザーにとってソフトウェアが使いやすくなるか」ということを考える。
ソフトウェア製品を作る際に、UIだけではなくUXを考えることで、ソフトウェアが使いやすくなり、ユーザーから「ソフトウェアを好きになってもらう」ことができる。
(放送大学「コンピュータとソフトウェア ('18)」を参考に執筆しました。)
2023.04.17
GUI開発で重要なことはいくつかあります。
まず重要なのは、コントロールを内包するコントロールがある、ということです。
たとえば、GUIツールキットのGTKでは、HBoxやVBoxのように、内部にウィジェットコントロールを含んで表示することのできるウィジェットコントロールがあります。
ほかにも、ツールバーなども、内部にボタンのコントロールを内包できます。
そのように、コントロールの中にコントロールを含めることができるということが、まず第一に重要です。
次に重要なのは、イベントとプロパティの設定です。
Delphiなどを使ってGUIプログラミングをした時、その主要な操作対象はコントロールのイベントとプロパティを書き換えることです。
いわば、「GUIプログラミングとはイベントとプロパティの操作である」と言ってもいいでしょう。
GTKなどでは、C言語でそのようなイベントとプロパティを操作する関係上、GLib/GObjectという、C言語のままでオブジェクト指向を可能にする基本ライブラリを使います。
GUIツールキットを何を使ったとしても、それは同じです。GUIプログラミングとはイベントとプロパティとの格闘です。
次に重要なのは、動的なコントロールの生成と破棄です。
最初からウィンドウをひとつしか表示しないアプリケーションは、作るのが楽です。ですが、タブを用いてたくさんのウィンドウをひとつのウィンドウの中で作らなければならないアプリケーションの場合、動的にコントロールを生成したり破棄したりしなければなりません。
そのようなアプリケーションの場合、ビュー画面も、シンプルな画面ではなく、自分が凝りに凝って作った多機能で複雑なビュー画面を使うことが多いでしょう。
そのような時は、タブを作成するたびに、ひとつのビュー画面のコントロールを作成し、ユーザーのイベントに応じて破棄したりできなければなりません。
ほかに重要なのは、ユーザーのイベントに対する反応です。これは単にイベントに応答するプロシージャを作るだけではなく、たとえばユーザーが画面を引き延ばしたり縮めたりした時に、どこのウィンドウが伸びるのか、あるいは常にどこにキーボードのフォーカスが当たるのか、ということを考えないといけません。
僕がDelphiを使って2ちゃんねる専用ブラウザを作っていた時は、専用のユーザーが伸び縮みさせられることのできるセパレータ(境界線)のコントロールを使っていました。そのようなコントロールを使ってGUIフォームをデザインしてもいいでしょう。GUIプログラミングはその多くがデザイン作業です。
最後に、さまざまなダイアログを表示させて、ユーザーがOKボタンを押した時に、その操作結果をプログラムのほうから使うことがあります。OKやキャンセルの結果を返すこともあれば、なんらかの入力データの結果を返すこともあるでしょう。
ほかにもGUIプログラミングはさまざまな要素があります。勉強をするのであれば、Linuxを使うのであればGTK、Windowsを使うのであればDelphiを僕はお勧めします。勉強や研究のためにとてもよい環境だからです。
2024.06.18
各プラットフォームのGUI環境については、Linuxデスクトップ環境・ウィンドウマネージャに一覧があります。
イベント駆動を参照のこと。
Adobe製品のようなGUIアプリケーションは開発するのが難しく見えるが、実際はフォームをデザインしてそのフォームから関数を呼び出せば開発できる。
大事なのはGUIフォームよりもコア機能を提供するためのコアルーチンの設計。