QtDesignerで画面イメージを作りましょう
今回は、ソースコードから画面を作るわけではありません。
QtDesignerで画面を作成し、uiファイルを作成します。
QtDesignerは、通常、以下の名前であります。
%Qtインストールディレクトリ%\qt\bin\designer.exe
これをダブルクリックで起動します。
起動すると恐らく、以下のような画面が最初に立ち上がると思います。そこで、"Widget"を選択して、作成をクリックします。
今回は、ボタンが一つあるだけの簡単なフォームのみを作成します。
※もし、上記の画面が立ち上がらなかった場合は、[ファイル]-[New]で同じ画面が立ち上がります。
何もない画面が中央に見えていると思います。
その画面の中央あたりに、左の"PushButton"をマウスでドラッグ&ドロップしてみましょう。
以下のように画面にボタンが作成できたと思います。
このまま、保存をクリックし、適当なディレクトリへ"test.ui"という名前で保存しましょう。
すると以下のようなテキストファイルが出力されます。これが、XML形式のuiファイルそのものです。
[test.ui]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>110</x>
<y>130</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
|
16行目あたりに
"QPushButton"がありますので、恐らく、このあたりに、追加したボタンの情報が入っていそうです。
このuiファイルは、XML形式ですので、C/CPPでは、そのままでは認識できません。
このXMLファイルのままでも、アプリケーションの中で読み込んで使用することができます。
それについては、後述します。
ここでは、基本操作手順に基づき作業を行います。
uiファイルをヘッダへ変換してくれるのがuic(ユーザインターフェイスコンパイラ)です。
では、早速、使ってみましょう。以下のコマンドを投入します。
1
| C:\temp> uic -o ui_test.h test.ui
|
このコマンドが終了するすると、"ui_test.h"が出力されます。
では、このファイルを見てみましょう。
[ui_test.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| /********************************************************************************
** Form generated from reading ui file 'test.ui'
**
** Created: Fri May 22 10:32:02 2009
** by: Qt User Interface Compiler version 4.5.1
**
** WARNING! All changes made in this file will be lost when recompiling ui file!
********************************************************************************/
#ifndef UI_TEST_H
#define UI_TEST_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QPushButton>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Form
{
public:
QPushButton *pushButton;
void setupUi(QWidget *Form)
{
if (Form->objectName().isEmpty())
Form->setObjectName(QString::fromUtf8("Form"));
Form->resize(400, 300);
pushButton = new QPushButton(Form);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setGeometry(QRect(110, 130, 75, 23));
retranslateUi(Form);
QMetaObject::connectSlotsByName(Form);
} // setupUi
void retranslateUi(QWidget *Form)
{
Form->setWindowTitle(QApplication::translate("Form", "Form", 0, QApplication::UnicodeUTF8));
pushButton->setText(QApplication::translate("Form", "PushButton", 0, QApplication::UnicodeUTF8));
Q_UNUSED(Form);
} // retranslateUi
};
namespace Ui {
class Form: public Ui_Form {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_TEST_H
|
注意すべきは、下記の点です。
- Ui_Formというクラスは、何も継承していない
- Formというクラスは、Ui_Formのみ継承している
QWidgetもQMainWindowも、その他、QPushButtonなども、何も継承していません。
ここがQtらしいところだと思います。MFCなどのリソースからクラスを起こす場合、ほとんどは、CWndの子供から更に継承したものができあがるのがよくあるパターンです。
しかし、そうしないところにQtの意地というか、一ひねりしていますという感じを受けます。
WTLもそうですが、凡人の私では、ついつい、継承を使いたくなりますが、そこに別の活路を見出す賢い方々がいらっしゃいます。
さて、話がそれましたが、では、先のヘッダでできたUi_Form,Formというクラスをどのように使えば良いでしょうか。
以下がその答えの一つです。
[sample.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
| #include "ui_test.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *widget = new QWidget;
Ui::Form ui;
ui.setupUi(widget);
widget->show();
return app.exec();
}
|
非常にシンプルです。
何か基本となる画面(ここでは、QWidgetを6行目あたりで生成しています)を、今回、自動作成したUi::Formに渡して、
基本となる画面へ埋め込むんですね。
埋め込まれた、画面を表示すれば、すでに"setupUi"でaddされてますから、きれいに表示できますね。
以下のような画面が表示されたと思います。
このようにほとんど手を加えることなる画面を作成することができます。
自分で記述するのは、先のsample.cppの12行程度ですから、画面表示だけを考えれば、RADツールといえばそうかもしれませんね。
このQtDesignerがあるので、Qtの開発者は、QtはRADツールだと言っているようです。しかし、どうでしょうね。
個人的には、RADツールは、VB6ぐらいを思い出しますが、皆さんはいかがでしょうか。
さて、画面表示は、こんなものでできますが、実際に、今度は、ボタンがクリックされたときにシグナル、スロットを定義したいと思います。
シグナルとスロットと追加する
では、ボタンをクリックされた時に、アプリケーションを終了するように定義しましょう。
以下がその例です。
[sample.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #include "QMessageBox"
#include "ui_test.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *widget = new QWidget;
Ui::Form ui;
ui.setupUi(widget);
QPushButton* ui_findButton = qFindChild<QPushButton*>(widget, "pushButton");
if(ui_findButton!=NULL){
widget->connect(ui_findButton, SIGNAL(clicked()),
qApp, SLOT(closeAllWindows()));
} else {
QMessageBox::information (NULL,"Nothing","Nothing pushButton.");
}
widget->show();
return app.exec();
}
|
11行目で、画面から"pushButton"というウィジェット名からQPushButtonのオブジェクトを探してきます。
その探したQPushButtonのシグナル"clicked"に、スロット"closeAllWindows"を割り当てています。
実際に、実行してクリックしてみてください。画面が閉じて、終了したと思います。
このように、すでにあるスロットやシグナルであれば、このように画面イメージをQtDesignerで作成して
簡単に制御までできます。
しかし、ほとんどの場合は、個別のスロットを定義したいものです。そうしたとき、メタを使わなければなりません。
使うためにmocで、ちゃんと認識できるように継承クラスを設けて、ヘッダとクラスに分けてあげます。
では、QWidgetを継承したクラスを作って、個別のスロットを用意してみましょう。
前回の記事と同じようにサンプルファイルを3つ準備します。
- sample.cpp
-- mainルーチンです。
- mainwindow.h
-- QWidget継承クラスヘッダです。
- mainwindow.cpp
-- QWidget継承クラスソースです。
では、それぞれのソースコードを見てみましょう。
[mainwindow.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| #ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_test.h"
#include <QtGui>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::Form ui;
};
#endif
|
15行目が、スロットの定義です。
名前に注意してください。
"on_ウィジェット名_シグナル名"となっていることに注意しなければなりません。
スロット名は、QtDesignerで指定することもできますが、何も指定がない場合は、上記の法則で、デフォルトのスロットを定義できます。
この定義名で、connect処理を記述しなくて良くなります。
[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #include "QMessageBox"
#include "mainwindow.h"
MainWindow::MainWindow()
{
ui.setupUi(this);
setWindowTitle(tr("SampleWindow"));
}
void MainWindow::on_pushButton_clicked()
{
QMessageBox::information (NULL,"Click","Click Click!!");
}
|
6行目で、自動で作成されたクラスをダイレクトに使用していたときと同じように、このウィジェット上にQtDesigneで定義した画面を貼り付けます。
12行目からは、ボタンがクリックされたときの動作です。
ここでは、メッセージボックスを表示するようにしています。
[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
| #include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
return app.exec();
}
|
ここは、説明は必要ないかと思います。単純にアプリケーションを作って、画面を作って表示だけです。
さあ、実行してみましょう。
以下のように、メッセージボックスが表示したと思います。
ここでは、単純な継承を用いましたが、Ui::Formを同時に多重継承させても同じようにできます。
内部属性として持つか、継承元(親)として持つかの違いです。
uiファイルをそのまま使う
最後にuiファイルをそのまま使ってみましょう。
先で作成したクラスをそのまま流用します。
- sample.cpp
-- mainルーチンです。
- mainwindow.h
-- QWidget継承クラスヘッダです。
- mainwindow.cpp
-- QWidget継承クラスソースです。
では、それぞれのソースコードを見てみましょう。
[mainwindow.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>
#ifndef _DEBUG
#pragma comment(lib, "QtUiTools.lib")
#else
#pragma comment(lib, "QtUiToolsd.lib")
#endif
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow();
private slots:
void on_pushButton_clicked();
};
#endif
|
6 - 10行目は、uiファイルを読み込むためのクラスライブラリを指定しています。
既に、記述しているライブラリが環境に設定してあれば不要です。
当然ですが、前回分には、
"Ui::Form ui;"がありましたが、今回は、ありません。
[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| #include "QMessageBox"
#include "mainwindow.h"
#include "QFile"
#include "QtUiTools/QUiLoader"
MainWindow::MainWindow()
{
QUiLoader oloader;
QFile ofile("test.ui");
ofile.open(QFile::ReadOnly);
QWidget *widget = oloader.load(&ofile, this);
ofile.close();
QPushButton* ui_findButton = qFindChild<QPushButton*>(widget, "pushButton");
if(ui_findButton!=NULL){
connect(ui_findButton, SIGNAL(clicked()),
this, SLOT(on_pushButton_clicked()));
} else {
QMessageBox::information (NULL,"Nothing","Nothing pushButton.");
}
setWindowTitle(tr("SampleWindow"));
}
void MainWindow::on_pushButton_clicked()
{
QMessageBox::information (NULL,"Click","Click Click!!");
}
|
10 - 23行目で、uiファイルを読み込み、"pushButton"オブジェクトのクリックシグナルとダイレクトにon_pushButton_clickedスロットを
定義しています。
当然ですが、Auto-onnectは、今回は、使えません。
※Auto-onnect:名前の定義だけでコネクトを自動で実施すること。
[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
| #include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
return app.exec();
}
|
ここは、説明は必要ないかと思います。単純にアプリケーションを作って、画面を作って表示だけです。
さあ、実行してみましょう。
※test.uiファイルを実行ファイルと同じディレクトリへコピーして実行してください。
以下のように、メッセージボックスが表示したと思います。
もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。
コメントをどうぞ