사람들이 가장 두려워하는 것 중에 하나가 새로운 것에 도전하는 것이 아닐까 싶다. 하지만 ‘시작이 반이다’라는 말이 괜히 있는 것이라고 생각하지 않는다. 일단 시작을 하면 그 두려움은 사라지고 그 도전 자체에 푹 빠지는 것이 프로그래머의 가장 큰 장점이 아닐까 한다. Qt를 처음 배우고자 하는 사람들을 위해 이 연재를 시작하고자 한다. Qt를 한 번이라도 해본 사람은 아마도 많이 느꼈을 것이다. Qt에 도전하는 것이 그 어떤 것보다도 쉬웠음을 말이다. 이 연재는 Qt에 관심이 있거나 Qt 프로그램을 시작하려는 사람들에게 초점이 맞춰져 있다. 그러나 그 끝은 Qt의 고수라는 호칭과 함께 마무리될 것이다. Qt의 전반적인 내용보다는 소스 위주와 관련 팁으로 꾸려나갈 것이며 이 연재로 인해 독자들이 Qt를 조금이나마 알 수 있는 기회가 되길 바란다.


김주범 | jbkim@hancom.com, 창경식 | kschang@hancom.com

현재 한컴리눅스에서 연구원으로 재직 중이며 한컴오피스와 한컴모바일오피스 개발에 참여했다.


프로그래머는 지적 호기심을 가지고 새로운 지식(언어, 패러다임)을 언제든지 수용할 수 있고, 자기 계발을 충분히 즐길 수 있는 사람이라 말한다면 억지라고 할 수 있을까? 필자 스스로 프로그래머라고 부를 수 있을 정도에 이를 만큼의 긴 경력을 갖고 있지는 못하지만 이 직업이야말로 다른 어떤 직업보다도 새로움에 적응하고 미래를 예측하는 능력이 절실히 필요하다고 생각한다. 많은 사람들이 프로그래머란 직업에 흥미를 갖고 도전하려 한다. 하지만 그 중에 많은 사람들이 프로그래머로서의 정체성을 의심하는 것 또한 사실이다.
한 가지의 프로그램 언어만 확실히 알아도 다른 프로그램 언어를 쉽게 사용할 수 있다는 말을 선배 개발자로부터 종종 듣게 된다. 쉽게 사용할 수 있다는 말은 어떻게 보면 익히는 데 그만큼의 시간이 덜 걸린다는 말이지, 다른 언어를 사용하는 것 자체가 습득 절차 없이 모국어를 쓰듯 사용할 수 있다는 것을 의미하진 않을 것이다. 한 시스템에서 다른 시스템으로 이식한다고 했을 때 적지 않은 시간이 소요된다는 사실은 이를 분명하게 증명해 준다. 한 시스템에서 프로그램을 개발하고 그 프로그램을 다른 언어를 사용하는 시스템으로 이식하는 일은 프로그래머로서 단순한 작업에 지나지 않는다. 그래서 필자는 항상 꿈을 꾸곤 했다. A라는 환경에서 작업한 프로그램을 B라는 환경에서 별다른 작업을 하지 않고 그대로 소스를 가져올 수 있다면, 그것도 네이티브하게 가져올 수 있다면(자바처럼 중간에 인터프리터가 있는 경우가 아니라 해당 머신에 최적화된 컴파일을 할 수 있다면) 얼마나 환상적일까 하는 상상을 했다. Qt를 만나기 전까지만 해도 이것은 머리 속에서만 그려지는 이상이었다. 하지만 Qt는 이상을 현실로 쉽게 가져올 수 있는 계기를 마련해 주었다.
독자들이 이 기사를 읽고 있다면 대부분이 프로그래머이거나 프로그래머를 꿈꾸는 사람들 중에 하나일 것이다. 독자들이 필자와 같은 꿈을 꾼 적이 있다면(한 시스템에서 다른 시스템으로 포팅을 해본 경험이 있는 프로그래머라면) 이번 글이 흥미로울 것이다. Qt에 대한 소개로 이번 연재를 시작하고자 한다. Qt를 처음 접하거나 관심 정도에 머물렀던 독자들은 이 글이 필수적일 테지만 중급 혹은 고급 프로그래머들은 다소 따분한 연재일지도 모르겠다. 하지만 Qt의 철학을 알 수 있다는 점에서 한번 훑어본다는 생각으로 읽어주었으면 좋겠다.

