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

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
(4 intermediate revisions by one other user not shown)
Line 1: Line 1:
h1. Qt ではじめる GUI プログラミング
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}


= Qt ではじめる GUI プログラミング =
Qt の世界へようこそ - Qt はクロスプラットフォームの GUI ツールキットです。この入門ガイドでは簡単なメモ帳プログラムの作成を通して基本的な Qt の知識を説明します。このガイドを読み終わるころには Qt の概要および API ドキュメントを参照しながら開発に必要な情報を集めることができるはずです。
Qt の世界へようこそ - Qt はクロスプラットフォームの GUI ツールキットです。この入門ガイドでは簡単なメモ帳プログラムの作成を通して基本的な Qt の知識を説明します。このガイドを読み終わるころには Qt の概要および API ドキュメントを参照しながら開発に必要な情報を集めることができるはずです。


Line 26: Line 27:
</code>
</code>


それでは1行ずつ見ていきましょう。最初の2行でサンプルプログラムに必要な2つのクラス、 "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html と "QTextEdit":http://doc.qt.nokia.com/4.7/qtextedit.html のヘッダファイルをインクルードしています。すべての Qt のクラスはその名前のヘッダファイルを持っています。
それでは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行目で "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html オブジェクトを作成しています。このオブジェクトはアプリケーション全体のリソースを管理し、 GUI を持つ Qt プログラムを動作させるのに欠くことのできない存在です。Qt はコマンドラインオプションを受け取るため、 <code>argv</code> と <code>args</code> が必要です。
6行目で [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] オブジェクトを作成しています。このオブジェクトはアプリケーション全体のリソースを管理し、 GUI を持つ Qt プログラムを動作させるのに欠くことのできない存在です。Qt はコマンドラインオプションを受け取るため、 <code>argv</code> と <code>args</code> が必要です。


