2015. 7. 28. 23:58

0031 - GUI 프로그래밍 소개 / 프로젝트 내 파일

참고 영상 (2분 22초 이후)

지난 시간인 0030 - GUI 프로그래밍 소개 에 이어서 진행합니다.

GUI Application 을 구성하는 각 File 들에 대해 살펴 봅니다.

1. main.cpp

파일을 열어서 보시면 Console Application 과 거의 동일해 보입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// main.cpp
#include "mainwindow.h"
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
 
    return a.exec();
}
 
cs

MainWindow w 와 w.show() 가 추가된 걸로 보이는데, 이것은 Project 를 생성할 때 지정한 MainWindow 클래스 설정에 의해 자동으로 생성되고 지원 되는 객체(w)와 그 객제가 제공하는 메소드(show) 입니다.

그 이외에는 Window 에 사용자의 Event 를 받기 위한 Loop 가 동작하는 QApplication 객체(a) 와 메소드(exec) 인 부분은 Console Application 때와 동일합니다.

2. 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
24
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private:
    Ui::MainWindow *ui;
};
 
#endif // MAINWINDOW_H
 
cs

Ui 는 Form을 구성하는 mainwindow.ui 에 대응하는 Class 를 포함하는 namespace 입니다.

Q_OBJECT 는 간단히 설명하면 Qt Library 를 원활하게 호출하고 사용하기 위한 매크로 입니다. 이 매크로를 통해 Qt 가 매타 오브젝트 시스템(Meta Object System) 구축이 가능해집니다. QObject 를 상속 받는 클래스라면 정의 초기에 지정해 주는 것을 권장하고 있습니다.

private 항목에 보면 MainWindow 클래스는 이름은 동일하지만 Ui 네임스페이스를 가지면서 Ui::MainWindow 형 객체인 포인터 ui 가 있음을 볼 수 있습니다. 이 Ui::MainWindow 클래스는 위에서 선언하고 있는 MainWindow 클래스와는 다르며 ui_mainwindow.h 에 정의 되어 있습니다.

이 ui_mainwindow.h 파일은 UI Creator (UIC) 가 Form 파일을 컴파일을 하면서 해당 헤더 파일을 자동으로 생성하는데, Ui::MainWindow 클래스는 상위 Folder 에 만들어진 build-003_GUI-Desktop_Qt_5_5_0_MinGW_32bit-Debug 의 ui_mainwindow.h 의 Ui_MainWindow 클래스에 대응 됩니다. 

3. ui_mainwindow.h

User Interface Compiler 라고 불리는 UIC 가 mainwindow.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
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// ui_mainwindow.h
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.5.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
 
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
 
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>
 
QT_BEGIN_NAMESPACE
 
class Ui_MainWindow
{
public:
    QMenuBar *menuBar;
    QToolBar *mainToolBar;
    QWidget *centralWidget;
    QStatusBar *statusBar;
 
    void setupUi(QMainWindow *MainWindow)
    {
        if (MainWindow->objectName().isEmpty())
            MainWindow->setObjectName(QStringLiteral("MainWindow"));
        MainWindow->resize(400300);
        menuBar = new QMenuBar(MainWindow);
        menuBar->setObjectName(QStringLiteral("menuBar"));
        MainWindow->setMenuBar(menuBar);
        mainToolBar = new QToolBar(MainWindow);
        mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
        MainWindow->addToolBar(mainToolBar);
        centralWidget = new QWidget(MainWindow);
        centralWidget->setObjectName(QStringLiteral("centralWidget"));
        MainWindow->setCentralWidget(centralWidget);
        statusBar = new QStatusBar(MainWindow);
        statusBar->setObjectName(QStringLiteral("statusBar"));
        MainWindow->setStatusBar(statusBar);
 
        retranslateUi(MainWindow);
 
        QMetaObject::connectSlotsByName(MainWindow);
    } // setupUi
 
    void retranslateUi(QMainWindow *MainWindow)
    {
        MainWindow->setWindowTitle(QApplication::translate("MainWindow""MainWindow"0));
    } // retranslateUi
 
};
 
