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