Qt 설치하기
앞에서도 언급했다시피 Qt는 다양한 플랫폼을 지원한다. 여기에선 가장 많이 쓰이는 두 가지 플랫폼(윈도우와 리눅스)에서 설치하는 방법을 간단히 설명할 것이다. 그 외의 플랫폼은 이 두 플랫폼과 성격이 유사하므로 배제하겠다.

윈도우에서 Qt 설치
윈도우용 Qt는 QPL 정책으로 풀려있지 않은 상태이다. 따라서 상업적인 제품을 개발하려고자 한다면 라이선스를 얻어야 하지만 비 상업적인 용도로 사용한다면 버전은 낮지만 트롤테크 홈페이지에서 다운 받을 수 있다(ftp://ftp.trolltech.com/qt/non-commercial/ QtWin230-NonCommercial.exe).
이 버전은 다른 버전과 달리 Qt 소스를 포함하고 있지 않다. 그리고 아쉽게도 볼랜드 C++는 지원하지 않는다. Qt 라이브러리, Qt 디자이너, tmake, 예제 프로그램으로 구성되어 있다. 설치하는 법은 일반 윈도우 애플리케이션 설치 방법과 동일하다.
비주얼 스튜디오 환경에서 Qt를 사용하려면 몇 가지 작업이 필요하다. Qt를 애드인(add-in)으로 넣는 과정으로 Tools-Customize 다이얼로그를 실행한 후, Add-ins and Macro Files 탭에서 QMsDev Developer Studio-Add-In을 추가시켜야 한다. 이제 비주얼 스튜디오에서 Qt를 사용할 준비는 다 된 셈이다. 애드인이 설치되면 <화면 2>와 같은 플로팅 툴바가 하나 보일 것이다.

◆ New Qt Project : .pro 프로젝트 파일과 VS의 dsp 파일을 생성한다.
◆ Generate Qt Project : .pro 프로젝트 파일을 VS의 dsp 파일로 변환시켜 준다.
◆ New Qt Dialog : 디자이너에서 수정할 수 있는 Qt 다이얼로그를 생성한다. 이 다이얼로그는 .pro 프로젝트 파일에 자동으로 추가된다.
◆ Qt Designer : 디자이너를 실행한다(디자이너에 대한 설명은 다음 호에 있을 예정이다).

리눅스에서 Qt 설치
먼저 Qt는 http://www.trolltech.com/download/qt/x11.html에서 얻을 수 있다. 다운받은 Qt를 아무 디렉토리에 푼다. 필자는 /home 디렉토리에 qt라는 디렉토리를 만들고 그곳에 풀었다. 리눅스는 윈도우와 달리 몇 개의 환경변수를 직접 셋팅해 줘야 한다. 먼저 필자가 .bash_profile에 작성한 것을 보자.

QTDIR=/home/qt/qt-x11-free-3.1.0
PATH=$QTDIR/bin:$PATH
MANPATH=$QTDIR/doc/man:$MANPATH
LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH

추가되는 환경변수로 $QTDIR이 있다. 이 환경변수가 셋팅되어 있지 않으면 Qt 컴파일 자체가 안 되는 것에 유의하자. 다운받은 Qt를 풀면 생기는 폴더가 $QTDIR이 된다. Qt를 구지 /usr/local에 설치할 필요는 없다. 대부분의 경우 /usr/local은 ‘/’ 파티션으로 잡혀 있어서 리눅스를 다시 설치하게 되면 Qt도 다시 설치해야 한다.
그러나 대부분의 리눅스 유저들이 ‘/home’ 파티션을 따로 잡을거라 생각한다. 이 경우 /home에 Qt를 설치하면 리눅스를 다시 설치하는 일이 발생해도 Qt는 그 자리에 남아있게 된다. 그러나 설치한 리눅스의 gcc나 중요 라이브러리들의 메이저 업그레이드가 되었다면 컴파일만 다시 한번 해주는 수고가 따를 것이다.
LD_LIBRARY_PATH는 라이브러리 로딩시에 찾는 PATH이다. 만약 이 패스를 설정하기 싫다면 /etc/ld.so.conf를 열어 그 곳에 라이브러리 패스를 넣어 줘도 된다. /etc/ld.so.conf에 패스를 넣어 주면 ldconfig를 한번 실행해야 한다(물론 root로). 이렇게 환경변수를 셋팅해 놓으면 Qt 컴파일 준비 완료이다.

리눅스에서 Qt 컴파일
그럼 먼저 configure 옵션을 살펴보자.

# cd $QTDIR
# ./configure

이와 같이 아무런 옵션 없이 configure를 할 경우 다음과 같은 옵션들이 정의되었다는 메시지가 나온다. 이 경우 쓰레드 및 gif 등이 컴파일 모듈에서 빠지게 된다. 이렇게 되면 QThread나 gif 관련된 것을 사용할 수 없게 된다.이를 사용하기 위해서는 ./configure -thread -qt-gif라고 해야 한다. 기본 값은 릴리즈로 컴파일된다. Qt를 디버깅하고 싶다면 -debug를 넣어야 한다. 만약 라이브러리 용량을 줄이고 싶다면 ./configure --help를 실행하여 help 내용을 보고, 모듈을 삭제 또는 추가해야 한다.

Configuration ....... nocrosscompiler minimal-config small-config medium-config large-config full-config styles tools kernel widgets dialogs iconview workspace network canvas table xml sql releasze dll largefile stl png no-gif zlib nis cups bigcodecs x11sm xinerama xrender xftfreetype xkb
STL support ......... yes
Thread support ...... no
NIS support ......... yes
CUPS support ........ yes
Large File support .. partial
GIF support ......... no
MNG support ......... plugin (qt)
JPEG support ........ plugin (qt)
PNG support ......... yes (qt)
zlib support ........ yes
OpenGL support ...... no
NAS sound support ... no
Session management .. yes
Xinerama support .... yes
Tablet support ...... no
XRender support ..... yes
Xft support ......... yes
XKB Support ......... yes

./configure가 끝났다면 make라고 치고 커피 한잔 마시고 오면 컴파일이 다 되어 있을 것이다. 여기서 잠깐 알아야 할 것이 있다. Qt 컴파일의 최종 목적을 $QTDIR/lib에 있는 Qt 라이브러리를 얻기 위함이다. 그런데 Qt는 라이브러리를 만들고 나서 example 디렉토리에 있는 예제들을 컴파일하기 시작한다. 이 example 폴더의 컴파일 시간이 꽤 길다.
example 폴더를 컴파일하지 않기 위해서는 ./configure 후에 example 폴더를 example_ 로 바꾸면 example_ 폴더를 컴파일하지 않는다. 물론 ‘successful’이라는 결과가 나오지는 않지만 example 폴더를 제외한 나머지 필요한 다른 것들은 정상적으로 컴파일을 해서 라이브러리까지 만드는 작업까지 끝낸 상태가 된다.
이런 방법을 쓰면 “example 폴더를 찾을 수 없습니다.”라는 메시지가 나올 것이다. 그러면 성공적으로 Qt 컴파일을 한 것이다. example는 나중에 필요한 것만 컴파일하면 된다.

Qt 디렉토리 소개
$QTDIR로 이동 후 ‘ls’를 해 보면 여러 디렉토리들이 나올 것이다. 여기서 알아둬야 할 디렉토리를 몇 가지 설명하겠다.

◆ doc : Qt 클래스들의 레퍼런스가 있다. 자주 참조하게 될 것이다(시작 페이지 doc/html/index.html ).
◆ include : Qt의 모든 헤더 파일이 이 디렉토리 밑에 링크되어 있다. 만약에 삼바를 통하여 Qt 디렉토리에 접근한다면 오픈한 파일을 쓰기(write)해선 안 된다. 쓰기를 하면 링크가 파일 자체로 바뀌기 때문에 두 개의 헤더 파일이 존재하게 된다. 따라서 주의하기 바란다.
◆ src : Qt 소스가 들어 있는 곳이다. 패치를 할 경우 이곳에서 하며, 패치 후 make할 때도 $QTDIR/src에서 make하면 된다.
◆ src/moc : src 중에서도 moc라는 디렉토리는 Qt 소스가 아닌 Mete-Object_compiler 소스이다. 다음 단락에서 moc를 설명하겠다.
◆ mkspecs : 이곳에는 플랫폼에 대한 스펙들이 들어 있다. 뒤에서 설명할 qmake도 이곳을 참조하여 Makefile를 만든다.
◆ tools/designer/uic : 다음 연재 때 소개할 디자이너에서 만들어지는 ui 파일을 컴파일하는 uic의 소스가 있는 디렉토리이다.

프로젝트 파일 만들기
Qt에서는 프로젝트 파일(.pro)을 이용하여 컴파일한다. 윈도우의 경우 이 파일을 이용하여 dsp 파일을 만들고, 리눅스의 경우 Makefile을 생성한다. 하나의 프로그램을 만들 때 가장 먼저 하는 작업이므로 기본적으로 알아야 할 사항을 언급하겠다.

Sample Profile)
TEMPLATE = app
SOURCES = hello.cpp
HEADERS = hello.h
CONFIG += qt warn_on release