8行目で "QTextEdit":http://doc.qt.nokia.com/4.7/qtextedit.html オブジェクトを作成しています。テキスト入力は GUI の視覚的な構成要素の1つです。Qt では通常これらをウィジェットと呼んでいます。ウィジェットは他にもスクロールバー、ラベル、ラジオボタンなどがあります。ウィジェットは他のウィジェットのコンテナ (入れ物) になることができます。たとえばダイアログやメインウィンドウなどです。
8行目で [http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit] オブジェクトを作成しています。テキスト入力は 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 関数を使ってウィジェットを表示してください。
9行目でテキスト入力を画面に表示しています。ウィジェットはコンテナとしても機能しますので (たとえばツールバーやメニュー、ステータスバーなどのウィジェットを持つ [http://doc.qt.nokia.com/4.7/qmainwindow.html)、ウィジェット単体を独立したウィンドウに表示することが可能です。ウィジェットはデフォルトでは非表示になっています。 QMainWindow] [http://doc.qt.nokia.com/4.7/qwidget.html#show show()] 関数を使ってウィジェットを表示してください。


11行目で "QApplication":http://doc.qt.nokia.com/4.7/qapplication.html のイベントループを開始します。 Qt アプリケーションが動いているとき、イベントが生成されてアプリケーションのウィジェットに送られます。具体的にはマウスボタンを押し込んだ、キーの押下などのイベントです。テキスト入力のウィジェットでテキストを入力したとき、ウィジェットはキー入力イベントを受け取り、打ち込まれたテキストを描画することで応答します。
11行目で [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] のイベントループを開始します。 Qt アプリケーションが動いているとき、イベントが生成されてアプリケーションのウィジェットに送られます。具体的にはマウスボタンを押し込んだ、キーの押下などのイベントです。テキスト入力のウィジェットでテキストを入力したとき、ウィジェットはキー入力イベントを受け取り、打ち込まれたテキストを描画することで応答します。


アプリケーションの起動は、コマンドプロンプトを開いて、<code>.cpp</code> ファイルのあるディレクトリに移動した後、次のコマンドを入力してプログラムをビルドしてください。
アプリケーションの起動は、コマンドプロンプトを開いて、<code>.cpp</code> ファイルのあるディレクトリに移動した後、次のコマンドを入力してプログラムをビルドしてください。
Line 46: Line 47:
その結果、<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> ファイルを書く方法については後ほど説明します。


h3. 関連するドキュメント
=== 関連するドキュメント ===
 
''' ウィジェットとウィンドウのジオメトリ: [http://doc.qt.nokia.com/4.7/application-windows.html Window and Dialog Widgets]
''' ウィジェットとウィンドウのジオメトリ: "Window and Dialog Widgets":http://doc.qt.nokia.com/4.7/application-windows.html
* イベントとその処理: [http://doc.qt.nokia.com/4.7/eventsandfilters.html The Event System]
* イベントとその処理: "The Event System":http://doc.qt.nokia.com/4.7/eventsandfilters.html


== 終了ボタンを追加する ==
== 終了ボタンを追加する ==


実際のアプリケーションでは通常より多くのウィジェットが必要です。そこで "QPushButton":http://doc.qt.nokia.com/4.7/qpushbutton.html をテキスト入力の真下に配置してみましょう。このボタンは押されるとメモ帳プログラムが終了します。
実際のアプリケーションでは通常より多くのウィジェットが必要です。そこで [http://doc.qt.nokia.com/4.7/qpushbutton.html QPushButton] をテキスト入力の真下に配置してみましょう。このボタンは押されるとメモ帳プログラムが終了します。


[[Image:http://doc.qt.nokia.com/4.7/images/gs2.png|サンプル2]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs2.png|サンプル2]]
Line 69: Line 69:
  QPushButton quitButton("Quit");
  QPushButton quitButton("Quit");


  QObject::connect(&amp;quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));
  QObject::connect(&quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));


  QVBoxLayout layout;
  QVBoxLayout layout;
  layout.addWidget(&amp;textEdit);
  layout.addWidget(&textEdit);
  layout.addWidget(&amp;quitButton);
  layout.addWidget(&quitButton);


  QWidget window;
  QWidget window;
  window.setLayout(&amp;layout);
  window.setLayout(&layout);


  window.show();
  window.show();
Line 84: Line 84:
</code>
</code>


1行目ではすべての Qt の GUI クラスを含む "QtGui":http://doc.qt.nokia.com/4.7/qtgui.html ヘッダをインクルードしています。
1行目ではすべての Qt の GUI クラスを含む [http://doc.qt.nokia.com/4.7/qtgui.html QtGui] ヘッダをインクルードしています。


10行目では終了ボタンが押されたときにアプリケーションが終了するように Qt のシグナルとスロットの仕組みを使っています。
10行目では終了ボタンが押されたときにアプリケーションが終了するように Qt のシグナルとスロットの仕組みを使っています。
スロットは実行時に名前 (通常の文字列) で呼び出される機能です。シグナルは呼び出されたときに登録されたスロットを起動する機能です。これを 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> はシグナルとスロットの関数シグニチャを受け取ります。そしてシグナルを送信するオブジェクトと受け取るオブジェクトのポインタも渡します。
[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行目では "QVBoxLayout":http://doc.qt.nokia.com/4.7/qvboxlayout.html オブジェクトを生成しています。前述の通り、ウィジェットは他のウィジェットを含むことができます。子ウィジェットの位置やサイズを直接指定することもできますが、通常はレイアウトを使うのが簡単です。レイアウトはウィジェットの子要素の位置とサイズを管理します。 例えば "QVBoxLayout":http://doc.qt.nokia.com/4.7/qvboxlayout.html は子要素を縦の列に配置します。
12行目では [http://doc.qt.nokia.com/4.7/qvboxlayout.html QVBoxLayout] オブジェクトを生成しています。前述の通り、ウィジェットは他のウィジェットを含むことができます。子ウィジェットの位置やサイズを直接指定することもできますが、通常はレイアウトを使うのが簡単です。レイアウトはウィジェットの子要素の位置とサイズを管理します。 例えば [http://doc.qt.nokia.com/4.7/qvboxlayout.html QVBoxLayout] は子要素を縦の列に配置します。


13行目と14行目ではテキスト入力とボタンをそれぞれレイアウトに追加しています。
13行目と14行目ではテキスト入力とボタンをそれぞれレイアウトに追加しています。
そして17行目でウィンドウにそのレイアウトを設定しています。
そして17行目でウィンドウにそのレイアウトを設定しています。


h3. 関連するドキュメント
=== 関連するドキュメント ===
 
''' シグナルとスロット: [http://doc.qt.nokia.com/4.7/signalsandslots.html Signals & Slots]
''' シグナルとスロット: "Signals &amp; Slots":http://doc.qt.nokia.com/4.7/signalsandslots.html
* レイアウト: [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]
* レイアウト: "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 のウィジェット: [http://doc.qt.nokia.com/4.7/gallery.html Qt Widget Gallery], [http://doc.qt.nokia.com/4.7/examples-widgets.html Widget Examples]
* 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 の派生クラスを作る ==


ユーザがアプリケーションを終了するとき、本当に終了したいかどうかを確認するダイアログを表示したいとします。このサンプルでは "QWidget":http://doc.qt.nokia.com/4.7/qwidget.html の派生クラスを定義して終了ボタンにつなぐためのスロットを追加します。
ユーザがアプリケーションを終了するとき、本当に終了したいかどうかを確認するダイアログを表示したいとします。このサンプルでは [http://doc.qt.nokia.com/4.7/qwidget.html QWidget] の派生クラスを定義して終了ボタンにつなぐためのスロットを追加します。


[[Image:http://doc.qt.nokia.com/4.7/images/gs3.png|サンプル3]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs3.png|サンプル3]]
Line 127: Line 126:
</code>
</code>


<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++ クラスにさまざまな機能を追加します。特にクラス名とスロット名は実行時に利用されます。同様にスロット引数の種類についても知ることができます。
<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> スロットに接続できます。
Line 151: Line 150:
</code>
</code>


上のクラス定義のように、 "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 は常にヒープ上に作成し、それらをコピーはしないようにしてください。
上のクラス定義のように、 [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] は常にヒープ上に作成し、それらをコピーはしないようにしてください。
 
ユーザに表示される文字列が "tr()":http://doc.qt.nokia.com/4.7/qobject.html#tr 関数で囲まれています。この関数はアプリケーションを他の言語 (英語や中国語) 向けに提供するときに必要になります。ここではこれ以上触れませんが、関連ドキュメントの <code>Qt Linguist</code> を参照してみてください。


h3. 関連するドキュメント
ユーザに表示される文字列が [http://doc.qt.nokia.com/4.7/qobject.html#tr tr()] 関数で囲まれています。この関数はアプリケーションを他の言語 (英語や中国語) 向けに提供するときに必要になります。ここではこれ以上触れませんが、関連ドキュメントの <code>Qt Linguist</code> を参照してみてください。


''' 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
''' 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]
* qmake と Qt のビルドシステム: "qmake Manual":http://doc.qt.nokia.com/4.7/qmake-manual.html
* 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 ファイルを作成する ===
=== .pro ファイルを作成する ===
Line 177: Line 175:
</code>
</code>


h2. QMainWindow を使う
== QMainWindow を使う ==
 
[http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] はメニュバー、ドック、ツールバー、ステータスバーを追加するための独自のレイアウトが備わっているため、多くのアプリケーションがその恩恵を受けるでしょう。中央のエリアにはどのような種類のウィジェットでも配置することができます。今回のサンプルプログラムではテキスト入力がそこに置かれます。
"QMainWindow":http://doc.qt.nokia.com/4.7/qmainwindow.html はメニュバー、ドック、ツールバー、ステータスバーを追加するための独自のレイアウトが備わっているため、多くのアプリケーションがその恩恵を受けるでしょう。中央のエリアにはどのような種類のウィジェットでも配置することができます。今回のサンプルプログラムではテキスト入力がそこに置かれます。


[[Image:http://doc.qt.nokia.com/4.7/images/gs4.png|サンプル4]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs4.png|サンプル4]]
Line 213: Line 210:
ドキュメントの保存と開く処理のためにさらに2つのスロットを追加しました。これらのスロットは次のセクションで実装します。
ドキュメントの保存と開く処理のためにさらに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 から メニューアイテムとツールボタンを作成できます。これがどのように動くのかちょっと見てみましょう。
メインウィンドウにおいてはしばしば同じスロットがさまざまなウィジェットから呼び出されます。具体的にはメニューアイテムとツールバーのボタンなどです。これをより簡単にするために 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 クラスのコンストラクタを GUI の構築に使います。
これまで通り Notepad クラスのコンストラクタを GUI の構築に使います。
Line 220: Line 217:
  Notepad::Notepad()
  Notepad::Notepad()
  {
  {
  saveAction = new QAction(tr("&amp;Open"), this);
  saveAction = new QAction(tr("&Open"), this);
  saveAction = new QAction(tr("&amp;Save"), this);
  saveAction = new QAction(tr("&Save"), this);
  exitAction = new QAction(tr("E&amp;amp;xit"), this);
  exitAction = new QAction(tr("E&xit"), this);


  connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
  connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
Line 228: Line 225:
  connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));
  connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));


  fileMenu = menuBar()->addMenu(tr("&amp;File"));
  fileMenu = menuBar()->addMenu(tr("&File"));
  fileMenu->addAction(openAction);
  fileMenu->addAction(openAction);
  fileMenu->addAction(saveAction);
  fileMenu->addAction(saveAction);
Line 241: Line 238:
</code>
</code>


"QAction":http://doc.qt.nokia.com/4.7/qaction.html は追加するウィジェットにラベルとして表示されるテキストと共に作成します (今回のサンプルではメニューアイテム)。ツールバーに追加するのであれば、そのアクションに "アイコン":http://doc.qt.nokia.com/4.7/qicon.html を持たせておくこともできます。
[http://doc.qt.nokia.com/4.7/qaction.html QAction] は追加するウィジェットにラベルとして表示されるテキストと共に作成します (今回のサンプルではメニューアイテム)。ツールバーに追加するのであれば、そのアクションに [http://doc.qt.nokia.com/4.7/qicon.html アイコン] を持たせておくこともできます。


これでメニューアイテムがクリックされると、アクションが起動し、スロットが呼び出されます。
これでメニューアイテムがクリックされると、アクションが起動し、スロットが呼び出されます。


h3. 関連するドキュメント
=== 関連するドキュメント ===
 
''' メインウィンドウとそのクラス: [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]
''' メインウィンドウとそのクラス: "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 アプリケーション: [http://doc.qt.nokia.com/4.7/qmdiarea.html QMdiArea], [http://doc.qt.nokia.com/4.7/mainwindows-mdi.html MDI Example]
* 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つのスロットを実装していきます。
このサンプルでは1つ前のサンプルで追加した <code>open()</code> と <code>save()</code> の2つのスロットを実装していきます。


Line 276: Line 271:
</code>
</code>


まず最初のステップで開くファイル名をユーザに求めています。Qt にはユーザがファイルを選択できるダイアログである "QFileDialog":http://doc.qt.nokia.com/4.7/qfiledialog.html があります。上の画像のダイアログは Kubuntu で表示させたものです。静的な "getOpenFileName()":http://doc.qt.nokia.com/4.7/qfiledialog.html#getOpenFileName 関数はモーダルなファイルダイアログを表示し、ユーザがファイルを選択するまで制御を戻しません。ダイアログは選択されたファイルのファイルパスか、ユーザがキャンセルした場合は空の文字列を返します。
まず最初のステップで開くファイル名をユーザに求めています。Qt にはユーザがファイルを選択できるダイアログである [http://doc.qt.nokia.com/4.7/qfiledialog.html QFileDialog] があります。上の画像のダイアログは Kubuntu で表示させたものです。静的な [http://doc.qt.nokia.com/4.7/qfiledialog.html#getOpenFileName 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 クラスの説明を参照してください)。
もし何らかのファイル名があるときは [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] クラスの説明を参照してください)。


今回はファイルのすべてのデータを "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 に返します。
今回はファイルのすべてのデータを [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> スロットにとりかかりましょう。
Line 293: Line 288:
  // error message
  // error message
  } else {
  } else {
  QTextStream stream(&amp;file);
  QTextStream stream(&file);
  stream << textEdit->toPlainText();
  stream << textEdit->toPlainText();
  stream.flush();
  stream.flush();
Line 301: Line 296:
</code>
</code>


テキスト入力の内容をファイルに書き込むとき、 "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 関数で受け付けます。
テキスト入力の内容をファイルに書き込むとき、 [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 プログラムと言えます。

サンプル1

これがソースコードです:

#include <QApplication>
#include <QTextEdit>

int main(int argv, char *'''args)
{
 QApplication app(argv, args);

 QTextEdit textEdit;
 textEdit.show();

 return app.exec();
}

それでは1行ずつ見ていきましょう。最初の2行でサンプルプログラムに必要な2つのクラス、 QApplicationQTextEdit のヘッダファイルをインクルードしています。すべての 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

終了ボタンを追加する

実際のアプリケーションでは通常より多くのウィジェットが必要です。そこで QPushButton をテキスト入力の真下に配置してみましょう。このボタンは押されるとメモ帳プログラムが終了します。

サンプル2

それではソースコードを見ていきます。

#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

QWidget の派生クラスを作る

ユーザがアプリケーションを終了するとき、本当に終了したいかどうかを確認するダイアログを表示したいとします。このサンプルでは QWidget の派生クラスを定義して終了ボタンにつなぐためのスロットを追加します。

サンプル3

それではソースコードを見ていきます。

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 はメニュバー、ドック、ツールバー、ステータスバーを追加するための独自のレイアウトが備わっているため、多くのアプリケーションがその恩恵を受けるでしょう。中央のエリアにはどのような種類のウィジェットでも配置することができます。今回のサンプルプログラムではテキスト入力がそこに置かれます。

サンプル4

それでは新しい

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 を提供しています。たとえば QMenuQToolBar は同じ 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


ドキュメントの保存と読み込み

このサンプルでは1つ前のサンプルで追加した

open()

save()

の2つのスロットを実装していきます。

サンプル5

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*) のみを QIODevicewrite() 関数で受け付けます。

関連するドキュメント