Getting Started on the Commandline/ja
h1. Qt ではじめる GUI プログラミング
Qt の世界へようこそ - Qt はクロスプラットフォームの GUI ツールキットです。この入門ガイドでは簡単なメモ帳プログラムの作成を通して基本的な Qt の知識を説明します。このガイドを読み終わるころには Qt の概要および API ドキュメントを参照しながら開発に必要な情報を集めることができるはずです。
Hello Notepad
最初のサンプルではウィンドウにテキストエリアを作成して表示します。これは GUI を持つもっとも簡単な Qt プログラムと言えます。
これがソースコードです:
<br />#include <QApplication&gt;<br />#include <QTextEdit&gt;
int main(int argv, char *'''args)<br />{<br /> QApplication app(argv, args);
<br /> QTextEdit textEdit;<br /> textEdit.show();
<br /> return app.exec&amp;#40;&#41;;<br />}<br />
それでは1行ずつ見ていきましょう。最初の2行でサンプルプログラムに必要な2つのクラス、 "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html と "QTextEdit":http://doc.qt.nokia.com/4.7/qtextedit.html のヘッダファイルをインクルードしています。すべての Qt のクラスはその名前のヘッダファイルを持っています。
6行目で "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html オブジェクトを作成しています。このオブジェクトはアプリケーション全体のリソースを管理し、 GUI を持つ Qt プログラムを動作させるのに欠くことのできない存在です。Qt はコマンドラインオプションを受け取るため、 <code>argv</code> と <code>args</code> が必要です。
8行目で "QTextEdit":http://doc.qt.nokia.com/4.7/qtextedit.html オブジェクトを作成しています。テキスト入力は GUI の視覚的な構成要素の1つです。Qt では通常これらをウィジェットと呼んでいます。ウィジェットは他にもスクロールバー、ラベル、ラジオボタンなどがあります。ウィジェットは他のウィジェットのコンテナ (入れ物) になることができます。たとえばダイアログやメインウィンドウなどです。
9行目でテキスト入力を画面に表示しています。ウィジェットはコンテナとしても機能しますので (たとえばツールバーやメニュー、ステータスバーなどのウィジェットを持つ "QMainWindow":http://doc.qt.nokia.com/4.7/qmainwindow.html)、ウィジェット単体を独立したウィンドウに表示することが可能です。ウィジェットはデフォルトでは非表示になっています。 "show()":http://doc.qt.nokia.com/4.7/qwidget.html#show 関数を使ってウィジェットを表示してください。
11行目で "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html のイベントループを開始します。 Qt アプリケーションが動いているとき、イベントが生成されてアプリケーションのウィジェットに送られます。具体的にはマウスボタンを押し込んだ、キーの押下などのイベントです。テキスト入力のウィジェットでテキストを入力したとき、ウィジェットはキー入力イベントを受け取り、打ち込まれたテキストを描画することで応答します。
アプリケーションの起動は、コマンドプロンプトを開いて、<code>.cpp</code> ファイルのあるディレクトリに移動した後、次のコマンドを入力してプログラムをビルドしてください。
<br />qmake -project<br />qmake<br />make<br />
その結果、<code>part1</code> ディレクトリに実行ファイルが生成されます (Windows の場合は <code>make</code> のかわりに <code>nmake</code> を使う必要があります。さらに実行ファイルは <code>part1/debug</code> または <code>part1/release</code> に置かれます)。<code>qmake</code> は Qt のビルドツールで、設定ファイルを受け取ります。 <code>qmake</code> は <code>-project</code> オプションを使用するとその設定ファイルを生成してくれます。渡された設定ファイル (拡張子は <code>.pro</code>) からプログラムをビルドするための <code>make</code> ファイルを生成します。独自に <code>.pro</code> ファイルを書く方法については後ほど説明します。
h3. 関連するドキュメント
ウィジェットとウィンドウのジオメトリ: "Window and Dialog Widgets":http://doc.qt.nokia.com/4.7/application-windows.html
* イベントとその処理: "The Event System":http://doc.qt.nokia.com/4.7/eventsandfilters.html
終了ボタンを追加する
実際のアプリケーションでは通常より多くのウィジェットが必要です。そこで "QPushButton":http://doc.qt.nokia.com/4.7/qpushbutton.html をテキスト入力の真下に配置してみましょう。このボタンは押されるとメモ帳プログラムが終了します。
それではソースコードを見ていきます。
<br />#include <QtGui&gt;
int main(int argv, char *'''args)<br />{<br /> QApplication app(argv, args);
<br /> QTextEdit textEdit;<br /> QPushButton quitButton("Quit&quot;);
<br /> QObject::connect(&quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));
<br /> QVBoxLayout layout;<br /> layout.addWidget(&textEdit);<br /> layout.addWidget(&quitButton);
<br /> QWidget window;<br /> window.setLayout(&layout);
<br /> window.show();
<br /> return app.exec&amp;#40;&#41;;<br />}<br />
1行目ではすべての Qt の GUI クラスを含む "QtGui":http://doc.qt.nokia.com/4.7/qtgui.html ヘッダをインクルードしています。
10行目では終了ボタンが押されたときにアプリケーションが終了するように Qt のシグナルとスロットの仕組みを使っています。
スロットは実行時に名前 (通常の文字列) で呼び出される機能です。シグナルは呼び出されたときに登録されたスロットを起動する機能です。これを Qt では、スロットをシグナルにつないで、シグナルを送信する、と言います。
"quit()":http://doc.qt.nokia.com/4.7/qcoreapplication.html#quit はアプリケーションを終了する "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html のスロットです。 "clicked()":http://doc.qt.nokia.com/4.7/qabstractbutton.html#clicked は "QPushButton":http://doc.qt.nokia.com/4.7/qpushbutton.html が押されたときに送信されるシグナルです。静的な "QObject::connect()":http://doc.qt.nokia.com/4.7/qobject.html#connect 関数はスロットをシグナルにつなぎます。2つのマクロ <code>SIGNAL ()</code> と <code>SLOT()</code> はシグナルとスロットの関数シグニチャを受け取ります。そしてシグナルを送信するオブジェクトと受け取るオブジェクトのポインタも渡します。
12行目では "QVBoxLayout":http://doc.qt.nokia.com/4.7/qvboxlayout.html オブジェクトを生成しています。前述の通り、ウィジェットは他のウィジェットを含むことができます。子ウィジェットの位置やサイズを直接指定することもできますが、通常はレイアウトを使うのが簡単です。レイアウトはウィジェットの子要素の位置とサイズを管理します。 例えば "QVBoxLayout":http://doc.qt.nokia.com/4.7/qvboxlayout.html は子要素を縦の列に配置します。
13行目と14行目ではテキスト入力とボタンをそれぞれレイアウトに追加しています。
そして17行目でウィンドウにそのレイアウトを設定しています。
h3. 関連するドキュメント
シグナルとスロット: "Signals & Slots":http://doc.qt.nokia.com/4.7/signalsandslots.html
* レイアウト: "Layout Management":http://doc.qt.nokia.com/4.7/layout.html, "Widgets and Layouts":http://doc.qt.nokia.com/4.7/widgets-and-layouts.html, "Layout Examples":http://doc.qt.nokia.com/4.7/examples-layouts.html
* Qt のウィジェット: "Qt Widget Gallery":http://doc.qt.nokia.com/4.7/gallery.html, "Widget Examples":http://doc.qt.nokia.com/4.7/examples-widgets.html
QWidget の派生クラスを作る
ユーザがアプリケーションを終了するとき、本当に終了したいかどうかを確認するダイアログを表示したいとします。このサンプルでは "QWidget":http://doc.qt.nokia.com/4.7/qwidget.html の派生クラスを定義して終了ボタンにつなぐためのスロットを追加します。
それではソースコードを見ていきます。
<br />class Notepad : public QWidget<br />{<br /> Q_OBJECT
public:<br /> Notepad();
private slots:<br /> void quit();
private:<br /> QTextEdit *textEdit;<br /> QPushButton *quitButton;<br />};<br />
<code>Q_OBJECT</code> マクロはクラス定義の先頭に置く必要があり、このクラスが <code>QObject</code> であることを宣言します ("QObject":http://doc.qt.nokia.com/4.7/qobject.html を継承しているので当然ではありますが)。 "QObject":http://doc.qt.nokia.com/4.7/qobject.html は通常の C++ クラスにさまざまな機能を追加します。特にクラス名とスロット名は実行時に利用されます。同様にスロット引数の種類についても知ることができます。
9行目 (実際のソースコードでは13行目) で <code>quit()</code> スロットを宣言しています。<code>slots</code> マクロを使えば簡単です。 これでシグニチャの一致するシグナル (ここでは引数を1つも持たないシグナルなら何でも) を <code>quit()</code> スロットに接続できます。
<code>main()</code> 関数で GUI の構築やスロットの接続を行うかわりに、 <code>Notepad</code> クラスのコンストラクタを使います。
<br /> Notepad::Notepad()<br /> {<br /> textEdit = new QTextEdit;<br /> quitButton = new QPushButton(tr("Quit&quot;));
connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));
QVBoxLayout '''layout = new QVBoxLayout;<br /> layout->addWidget(textEdit);<br /> layout->addWidget(quitButton);
<br /> setLayout(layout);
<br /> setWindowTitle(tr("Notepad&quot;));<br /> }<br />
上のクラス定義のように、 "QObject":http://doc.qt.nokia.com/4.7/qobject.html へのポインタを使います (<code>textEdit</code> と <code>quitButton</code>)。通常、 "QObject":http://doc.qt.nokia.com/4.7/qobject.html は常にヒープ上に作成し、それらをコピーはしないようにしてください。
ユーザに表示される文字列が "tr()":http://doc.qt.nokia.com/4.7/qobject.html#tr 関数で囲まれています。この関数はアプリケーションを他の言語 (英語や中国語) 向けに提供するときに必要になります。ここではこれ以上触れませんが、関連ドキュメントの <code>Qt Linguist</code> を参照してみてください。
h3. 関連するドキュメント
tr() 関数と国際化: "Qt Linguist Manual":http://doc.qt.nokia.com/4.7/linguist-manual.html, "Writing Source Code for Translation":http://doc.qt.nokia.com/4.7/i18n-source-translation.html, "Hello tr()":http://doc.qt.nokia.com/4.7/linguist-hellotr.html, "Internationalization with Qt":http://doc.qt.nokia.com/4.7/internationalization.html
* QObject と Qt のオブジェクトモデル (Qt の本質を知る): "Object Model":http://doc.qt.nokia.com/4.7/object.html
* qmake と Qt のビルドシステム: "qmake Manual":http://doc.qt.nokia.com/4.7/qmake-manual.html
.pro ファイルを作成する
<code>qmake</code> の <code>project</code> オプションを使うかわりに、このサンプルプログラムのための <code>.pro</code> ファイルを書いてみましょう。
<br />HEADERS = notepad.h<br />SOURCES = notepad.cpp main.cpp<br />
以下のシェルコマンドでサンプルプログラムをビルドします。
<br />qmake<br />make<br />
h2. QMainWindow を使う
"QMainWindow":http://doc.qt.nokia.com/4.7/qmainwindow.html はメニュバー、ドック、ツールバー、ステータスバーを追加するための独自のレイアウトが備わっているため、多くのアプリケーションがその恩恵を受けるでしょう。中央のエリアにはどのような種類のウィジェットでも配置することができます。今回のサンプルプログラムではテキスト入力がそこに置かれます。
サンプル4
それでは新しい <code>Notepad</code> クラスの定義を見ていきましょう。
<br /> #include <QtGui&gt;
<br /> class Notepad : public QMainWindow<br /> {<br /> Q_OBJECT
<br /> public:<br /> Notepad();
<br /> private slots:<br /> void open();<br /> void save();<br /> void quit();
<br /> private:<br /> QTextEdit *textEdit;
<br /> QAction *openAction;<br /> QAction *saveAction;<br /> QAction *exitAction;
<br /> QMenu '''fileMenu;<br /> };<br />
ドキュメントの保存と開く処理のためにさらに2つのスロットを追加しました。これらのスロットは次のセクションで実装します。
メインウィンドウにおいてはしばしば同じスロットがさまざまなウィジェットから呼び出されます。具体的にはメニューアイテムとツールバーのボタンなどです。これをより簡単にするために Qt はさまざまなウィジェットに渡されて、1つのスロットに接続される "QAction":http://doc.qt.nokia.com/4.7/qaction.html を提供しています。たとえば "QMenu":http://doc.qt.nokia.com/4.7/qmenu.html と "QToolBar":http://doc.qt.nokia.com/4.7/qtoolbar.html は同じ "QAction":http://doc.qt.nokia.com/4.7/qaction.html から メニューアイテムとツールボタンを作成できます。これがどのように動くのかちょっと見てみましょう。
これまで通り Notepad クラスのコンストラクタを GUI の構築に使います。
<br /> Notepad::Notepad()<br /> {<br /> saveAction = new QAction(tr("&Open&quot;), this);<br /> saveAction = new QAction(tr("&Save&quot;), this);<br /> exitAction = new QAction(tr("E&amp;xit&quot;), this);
<br /> connect(openAction, SIGNAL (triggered()), this, SLOT (open()));<br /> connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));<br /> connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));
<br /> fileMenu = menuBar()<s>>addMenu(tr("&File&quot;));<br /> fileMenu</s>>addAction(openAction);<br /> fileMenu->addAction(saveAction);<br /> fileMenu->addSeparator();<br /> fileMenu->addAction(exitAction);
<br /> textEdit = new QTextEdit;<br /> setCentralWidget(textEdit);
<br /> setWindowTitle(tr("Notepad&quot;));<br /> }<br />
"QAction":http://doc.qt.nokia.com/4.7/qaction.html は追加するウィジェットにラベルとして表示されるテキストと共に作成します (今回のサンプルではメニューアイテム)。ツールバーに追加するのであれば、そのアクションに "アイコン":http://doc.qt.nokia.com/4.7/qicon.html を持たせておくこともできます。
これでメニューアイテムがクリックされると、アクションが起動し、スロットが呼び出されます。
h3. 関連するドキュメント
メインウィンドウとそのクラス: "Application Main Window":http://doc.qt.nokia.com/4.7/mainwindow.html, "Main Window Examples":http://doc.qt.nokia.com/4.7/examples-mainwindow.html
* MDI アプリケーション: "QMdiArea":http://doc.qt.nokia.com/4.7/qmdiarea.html, "MDI Example":http://doc.qt.nokia.com/4.7/mainwindows-mdi.html
h2. ドキュメントの保存と読み込み
このサンプルでは1つ前のサンプルで追加した <code>open()</code> と <code>save()</code> の2つのスロットを実装していきます。
サンプル5
<code>open()</code> スロットの方からはじめてみましょう:
<br /> QString fileName = QFileDialog::getOpenFileName(this, tr("Open File&quot;), "",<br /> tr("Text Files ('''.txt);;C++ Files ('''.cpp '''.h)"));
<br /> if (fileName != "") {<br /> QFile file&amp;#40;fileName&amp;#41;;<br /> if (!file.open(QIODevice::ReadOnly)) {<br /> QMessageBox::critical(this, tr("Error&quot;),<br /> tr("Could not open file&quot;));<br /> return;<br /> }<br /> QString contents = file.readAll().constData();<br /> textEdit->setPlainText(contents);<br /> file.close();<br /> }<br />
まず最初のステップで開くファイル名をユーザに求めています。Qt にはユーザがファイルを選択できるダイアログである "QFileDialog":http://doc.qt.nokia.com/4.7/qfiledialog.html があります。上の画像のダイアログは Kubuntu で表示させたものです。静的な "getOpenFileName()":http://doc.qt.nokia.com/4.7/qfiledialog.html#getOpenFileName 関数はモーダルなファイルダイアログを表示し、ユーザがファイルを選択するまで制御を戻しません。ダイアログは選択されたファイルのファイルパスか、ユーザがキャンセルした場合は空の文字列を返します。
もし何らかのファイル名があるときは "open()":http://doc.qt.nokia.com/4.7/qiodevice.html#open を使ってファイルのオープンを試みて、正しく開くことができたら true を返します。ここではエラー処理について詳しく説明しませんが、関連ドキュメントを参照してみてください。ファイルが開けなかった場合、ここでは "QMessageBox":http://doc.qt.nokia.com/4.7/qmessagebox.html を使ってエラーメッセージを表示します (詳しくは "QMessageBox":http://doc.qt.nokia.com/4.7/qmessagebox.html クラスの説明を参照してください)。
今回はファイルのすべてのデータを "QByteArray":http://doc.qt.nokia.com/4.7/qbytearray.html として返す "readAll()":http://doc.qt.nokia.com/4.7/qiodevice.html#readAll 関数を使っています。 "constData()":http://doc.qt.nokia.com/4.7/qbytearray.html#constData は配列のすべてのデータを const char* で返します ("QString":http://doc.qt.nokia.com/4.7/qstring.html にはそのコンストラクタがある)。そして内容がテキスト入力に表示されます。あとは "close()":http://doc.qt.nokia.com/4.7/qiodevice.html#close を呼び出してファイルディスクリプタを OS に返します。
次は <code>save()</code> スロットにとりかかりましょう。
<br /> QString fileName = QFileDialog::getSaveFileName(this, tr("Save File&quot;), "",<br /> tr("Text Files ('''.txt);;C++ Files ('''.cpp'''.h)"));
<br /> if (fileName != "") {<br /> QFile file&amp;#40;fileName&amp;#41;;<br /> if (!file.open(QIODevice::WriteOnly)) {<br /> // error message<br /> } else {<br /> QTextStream stream(&file);<br /> stream << textEdit</s>>toPlainText();<br /> stream.flush();<br /> file.close();<br /> }<br /> }<br />
テキスト入力の内容をファイルに書き込むとき、 "QFile":http://doc.qt.nokia.com/4.7/qfile.html オブジェクトをラップする "QTextStream":http://doc.qt.nokia.com/4.7/qtextstream.html クラスを使います。テキストストリームは QString をファイルに書き込むことができます。 "QFile":http://doc.qt.nokia.com/4.7/qfile.html はオブジェクト化されていない文字列データ (char*) のみを "QIODevice":http://doc.qt.nokia.com/4.7/qiodevice.html の "write()":http://doc.qt.nokia.com/4.7/qiodevice.html#write 関数で受け付けます。