앞의 프로젝트 파일은 가장 기본적인 프로파일이다. TEMPLATE은 기본적인 프로그램 성격을 가리킨다. app는 일반 애플리케이션을 말한다. 이 외에 lib는 라이브러리를 만들 때 사용한다(동적, 정적 라이브러리 모두를 포함한다). SOURCES는 프로그램에서 구현한 소스 파일들을 포함한다. 하나의 파일의 경우엔 문제가 없지만 대부분의 프로그램은 다수의 소스파일들을 포함한다. 이 경우엔 다음과 같이 사용하는 것이 편하다.

SOURCES = hello.cpp
main.cpp

HEADERS는 프로그램에서 필요한 헤더 파일들을 포함한다. CONFIG에는 =가 아닌 +=를 사용했음에 주의할 필요가 있다. 그 이유는 configuration 옵션이 이미 있을 수도 있고, = 표시는 기존의 값을 대체하기 때문에 +=를 사용하는 편이 낫다.
qt는 프로그램이 Qt를 사용하고 있음을 나타낸다. 이것은 링크할 때나 컴파일할 때 인클루드 패스의 필요에 따라 Qt 라이브러리를 가져올 수 있음을 의미한다. warn_on은 컴파일할 때 warning을 출력하도록 하는 부분이고 (↔warn_off) release는 제품을 출시할 때 사용하는 옵션이다. 일반적으로 개발할 땐 debug 옵션으로 해야 디버깅을 할 수 있다. 그 밖에 staticlib 옵션을 사용하면(TEMPLATE = lib로 하였을 때) 정적 라이브러리가 만들어지고, 아무 옵션도 주지 않으면 동적 라이브러리가 생성된다.
pro 파일이 다 만들었으면 Makefile을 만들 차례다. 여기에선 $QTDIR/example/hello 프로젝트를 이용해 보겠다. VS 환경에서는 Generate Qt Project를 이용해서 dsp 파일로 변환해주면 된다. 리눅스 환경에서는 qmake를 이용하여 다음과 같이 Makefile을 만든다.

