이번엔 ui파일을 포함한 소스파일도 첨부합니다.
testdialog.tar.gz예제 소스 파일
main.cpp
[code]#include <QApplication>
#include "testdialog.h"
int main(int argc, char **argv) {
QApplication app(argc, argv);
TestDialog dlg;
dlg.show();
return app.exec();
}
[/code]testdialog.h
[code]
#ifndef TESTDIALOG_H
#define TESTDIALOG_H
#include <QDialog>
#include "ui_testdialog.h"
class QButtonGroup;
class TestDialog : public QDialog {
Q_OBJECT
public:
enum Color {RGB = 0, CMYK, YUV};
TestDialog();
private slots:
void setColorChecked(int id);
private:
Ui::TestDialog ui;
QButtonGroup *buttons;
};
#endif
[/code]testdialog.cpp
[code]
#include <QButtonGroup>
#include "testdialog.h"
TestDialog::TestDialog() {
ui.setupUi(this);
buttons = new QButtonGroup(this);
buttons->addButton(ui.rgb_radio, RGB);
buttons->addButton(ui.cmyk_radio, CMYK);
buttons->addButton(ui.yuv_radio, YUV);
connect(buttons, SIGNAL(buttonClicked(int)), ui.color_combo, SLOT(setCurrentIndex(int)));
connect(ui.color_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(setColorChecked(int)));
}
void TestDialog::setColorChecked(int id) {
buttons->button(id)->setChecked(true);
}
[/code]
지난번에 만든 ui파일(전 testdialog.ui 란 이름으로 저장하였습니다)과, 위의 세 파일을 작성한후, 여느때처럼 qmake -project를 이용하여 프로젝트파일을 생성해보면 평소와 다른게 하나 있을 것입니다.
바로 FORMS += testdialog.ui 라는 항목인데요, 이렇게 생성한 ui파일을 프로젝트파일의 FORMS 항목에 추가해주면 컴파일시에 자동으로 ui파일로부터 소스코드를 생성해줍니다.
그러므로, 만약 qmake -project를 이용하지 않고, 직접 프로젝트 파일을 만드시는 분은, FORMS 항목을 추가하는 걸 잊지 마시기 바랍니다.
프로젝트 파일을 생성한후, qmake로 Makefile을 만들고, make를 실행해보면 지금까지 본적 없는 작업이 앞쪽에 추가된 것이 보일 것입니다.
/usr/bin/uic-qt4 testdialog.ui -o ui_testdialog.h
이런 작업이 처음에 실행됩니다(/usr/bin/uic-qt4 부분은 Qt의 설치 환경에 따라 다를수 있지만 거의 다 프로그램 이름에는 uic가 들어가 있을 것입니다).
컴파일이 끝난후 작업 디렉토리를 보면 moc_*파일 이외에 ui_testdialog.h라는 파일이 생성된 것을 알 수 있습니다.
이 파일이 실제로 소스코드에서 쓰이는 파일입니다.
한번 살짝 열어보면...
[code]...
#include <QtGui/QRadioButton>
#include <QtGui/QSlider>
...[/code]이렇게 ui파일에서 이용한 클래스들을 위한 해더파일의 인클루드문이나[code]...
class Ui_TestDialog
{
public:
...
void setupUi(QDialog *TestDialog)
{
...
} // setupUi
void retranslateUi(QDialog *TestDialog)
{
...
} // retranslateUi
};
namespace Ui {
class TestDialog: public Ui_TestDialog {};
} // namespace Ui
...[/code]이러한 클래스 선언과 정의가 포함되어있습니다.
이 ui_testdialog.h파일이야 말로 디자이너를 이용한 UI 구현의 본체인 것입니다.
간단하게 이 파일이 만들어 지는 과정을 설명하자면, 우선 디자이너를 이용해서 xx.ui파일을 만듭니다.
이 xx.ui파일은 수정 편집이 용이하도록 XML로 기술되어있기 때문에 소스로 바로 이용하는 것은 불가능합니다.
여기서 uic라는 Qt와 함께 설치되는 툴을 이용하여, xx.ui파일을 ui_xx.h로 변환해주는 것입니다.
그러므로 FORMS 항목을 적지 않더라도, uic로 .ui파일을 해더파일로 변환해주기만 하면 문제 없습니다만, 매번 수정할때마다 작업하는게 귀찮으므로, 프로젝트 파일의 FORMS항목에 적어두어서, make할때 자동으로 uic를 돌리도록 하는게 편합니다.
이번엔 ui_testdialog.h파일에 선언된 클래스를 살펴보겠습니다.
우선 Ui_TestDialog 입니다.
이 클래스의 이름은 .ui파일에서 지정한 폼의 objectName으로 결정됩니다.
지난 시간에 TestDialog란 이름으로 지었기 때문에, 앞에 Ui_가 붙어 Ui_TestDialog란 이름이 됩니다.
폼을 만드는데 필요한 객체들이 선언되어있고, setupUi와 restranslateUi라는 두개의 함수가 선언되어있습니다.
retranslateUi는 UI의 문자열들을 번역내용을 갱신하기 위한 함수인데, 여기선 번역을 이용하지 않으므로 이용할일이 없습니다.
중요한건 setupUi라는 함수입니다.
이 함수의 내용을 보면 전전시간에 설명한 레이아웃 시스템처럼 각종 레이아웃이 생성되고 위젯들이 배치되는 과정과, 디자이너에서 연결한 시그널/슬롯들이 연결되도록 되어있습니다.
바로 이 setupUi가 UI를 위젯이나 다이얼로그등에 적용시켜주는 함수인 것입니다.
Ui_TestDialog외에, Ui라는 네임스페이스 속에, Ui_TestDialog를 상속하기만 하고 아무것도 하지 않는 TestDialog란 클래스가 선언되어있습니다.
결국 Ui_TestDialog와 Ui::TestDialog는 동등하므로 어느쪽을 쓰든 상관없습니다.
이제 소스코드를 살펴보겠습니다.
testdialog.h의 5번째 줄을 보면 ui_testdialog.h파일을 인클루드하고 있는 것을 알 수 있습니다. 이렇게 uic로 생성된 해더파일을 직접 인클루드하여 이용합니다.
그리고 Ui용 클래스를 이용하는 방법에는 두가지가 있습니다.
제가 이용한 것과 같은 private 멤버로 선언하는 방법과, priavte 상속을 이용하는 방법입니다.
상속에 대해 공부하셨다면 아시겠지만, private 상속은 public 상속과 달리 A has B 의 관계이므로 결국 private 멤버로 선언하는 것과 다를바가 없습니다.
17번째 줄을 보면 Ui::TestDialog ui; 와 같이 UI 클래스의 객체를 선언하고 있는 것을 알 수 있습니다.
만약 private 상속을 이용한다면, 클래스 정의 부분이
[code]class TestDialog : public QDialog, private Ui::TestDialog {[/code]와 같이 바뀌고, ui선언은 없어지겠지요.
그리고 보통 생성사에서 Ui::TestDialog::setupUi를 호출함으로써 UI를 적용합니다.
이 예제처럼 새로운 위젯을 직접 정의하는 경우라면 두가지 방법이 차이가 없지만, 예를 들어 특별히 복잡한 함수나 슬롯/시그널이 필요없이 간단하게 값만 입력받거나 디스플레이하기 위한 폼의 경우라면
QDialog dlg(this);
Ui::Form ui;
ui.setupUi(&dlg);
와 같이 함으로써 폼만 만들고 특별히 새로운 클래스를 작성하지 않고 이용하는 방법도 있습니다.
이경우는 새로운 클래스를 만들지 않으므로 다중 상속을 이용한 UI의 적용은 불가능하겠지요.
또, QButtonGroup이라는 처음보는 클래스가 있는데요, 이 클래스는 이름 그대로 버튼들을 하나의 그룹으로 묶어서 관리할때 편리합니다.
여기서 말하는 버튼은 QAbstractButton클래스를 상속받은 클래스들로, QPushButton이나 QRadioButton, QCheckBox, QToolButton 등이 해당합니다.
특히, QRadioButton은 처음부터 여러개중에 하나를 선택하기 위한 목적으로 연관된 버튼들이 여러개 있는 경우가 많기 때문에, QButtonGroup이 유용합니다.
testdialog.cpp파일을 보겠습니다.
소스를 보면 ui의 멤버로 버튼들로 접근 하고 있는 것을 알 수 있습니다.
각 멤버의 이름은 역시 전회에서 설명한대로 디자이너에서 objectName로 지정한 값이 이용됩니다.
만약 private멤버로 ui를 선언하지 않고, Ui::TestDialog를 private 상속 받은 경우라면 ui.대신에 보통 private 멤버처럼 접근해서 이용하면 됩니다.
여기서 7~9번째 줄을 보면 addButton을 이용하여 라디오 버튼들을 추가하고 있는데요, 버튼 포인터외에 인자를 하나 더 넘기고 있습니다.
이 인자는 버튼을 구분하기 위한 'id'입니다.
이 id로 버튼의 고유한 값을 지정하면 유용한 경우가 많습니다.
예를 들어, 이경우에는 enum을 이용하여 RGB, CMYK, YUV라는 상수를 정의하였고, 각각을 0, 1, 2로 대응시켰습니다.
이 값은 color_combo의 RGB, CMYK, YUV의 인덱스에 대응하기 때문에, id로 이 값들을 넘겨줌으로써 간단하게 10번째 줄과 같은 시그널/슬롯의 연결이 가능합니다.
또한, 반대로 color_combo의 인덱스가 바뀔때마다 라디오 버튼의 선택이 바뀌도록 setColorChecked라는 슬롯을 이용합니다.
이경우도 역시 id와 인덱스를 대응시켜뒀기 때문에, QButtonGroup::button()에 인자로 인덱스를 넘겨주어서 거기에 해당하는 id의 버튼 포인터를 가져오고, 그 버튼이 체크되도록 합니다.
한번 컴파일된 파일을 실행해보면, 라디오 버튼의 선택이 바뀔때마다 콤보박스의 값이 바뀌고, 반대로 콤보박스의 값을 바꿀때마다, 라디오 버튼의 선택이 바뀔 것입니다.
이상으로 2회에걸쳐 디자이너의 사용 방법에 대해 알아보았습니다.
일단 디자이너를 쓰는데 있어서 필요한 내용은 설명했다고 생각합니다. 액션이나 리소스에 대해서는 설명하지 않았는데, 차후에 메인윈도우에 대한 설명을 하게 되면 따로 설명하지 않더라도 어떻게 이용하는지 알 수 있게 될 것이라고 생각합니다.
다음 시간에는 각종 위젯에 대해 소개하도록 하겠습니다.
Posted by xylosper