namespace Ui {
    class MainWindow: public Ui_MainWindow {};
// namespace Ui
 
QT_END_NAMESPACE
 
#endif // UI_MAINWINDOW_H
 
cs

mainwindow.h 에서

namespace Ui {
class MainWindow;
}

전방 선언(forward-declaration) 을 통해 이 Ui_MainWindow 클래스를 포함하는 객체(w)는 Form 내용의 변경으로 인해 UI Creator 가 생성하는 ui_mainwindow.h 내용이 변경되어도 내용과 관계 없이 MainWindow 를 가리키는 포인터(ui)의 Size 가 동일(32비트 기준 4바이트) 하므로 컴파일시 이 객체(w) 를 사용하는 mainwindow.cpp 가 ui_mainwindow.h 를 다시 인클루드(include) 하여 재컴파일 하는 부담을 덜어줍니다.

추가로 자세한 설명은 [QT/X11] Qt에 대하여 - 6. Meta-Object System 페이지를 병행해서 보시면 이해에 도움이 됩니다.

4. mainwindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
cs

MainWindow.cpp 는 사용자가 처음 지정한 MainWindow 객체에 대해 생성자와 소멸자 그리고 추가로 만들 메소드에 대한 내용을 담고 있습니다.

처음에는 구분이 어려우실 수 있는데,MainWindow::MainWindow(...) 는 MainWindow 의 생성자이며, 생성자에서 초기화 목록에 포함되어 잇는 Ui::MainWindow 는 Ui_MainWindow 클래스를 가리키며, 이는 3. 항목에 설명한 ui_mainwindow.h 에 정의되어 있습니다.

따라서 ui->setupUi() 는 MainWindow 클래스에서 호출되지 않고 Ui_MainWindow 에 선언된 setupUi 메소드를 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ui_mainwindow.h
void setupUi(QMainWindow *MainWindow)
{
    if (MainWindow->objectName().isEmpty())
        MainWindow->setObjectName(QStringLiteral("MainWindow"));
    MainWindow->resize(400300);
    menuBar = new QMenuBar(MainWindow);
    menuBar->setObjectName(QStringLiteral("menuBar"));
    MainWindow->setMenuBar(menuBar);
    mainToolBar = new QToolBar(MainWindow);
    mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
    MainWindow->addToolBar(mainToolBar);
    centralWidget = new QWidget(MainWindow);
    centralWidget->setObjectName(QStringLiteral("centralWidget"));
    MainWindow->setCentralWidget(centralWidget);
    statusBar = new QStatusBar(MainWindow);
    statusBar->setObjectName(QStringLiteral("statusBar"));
    MainWindow->setStatusBar(statusBar);
 
    retranslateUi(MainWindow);
 
    QMetaObject::connectSlotsByName(MainWindow);
// setupUi
cs

5. 003_GUI.pro

Qt 에서 사용하는 빌드 도구 (Build Tool) 인 qmake 에서 사용하며 필요한 라이브러리와 컴파일시 포함되어야 하는 파일, 헤더, 폼들을 지정합니다. 이를 Qt Creator 열어서 코딩 작업을 시작할 수  있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 003_GUI.pro
#-------------------------------------------------
#
# Project created by QtCreator 2015-07-24T02:27:14
#
#-------------------------------------------------
 
QT       += core gui
 
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 
TARGET = 003_GUI
TEMPLATE = app
 
 
SOURCES += main.cpp\
        mainwindow.cpp
 
HEADERS  += mainwindow.h
 
FORMS    += mainwindow.ui
 
cs

6. moc_mainwindow.cpp

Meta Object Compiler 라고 불리는 MOC 에 의해서 생성되며, 빌드시 결과물이 나오는 폴더에서 생성됩니다. 이름과는 달리 직접 컴파일을 하지 않으며  Q_OBJECT, public slots:, protected slots:, private slots:, signals: 와 같은 키워드가 있으면 이를 확인해서 다른 C++ 코드로 치환 해줍니다. 해당 코드는 Qt 에서 직접 하므로 개발자가 따로 수정하거나 추가 하는 부분은 없습니다.


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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// moc_mainwindow.cpp
/****************************************************************************
** Meta object code from reading C++ file 'mainwindow.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.5.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
 
#include "../../003_GUI/mainwindow.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'mainwindow.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.5.0. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
 
QT_BEGIN_MOC_NAMESPACE
struct qt_meta_stringdata_MainWindow_t {
    QByteArrayData data[1];
    char stringdata0[11];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
    Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
    qptrdiff(offsetof(qt_meta_stringdata_MainWindow_t, stringdata0) + ofs \
        - idx * sizeof(QByteArrayData)) \
    )
static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = {
    {
QT_MOC_LITERAL(0010// "MainWindow"
 
    },
    "MainWindow"
};
#undef QT_MOC_LITERAL
 
static const uint qt_meta_data_MainWindow[] = {
 
 // content:
       7,       // revision
       0,       // classname
       0,    0// classinfo
       0,    0// methods
       0,    0// properties
       0,    0// enums/sets
       0,    0// constructors
       0,       // flags
       0,       // signalCount
 
              // eod
};
 
void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    Q_UNUSED(_o);
    Q_UNUSED(_id);
    Q_UNUSED(_c);
    Q_UNUSED(_a);
}
 
const QMetaObject MainWindow::staticMetaObject = {
    { &QMainWindow::staticMetaObject, qt_meta_stringdata_MainWindow.data,
      qt_meta_data_MainWindow,  qt_static_metacall, Q_NULLPTR, Q_NULLPTR}
};
 
 
const QMetaObject *MainWindow::metaObject() const
{
    return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
 
void *MainWindow::qt_metacast(const char *_clname)
{
    if (!_clname) return Q_NULLPTR;
    if (!strcmp(_clname, qt_meta_stringdata_MainWindow.stringdata0))
        return static_cast<void*>(const_cast< MainWindow*>(this));
    return QMainWindow::qt_metacast(_clname);
}
 
int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    _id = QMainWindow::qt_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    return _id;
}
QT_END_MOC_NAMESPACE
 
cs

참고 문서


Trackback 0 Comment 0