qmake -o Makefile hello.pro
‘Hello World’ 예제 컴파일
프로그램 언어를 시작할 때 항상 나오는 것이 Hello World(전체 소스 파일은 ‘이달의 디스켓’ 참조)이다. 소개를 어느 정도 마치고 나서 Hello World가 나오지 않으면 이상할 정도로 표준이 되어버렸다. 이 프로그램은 한 개의 버튼이 Hello World와 Hello Qt를 번갈아 가면서 디스플레이하도록 하는 간단하면서도 Qt의 핵심 개념을 알아볼 수 있는 예제이다. 예전엔 프로그램 언어에 레퍼런스라는 게 많지 않았다. 하지만 요즘엔 레퍼런스가 너무 잘 되어 있어 책을 참고할 일이 많이 줄어든 것이 사실이다. Qt도 여러 차례 레퍼런스에 대하여 극찬을 받은 적도 있고 상을 수상한 적도 있을 정도로 훌륭한 레퍼런스를 갖고 있다. 앞의 프로그램에서 하나하나 설명을 하지 않을 것이다. 설명하는 것보다 레퍼런스를 찾아서 한번 읽어 보는 것이 훨씬 도움이 많이 될 것이다.
<화면 3>과 <화면 4>는 Hello World 소스의 실행결과이다. 먼저 <화면 3>은 처음 실행시 윈도우 모양이고, 왼쪽 하단 버튼을 클릭하면 <화면 4>와 같이 된다. 또는 단축키를 이용하여 버튼 클릭을 대신할 수 있다.

