ホーム

OFF-SOFT.net

OFF-SOFT.net

ウェブやソフトウェアに関するサポート&情報サイトです。サイト構築からソフトウェアの作成、利用まであなたの助けになるかも・・・・しれません。たぶん・・。

Qt (3) QtDesignerとuiファイルを調べる

公開日| 2009年05月22日 | コメントはまだありません。
概要 :
 Qtの最もQtらしい特徴は、mocとuicという2つのコンパイラを持つことです。(前回の記事にも同じことを記述しました)

 今回の記事では、前回説明していないuicの機能について記述します。
Qtでは、ユーザインターフェイスを作成する場合、Windowsで使うようなリソースファイルを使いません。 Qtで取り扱うリソースファイルは、ほとんどが画像ファイルの定義だけです。 Qtでは、画面がソースコードで直に書けますから、特別リソースファイルを必要としないわけです。
しかし、VisualBasicなどのRADツールになれた人にとって、ソースコードで想像しながら画面を作成するのは、 苦痛とも言えます。そこで、Qtでは、Qt Designerというツールが同梱されています。

このQt Designerは、画面イメージを実際の画面へ貼り付けて作成することができます。 ただし、Windowsのようなリソースファイルを出力しません。ここで出力するファイルは、XML形式のuiファイルと呼ばれるテキストファイルが出力されます。

Qtでは、このuiファイルをC/C++のヘッダへ変換し、ビルド(コンパイル+リンク)を行います。 このuiファイルをC/C++のヘッダへ変換をuic(ユーザインターフェイスコンパイラ)が行うわけです。

今回は。この一連の流れをサンプルソースを使って解説してみたいと思います。
ここで使用するプログラムは、下記の関連サイトに記載されているサンプルプログラムを判りやすく、一部、変更したものです。

MOC:メタオブジェクトコンパイラ
UIC:ユーザインターフェイスコンパイラ

関連サイト: http://doc.trolltech.com/4.5/designer-using-a-ui-file.html

ここで使用したサンプルソースコード:

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"がありますので、恐らく、このあたりに、追加したボタンの情報が入っていそうです。

このフォーマットについて、詳しく書かれたものは、見当たりません。
以下に正式に公開されている情報ページを乗せておきますが、ただ、こんなものです、と書かれてあるに過ぎません。
Qt Designer's UI File Format : http://doc.trolltech.com/4.5/designer-ui-file-format.html
このページにも書いてありますが、フォーマットは変わるかもしれないと書いてありますので、一生懸命、この中身を理解する必要もないと思います。
おおよそ、どんなものが入っているかぐらいで良いと思います。

この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ファイルを実行ファイルと同じディレクトリへコピーして実行してください。

以下のように、メッセージボックスが表示したと思います。



いかがだったでしょうか。 今回の記事は、一部のソースコードや、使い方は、判りやすいように、また、具体的に変更していますが、ほとんど、関連サイトに記載のものです。
非常に、基本的で、重要なところでしたので、あえて記事にしておきました。

関連サイト: http://doc.trolltech.com/4.5/designer-using-a-ui-file.html

何かお気づきの点があれば、コメントいただければ幸いです。

もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。


コメント

コメントをどうぞ







  • はてなブックマークへ追加する
  • Facebookでシェアする
  • twitter でつぶやく
  • Google Plusでシェアする
  • Pocketでシェアする
ページトップへ