QtでGUIアプリーション作成入門(1)
Qtフレームワークを使って下のようなアプリケーションを作ってみる。色んな所でQt入門記事があるけど、公式Qtドキュメントのチュートリアルが結局わかりやすかった。
通常はユーザーインターフェースの作成にはQtデザイナー使用するが、Qtの動作を理解するために、あえてそれを使わないで、ソースコードからUIを作成する方法を紹介する。
対象はC++は既にわかっていてCUIソフトは作ったことあるけど、GUIはない人。
現在のQtのバージョンはQt5.1、もうすぐQt5.2の正式版がリリースされる、5.2ではiOSもサポートされるので、iPhoneアプリも作成できるようになります。
プロジェクトの作成
プロジェクトの新規作成>Qt Guiアプリケーション
- 名前:AddressBook
- クラス名:AddressBook
- 基底クラス:QWidgets
以下のファイルが生成される
- AddressBook.pro:プロジェクトの設定ファイル
- main.cpp:メイン関数がある
- addressbook.h:AddressBookクラスのヘッダ
- addressbook.cpp:AddressBookクラスの実装
コンパイル&実行はQtクリエイターの実行ボタンでもいいけど、コマンドラインからは.proがあるディレクトリにcdして。
qmake&&make
qmakeがMakefileを作成して、それをmakeする。するとAddressBook.exeなり.appができる。
基本的UIの作成
ソースコードで作成したUIとQtデザイナーで作成したUIは両立するが表示が重なるので配置には注意が必要。
addressbook.h
#include "addressbook.h" #include "ui_AddressBook.h"//Qtデザイナーで作成したui用 #include <QtWidgets> class QLineEdit; class QTextEdit; class AddressBook : public QWidget { Q_OBJECT public: AddressBook(QWidget *parent = 0); private: QLineEdit *nameLine;//名前を入力するUI要素 QTextEdit *addressText;//住所を入力するUI要素 };
AddressBookクラスを QWidget クラスのサブクラスとして定義するので、
このクラスは QLineEdit andQTextEdit のポインタをメンバ変数として持つ。それぞれ名前と住所を格納する。メンバ変数がポインタなのは、インスタンス化は実行時にするため。これらのクラスのためのヘッダ
他にもQLabelは文字列をウィンドウに表示するのに使うが、これのオブジェクトの宣言は含まない、これを参照する必要はないため。
addressbookクラスのコンストラクタは QWidget 型の引数 parent を受け取る。これはAddressBookウィジェットが他のウィジェットから呼び出された時に、呼び出し元の親ウィジェットを指定するために使うが、ここではAddressBookはユーザーが呼び出すトップレベルのウィジェットなので=0がデフォルトになっている。
addressbook.cpp
AddressBook::AddressBook(QWidget *parent) : QWidget(parent) { QLabel *nameLabel = new QLabel(tr("Name:")); nameLine = new QLineEdit; QLabel *addressLabel = new QLabel(tr("Address:")); addressText = new QTextEdit;
Qtでのトップレベル・ウィジェットのコンストラクタの主な役割はUI要素をセットアップすること。このコンストラクタでは、QLabel オブジェクト nameLabel と addressLabel がインスタンス化される、同様に、nameLine と addressText もインスタンス化される。
tr() 関数は翻訳された文字列を返す(なければそのままの文字列)。この関数は引数として与えられた QString 文字列を他の言語に翻訳するべきものとして印を付ける。翻訳すべき文字列が現れるときには常に使うべき。
レイアウト
Qtでプログラミンする際にはレイアウトがどのように働くのか理解しておくと便利。Qtは、各ウィジェットを配置するために、3つの主要なレイアウトクラスを提供する: QHBoxLayout, QVBoxLayout and QGridLayout 。
ここでは QGridLayout を使い、ラベルと入力フィールドを構造的に配置する。QGridLayout は空間を格子状に分け、ウィジェットを配置する、行と列の数を指定する。
上のダイヤグラムはセルのレイアウトとウィジェットの位置を示している、次のコードでこのアレンジメントを指定する。
QGridLayout *mainLayout = new QGridLayout; mainLayout->addWidget(nameLabel, 0, 0); mainLayout->addWidget(nameLine, 0, 1); mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop); mainLayout->addWidget(addressText, 1, 1);
addressLabel は Qt::AlignTop を付加的な引数として使っている。これはセル(1,0)が垂直中心に位置しないようにするため。
レイアウトオブジェクトをこのウィジェット上にインスタンス化するために、ウィジェットの setLayout() 関数を呼び出す必要がある:
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
最後に、ウィンドウ名を "Simple Address Book" とする。
アプリケーションの実行
main.cppにメイン関数が記述されている。この関数内で QApplication オブジェクト, app をインスタンス化する。
QApplication は様々なアプリケーションワイドな機能を提供する、例えば、デフォルトフォントやカーソル、イベントループ。なのでQtのGUIアプリには常に1つの QApplication オブジェクトが存在する。
int main(int argc, char *argv[]) { QApplication app(argc, argv); AddressBook addressBook; addressBook.show(); return app.exec(); }
メイン関数内で addressbookウィジェットをインスタンス化し、表示するために show() 関数を呼び出している。しかし、ウィジェットはアプリケーションのイベントループが始まるまでは表示されない。アプリケーション・クラスの exec() 関数を呼び出すことでイベントループを開始している。この関数の返り値がmain関数の返り値として利用されている。
アドレスブック・ウィジェットをメイン関数のメモリ領域でインスタンス化することで、メイン関数のスコープを外れるとアドレスブックやその子ウィジェットのメモリは開放され、メモリーリークを防ぐ。