소스 컴파일
hello.pro 파일을 qmake를 하면 Makefile이 만들어지고, 후에 make하면 컴파일이 된다. 아주 간단하다.

방법 1.
# qmake -o Makefile hello.pro
# make
하지만 make하는 과정을 살펴보기 위해 방법 2를 보자.

방법 2.
# moc moc_hello.cpp hello.h
# g++ -c hello.cpp -I/home/qt/qt-x11-free-3.1.0/include
# g++ -c main.cpp -I/home/qt/qt-x11-free-3.1.0/include
# g++ -c moc_hello.cpp -I/home/qt/qt-x11-free-3.1.0/include
# g++ -o hello hello.o main.o moc_hello.o
-Wl,-rpath,/home/qt/qt-x11-free-3.1.0/lib -L/home/qt/qt-x11-free-3.1.0/lib -lqt

여기서 말하고자 하는 것은 moc이다. 자, 그럼 이제 moc에 대해 알아보자. 그런데 moc를 알기 위해선 시그널과 슬롯에 대해 알아야 한다.

시그널과 슬롯
<그림 1>은 시그널과 슬롯에 관한 내용을 그림으로 설명해 놓은 것이다. 그림을 보면서 다음 내용을 이해하기 바란다.
시그널과 슬롯을 굳이 MFC와 비교하여 설명한다면 이벤트와 이벤트를 받는 함수와 비슷하다. MFC와 QT를 많이 다뤄본 사람은 이 말이 다르다고 말할지도 모른다. 그러나 이렇게 설명하는 것이 필자가 생각한 것 중 가장 적절한 표현이라 생각한다. 예를 들자면, 키보드의 키가 눌린 것은 시그널이고 그 키에 대한 어떠한 표현은 슬롯이라 말할 수 있다. 명칭이 익숙하지 않아 좀 어색할지 모르지만 조금만 사용해 보면 너무도 쉬운 것이 될 것이다. 다음은 시그널과 슬롯의 사용방법과 주의 사항이다.

짾 시그널과 슬롯은 클래스에서만 존재해야 하며 독립적인 함수로서 사용할 수 없다.
짿 시그널과 슬롯을 정의하려는 모든 클래스는 QObject 클래스에서 파생되어야 한다.
쨁 시그널과 슬롯을 선언하는 클래스 안에는 반드시 Q_OBJECT라는 매크로를 포함하고 있어야 한다.
쨂 시그널의 정의는 ‘signals:’ 키워드를 사용하고, 슬롯은 public slots, private slots 등으로 정의해야 한다. 다만 정적(static)으로는 만들 수 없다.
쨃 직접 작성한 시그널을 보내고 싶다면 emit라는 키워드를 사용한다.
쨄 시그널과 슬롯의 매개 변수 개수는 같아야 한다.
? 시그널과 슬롯의 연결은 QObject::connect() 메쏘드를 통해 이루어진다.
? 시그널과 슬롯의 이름은 connect() 메쏘드 안의 SIGNAL(), SLOT()의 인자로 들어간다.
? 여러 개의 슬롯이 하나의 시그널에 연결될 수 있고 그 반대로도 연결할 수 있다.

사용 방법은 이와 같다. 예제에서 사용된 문장을 보면 hello.h 파일에서 Q_OBJECT 매크로가 있으며, 한 개의 시그널과 두 개의 슬롯을 정의하고 있다. 이 시그널과 슬롯의 사용은 hello.cpp에서 사용하고 있으며, 생성자에서 connect() 메쏘드를 이용하여 연결시켜준다. connect 안의 인자를 보면 다음과 같이 되어 있다.

쮝 connect( 시그널송신자, SIGNAL(시그널), 시그널수신자, SLOT(슬롯) );

이달의 디스켓의 Hello World 소스를 자세히 보면 의심이 가는 곳이 있을 것이다. 바로 첫 번째 connect()의 ‘clicked()’ 시그널이 무엇인지 궁금할 것이다. 이 ‘clicked()’은 QPushButton 클래스의 부모인 QButton 클래스의 시그널로 정의되어 있다. 이것은 Qt 내부에서 가지고 있는 시그널이며, 버튼을 클릭했을 때 발생하는 시그널이다.

MOC
자, 이제 시그널과 슬롯에 대하여 조금 알았으니 방법 2에서 말한 moc를 알아보자. moc는 $QTDIR/bin에 있으며, 전 단락에서 설명한 것과 같이 $QTDIR/src/moc에 소스가 있다. 컴파일 과정을 보면 moc는 헤더 파일을 파싱하여 cpp 파일을 만들고 그것을 다시 g++ 컴파일러가 컴파일하여 object 파일을 만든다. 최종적으로 링크시에는 이 object 파일과 같이 링크를 해줘야 시그널과 슬롯을 연결하여 사용할 수 있으며, 에러 없이 컴파일된다. 방법 2는 moc를 설명하기 위한 과정이었고, 다음부터는 방법 1로 컴파일을 할 것이다(moc가 파싱할 때 “#if 0”과 같은 전처리 구문으로 막아놓은 곳을 제외하지 않고 파싱한다. 즉, #if 전처리 구문을 moc가 파싱할 때 무시하고 처리하므로 유의해야 한다).

예제)
[ header.h ] [ source.cpp ]
------------------------------ ------------------------------
Hello .....
{ #ifdef _USE_DOC_
Q_OBJECT void Hello::slotGetDoc()
{
#ifdef _USE_DOC_ .....
public slot: }
void slotGetDoc(); #endif
#endif
....
}
------------------------------ ------------------------------

이 경우에 _USE_DOC_를 정의하지 않고 사용한다면 에러가 발생한다. moc가 헤더 파일에 #ifdef _USE_DOC_를 무시하기 때문이다(“-Wl, -rpath, $DIRECTORY” 옵션은 어떤 특정한 프로그램이 컴파일될 때 실시간으로 라이브러리의 패스를 정해주는 역할을 한다).
이제 Qt 중급 프로그래머!
Qt의 장점을 가능한 부각시키면서도 Qt를 처음으로 접하는 사람들에게 쉽게 접근하기 위해 설명하려고 노력했다. ‘시작이 반이다.’라는 글과 함께 연재를 시작했는데 독자들이 느끼기에는 반을 넘어서 새로운 도전으로 받아들여줬으면 하는 바람이다. 다음 연재에서는 Qt에서 사용하는 컨트롤들을 자세히 다루어볼 생각이다. 독자들이 많이 요구하는 컨트롤에 대하여 자세히 설명했으면 한다. 그러기 위해서는 독자 여러분들의 의견이 있었으면 한다.
아쉽게도 검색엔진에서 Qt라고 치면, 전혀 엉뚱한 내용만 나오는 것을 확인할 수 있다. 이는 개발자 층이 폭넓지 않은 이유가 가장 크겠지만, 개발자들을 모을 수 있는 구심점 역할을 하는 커뮤니티의 부재가 더 큰 문제라고 생각한다. 유일하게 Q&A로 간신히(!) 커뮤니티를 유지하는 곳이 바로 Qt 센터(http://www.qtcenter.co.kr)이다. Qt 개발자로서 이는 참으로 안타깝다고 할 수 밖에 없는 상황이다. 이 연재를 통해서 많은 Qt 개발자들이 하나로 뭉쳤으면 하는 바람을 가지고 이 사이트를 소개해 본다. 이번 연재의 내용 중 궁금한 사항이나 옳지 않았던 내용이 있으면 QA 게시판에 글을 올려주길 바란다. 성심성의껏 답변하도록 최선을 다하겠다.

정리 | 강경수 | elegy@korea.cnet.com




[ Qt를 만든 트롤테크 ]
트롤테크(http://www.trolltech.com)는 노르웨이 오슬로라는 지역에 본사를 두고 있다. 75명 중에 약 절반이 개발자이며, 특이할 만한 사실은 회사 홈페이지에서도 나와 있듯이 자신들을 특이한 회사(An Unusual Company)라고 소개하고 있다는 점이다. 그 이유를 살펴보면, 먼저 많지 않은 직원들이 17개국 출신이라는 점과 비즈니스 모델을 오픈소스 영역에 이익을 주는 방향으로 잡고 있다는 점을 내세우고 있다.
이 회사는 크게 두 가지의 소프트웨어를 개발한다. 하나는 멀티 플랫폼에서 돌아가는 애플리케이션 개발 환경을 제공하는 것이고, 다른 하나는 PDA나 모바일 장치에 들어가는 임베디드 리눅스 애플리케이션 플랫폼을 제공하는 것이다.
‘하나의 소스를 가지고 여러 플랫폼에서 별다른 수정 없이 프로그램을 돌린다!‘ 이것이 트롤테크의 기본 모토이다. 윈도우, 리눅스, Mac OS X, 임베디드 리눅스 등 여러 플랫폼에서 하나의 소스를 가지고 컴파일만 다시 해서 실행시킬 수 있다는 것 자체가 놀라움이다. 윈도우와 리눅스가 서로 극과 극의 환경에 있다고 해도 과언이 아닐텐데, 이를 가능하게 해 주는 것이 Qt이고 Qt가 가지고 있는 가장 큰 특징이라고 할 수 있다.

[ Hello World 소스의 상세 설명 ]
이달의 디스켓에 수록된 Hello World 예제 중 중요한 부분을 설명한다.

(main.cpp)7 QApplication a(argc,argv);
모든 Qt 응용 프로그램은 QApplication이란 객체 하나를 꼭 갖고 있어야 한다. 이 객체가 하는 역할은 MFC의 winapp와 비슷하다. 메인 이벤트 루프, 즉 모든 이벤트 운용을 책임지고 있고 이러한 이벤트들을 각각 관리한다. 애플리케이션의 초기화와 종료를 책임지고, 시스템과 애플리케이션 셋팅에 관한 모두를 처리한다. 이 객체를 가리키는 글로벌 포인터인 qApp를 통해 접근 가능하다. Qt에서 제공하는 유일한 글로벌 포인터이다. 그 밖에 응용 프로그램에 스타일을 지정하거나, 국제화 지원에 대한 세팅, 클립보드나 데스크톱의 크기 등과 같은 객체에 대한 제공도 한다. 주의할 사항이 있다면, 이 객체는 초기화하는 작업이 많으므로 유저 인터페이스 관련된 객체가 생성되는 것보다 먼저 생성되어야만 한다는 것이다. 또한 커맨드 라인 인수를 이 객체의 생성자로 받아서 처리하므로 응용 프로그램이 커맨드 라인 인수를 해석하여 처리해야 한다면 이 객체를 통해서 처리하는 것이 옳다.

(main.cpp)15 a.setMainWidget( &h );
애플리케이션의 메인 위젯을 정의하는 부분이다. 메인 위젯이 종료 됐을 때 애플리케이션 실행이 끝난다는 것을 제외하면, 메인 위젯은 다른 위젯과 다를 게 별로 없다. 이 메쏘드를 사용하지 않고 다음과 같이 쓸 수도 있다.

a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
이 부분을 하지 않으면, 프로그램을 창을 닫아서 종료시켜 눈에서 사라졌을지 몰라도 메모리에는 여전히 종료되지 않은 상태로 남아있게 된다.

(main.cpp)19 return a.exec();
메인 이벤트 루프로 들어가는 역할을 한다. 이 메인 이벤트 루프는 필요한 모든 이벤트를 윈도우 시스템으로부터 가져와 해당 이벤트가 필요한 위젯으로 보내지게 된다. 이 때 위젯은 각각 자신이 처리해야 할 작업을 알고 있으므로 QApplication 객체는 이벤트만 보내주면 되므로 이에 대한 코드는 따로 필요하지 않다. exec() 메쏘드를 호출하기 전에 메인 이벤트 루프를 사용하는 위젯은 사용이 불가능하지만 메시지 박스와 같이 로컬 이벤트 루프를 사용하는 경우엔 exec() 메쏘드 호출 전에 사용될 수 있다. 이 메쏘드는 exit() 호출되거나 메인 위젯이 종료될 때까지 기다리고 해당 종료값을 반환한다.

(hello.h)8 class Hello : public QWidget
QWidget은 유저 인터페이스 객체들의 기반 클래스이다. MFC의 CWnd 클래스와 비슷한 역할을 한다고 생각하면 이해하기 쉽다. Qt에서 대부분의 클래스는 이 QWidget으로부터 상속받는다. 마우스나 키보드, 기타 윈도우 시스템으로부터 받는 이벤트들을 받아서 처리할 수 있으며, 자기 자신을 리페인트 처리하는 역할도 한다. 이 밖에 크기 변경, 위치 변경에 대한 정보를 얻을 수 있도록 해준다.

QWidget( QWidget * parent = 0, const char * name = 0, WFlags f = 0 )
위젯 생성자는 두 개 혹은 세 개의 인자를 받는다. 첫 번째 QWidget * parent = 0은 새로운 위젯의 부모를 가리킨다. 디폴트 값(0)일 경우엔 부모가 없게 되므로 자신이 탑-레벨 윈도우가 된다. 부모가 지정되면, 그 부모의 자식이 되고 부모의 좌표체계에 종속받게 된다.
const char *name = 0은 위젯의 이름을 가리킨다. WFlags f = 0은 위젯 플래그 값을 셋팅한다. 이 위젯 플래그 값을 통해 탑-레벨 윈도우를 만들거나, 타이틀 바가 없거나 보더가 없는 위젯들을 만들 수 있다.

(hellp.cpp)65 void Hello::paintEvent( QPaintEvent* )
위젯이 리페인트 될 필요가 있을 때(위젯이 페인트 이벤트를 받게 될 때) 불려지는 메쏘드이다. 페인트 이벤트는 위젯의 전부나 일부를 다시 그려달라는 요청을 말한다. 이 이벤트는 repaint()나 update()로서 발생될 수 있다. 화면에 무언가를 그리거나 보여주기 위해서는 이 메쏘드를 반드시 구현해야만 한다.

(hello.cpp)18 m_pPushButton = new QPushButton( this );
가장 많이 사용되는 유저 인터페이스 클래스 중에 하나일 것이다. 이 버튼을 클릭하면 click이라는 시그널을 발생시키게 되고, 발생된 시그널을 슬롯과 연결하여 수행하고자 하는 명령을 처리하게 된다. 대부분의 유저 인터페이스 클래스가 이처럼 동작하게 된다.
버튼 관련된 클래스는 QButton으로부터 상속을 받게 되고, 이 QButton 클래스 역시 QWidget으로부터 상속을 받는다. 누누이 강조하지만, QWidget 클래스로부터 대부분이 파생된다는 걸 잊지 말아야 한다. 이와 같이 QPushbutton은 MFC에서 말하는 컨트롤에 가깝다고 할 수 있고, QWidget은 컨테이너 클래스로 보면 쉽게 이해가 갈 것이다.
프로그램을 개발하다 보면, API가 제공해주는 모양 그대로 사용하는 일이 많지는 않을 것이다. 버튼의 경우도 디폴트로 제공하는 모양 위에 비트맵을 올리는 경우가 많다. Qt에서는 이런 작업을 간단한 메쏘드 하나로 해결할 수 있다(setPixmap()을 이용하면 된다),

QString nextStr( “&Hello World” ); m_pPushButton->setText( nextStr );
이처럼 Hello의 H 앞에 & 기호를 붙여주면 간단하게 를 눌렀을 때 이 버튼을 클릭되는 효과를 볼 수 있다.방금 말한 2가지 방법은 Qt가 프로그램을 구현하는 데 있어서 편리한 점을 알 수 있다. 필요한 기능을 구현해야 하는 일이 발생하는 일은 부지기수로 많을 것이지만, 편리한 기능을 담고 있는 메쏘드가 많기 때문에 Qt의 매력에 쉽게 빠질 것이다.

setGeometry(), setFixedSize(), setFont(),
setPaletteBackgroundColor(), setPaletteForegroundColor() 메쏘드 등은 레퍼런스를 참고하길 바란다. 대부분의 클래스가 이 QWidget으로부터 상속을 받으므로, 메서드를 한 번씩 훑어보는 것도 Qt 프로그램을 하는 데 도움이 될 것이다.
Posted by 용학도리
,