Kylix Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
카일릭스 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
자유게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

카일릭스 강좌/문서
[2] QT Programing (2) - 기본적인 QT Programming
문의형 [] 10268 읽음    2002-05-08 03:17
  • Hello World

  • 모든 Programing 언어나 FrameWork을 공부할때 맨처음 하게 되는 Program이 Hello World 라는 문자열을 출력하는 것입니다.

    이 연재에서도 첫 Program으로 Hello World를 만들어 볼 것입니다. QT로 작성한 Hello World는 다음과 같습니다.



    1 #include <qapplication.h>
    2 #include <qlabel.h>
    3
    4 int main(int argc , char *argv[]){
    5 QApplication a(argc , argv);
    6 QLabel hello("Hello World!!" , 0);
    7
    8 a.setMainWidget(&hello);
    9 hello.show();
    10
    11 return a.exec();
    12 }



    위의 내용을 hello.cpp에 저장하고 Shell에서 다음의 순서로 합니다.



    [root@localhost qt]# progen -o hello.pro hello.cpp



    위의 명령어로 hello.pro라고 하는 Project File이 생성이 됩니다.
    만약 QT를 설치할때 여기에서와 같이 -thread Option을 주었다면 위의 hello.pro 를 수정할 필요가 있습니다.



    ◎ hello.pro 의 원본

    TEMPLATE = app
    CONFIG = qt warn_on release
    HEADERS =
    SOURCES = hello.cpp
    INTERFACES =



    위의 내용중에서 두번째 줄의 CONFIG의 값에 thread를 추가 시킵니다.



    ◎ 수정된 hello.pro

    TEMPLATE = app
    CONFIG = qt thread warn_on release
    HEADERS =
    SOURCES = hello.cpp
    INTERFACES =



    이후에 계속해서 tmake를 실행 합니다.



    [root@localhost qt]# tmake -o Makefile hello.pro
    [root@localhost qt]# ls
    Makefile hello.cpp hello.pro



    위의 과정을 살펴 보면 먼저 progen을 사용하여 Project File(hello.pro)을 생성하고 두번째 에서는 생성된
    Project File을 수정하고 세번째로 tmake를 사용하여 hello.pro에 정의된 내용을 참조하여 Makefile을 생성합니다.
    그러면 이후에는 이 Makefile을 이용하여 Compile하면 됩니다



    [root@localhost doc]# make
    g++ -c -pipe -Wall -W -O2 -D_REENTRANT -DQT_THREAD_SUPPORT -DNO_DEBUG -I/usr/local/qt-x11-free-3.0.1/include -o hello.o hello.cpp
    g++ -o hello hello.o -L/usr/local/qt-x11-free-3.0.1/lib -L/usr/X11R6/lib -lpthread -lqt-mt -lXext -lX11 -lm
    [root@localhost doc]# ls
    Makefile* hello* hello.cpp* hello.o* hello.pro*
    [root@localhost doc]#



    자 앞의 과정들을 살펴 보면 다음의 순서로 Programing 한다는 것을 알 수 있습니다.



    Source Coding -> progen -> Project File 수정 -> tmake -> make



    그리고 Compile된 결과물을 실행 시키면..



    [root@localhost qt]# ./hello



    위와 같은 결과를 볼 수 있습니다.

    그럼 이제 왜 위와 같은 결과가 나오는 것인가 하는 것을 짚어 보겠습니다.

    1번째 줄에서 qapplication.h를 Include하는 항목이 있는데 이것은 QT를 이용한 GUI Application을 작성할때 항상 include해야 합니다. 그리고 두번째 줄에서는 qlabel.h를 Include하는데 이것은 Label을 사용하기위한 Include입니다.

    그리고 main함수의 5번째 줄에서 QApplication형으로 a를 초기화 하는데 QApplication에서는 main함수의 인자인 argc와 argv를 인자로 받습니다.

    6번째 줄에서는 QLabel형으로 hello를 초기화 하는데 QLabel에서는 Label에 기본적으로 표시할 문자열과 해당 객체의 Parent를 지정합니다.(일반적으로 Parent는 해당 Component가 포함되어 있는 Widget을 지정하는데 여기에서는 Label 하나만 존재하고 그 Label이 다른 Component에 포함되어 있지 않으므로 0, 즉 최상위 Widget이라고 지정합니다.)

    8번째 줄에서 a의 Main Widget , 즉 이 GUI 프로그램에서의 Main Component를 hello로 지정하기 위해 그 주소값을 인자로 넘겨주고 hello.show()를 통해 해당 Component를 하면에 표시합니다. 이때 이 GUI 프로그램의 크기를 지정하지 않았으므로 해당 Component를 표시할 수 있을 정도로 크기가 조절됩니다.

    11번째 줄에서 이 GUI Application의 실행에 대한 값을 반환하고 프로그램이 종료합니다.



    ※ 참고
    QT Refrence는 QT를 설치한 Directory아래에 doc/html/index.html에서 찾아 볼 수 있습니다.
    (예를 들어 /usr/local/qt-x11-free-3.0.1/doc/html/index.html)

    이 문서에서는 검색 기능이 없고 원하는 Class와 그에 포함 되어 있는 멤버함수를 찾아 보기 위해서는 API Refrence에서 찾아 보면 됩니다.

    예를들어 QApplication 객체에 대해서 알아 보려면

    QT Refrence -> API Refrence -> All Classes -> QApplication

    의 순서로 찾아 보면 됩니다. 즉 Netscape이나 Konqueror같은 Web Browser를 이용하여
    주소표시줄에 file:///usr/local/qt-x11-free-3.0.1/doc/html/index.html
    로 찾아간 후 여기에서 API Refrence(왼쪽 중간)에서 All Classes를 Click하면 모든 QT Class들이 알파벳 순으로 출력되고
    거기에서 원하는 Class를 Click하면 자세한 설명을 볼 수 있습니다.


  • 두번째 Program

  • 앞의 Hello World는 단지 Label을 화면에 출력 하는 것 뿐 아무런 기능을 하지 않습니다. 이번에는 복수개의 Component를 포함하는 프로그램을 작성하고 버튼을 Click했을때 Program을 종료하도록 하겠습니다.



    1 #include <qapplication.h>
    2 #include <qpushbutton.h>
    3 #include <qlabel.h>
    4
    5 #define kor(str) QString::fromLocal8Bit(str)
    6
    7 int main(int argc , char *argv[]){
    8 QApplication a(argc , argv);
    9 QWidget widget;
    10
    11 QLabel label(kor("라벨이라~~~~~네!!") , &widget);
    12 label.setGeometry(50 , 10 , 100 , 30);
    13
    14 QPushButton quit(kor("쫑~") , &widget);
    15 quit.setGeometry(50 , 50 , 100 , 30);
    16
    17 widget.setGeometry(200 , 200 , 200 , 100);
    18
    19 QObject::connect(&quit , SIGNAL(clicked()) , &a , SLOT(quit()));
    20
    21 a.setMainWidget(&widget);
    22 widget.show();
    23
    24 return a.exec();
    25 }



    먼저 5번째 줄에서는 QT에서 2Byte문자를 사용하는 것을 보여 주고 있는데, QT에서 Label이나 Button 등에서 한글을 사용하고자 할 때에는 QString Class의
    fromLocal8Bit() Method를 사용하기 위해 다음과 같이 사용합니다.



    QString::fromLocal8Bit("문자열");



    Component등에서 사용할 때에는



    QLabel label(fromLocal8Bit("라벨이라~~~네!!") , &widget);



    위와 같이 사용하게 됩니다. 얼핏 보기에도 좀 길고 보기가 불편 하다는 것을 알 수 있죠.. 그래서 5번째 줄에서 kor(str) 이라는 함수로 줄여 놓았습니다.

    9번째 줄에서 QWidget 형으로 widget이라는 변수를 선언 하고 있는데, 첫번째 프로그램에서는 만들고자 하는 GUI Program에 포함 되는 Component가 하나 밖에 없으므로 이것을 Main Widget으로 만들면 되었는데 두번째 프로그램에서는 Component가 두개 입니다. 이러한 경우에는 Component들을 어딘가에 붙여 놓는 방식을 사용하게 되는데. 이때 Component들을 붙일 목적으로 사용되어지는 Class가 바로 QWidget입니다. 그러므로 이후에 오는 Component들은 여기에 붙이게 됩니다.

    11번째줄의 QLabel은 첫번째에서 보았던 것과 약간 달라지는데 먼저 기본적으로 표시할 문자열을 kor("라벨이라~~~~네!!") 라고 했는데 kor() 함수는 앞의 5번째 줄에서 2Byte문자를 사용하기 위해 정의한 함수라고 했습니다. 즉, QT에서 한글을 사용하기 위해서는 이와 같이 사용하면 됩니다. 그리고 두번째 인자(이 Component를 포함시킬 Parent)에 &widget 이라고 하는 것은 앞서 설명 한것과 같이 이 Component를 포함시킬 Parent를 QWidget형의 주소값을 넘겨 주고 있습니다. 즉 이 Component를 widget에 포함 시키겠다는 것입니다.

    14번째 줄의 QPushButton형의 button역시 QLabel과 같은 방식으로 사용되어 지고, 19번째 줄의 QObject::connect()는 QT의 중요한 기술 중 하나인 SIGNAL과 SLOT인데 이것에 대한 것은 이 후에 따로 다룰 것이므로 여기에서는 Button을 Click하면 프로그램이 종료 한다는 것만 알아 두면 됩니다.

    21번째 줄에서는 Main Widget을 widget으로 지정하고 22번째 줄에서 이것을 화면에 출력하고 있습니다.

    QT에서는 GUI Program의 Component들을 정렬할 때 두가지 방식을 사용하고 있는데 먼저 하나는 각각의 Component들의 위치와 크기를 지정하는 것이고 두번째 방식은 Layout Manager를 사용하는 것인데, 이 프로그램에 사용하고 있는것은 전자의 방식이며 이러한 방식은 해당 Component객체의 setGeometry() Method를 호출함으로써 사용되어 지고, Layout Manager는 Component들을 정렬할 방식을 미리 정의하고 그에 따라 Component를 정렬하는 방식인데 이것 역시 이 후에 다시 자세히 보도록 하겠습니다.

    12 , 15 , 17 번째 줄에서 각각 사용하고 있는 setGeometry() Method는 모두 QWidget에서 상속받은 Method로써 Component의 크기와 위치를 지정하게 됩니다.
    이 함수의 원형은 다음과 같습니다.



    void QWidget::setGeometry(int x , int y , int w , int h)



    각각의 인자는 먼저 해당 Component의 위치를 나타내는 x , y 그리고 Component의 크기를 나타내는 w , h 가 있습니다.

    12번째 줄의 label.setGeometry(50 , 10 , 100 , 30)은 widget의 원점에서 가로 50 , 세로 10의 위치에 가로 100 , 세로 30크기로 Label을 표시하는 것이고, 15번째 줄의 quit.setGeometry(50 , 50 , 100 , 30)은 widget의 원점에서 가로 50 세로 50 의 위치에 가로 100 세로 30의 크기로 Button을표시하는 것입니다.

    그렇다면 17번째 줄에서의 widget.setGeometry(200 , 200 , 200 , 100)은 무엇을 뜻할 까요?
    widget은 이 GUI응용 프로그램에서 Main Widget입니다. Main Widget은 Parent가 자기 자신입니다. 이러한 Component에서 setGeometry는 처음 응용프로그램을 실행할 때의 위치와 응용프로그램의 크기를 지정하는 것이 됩니다.

    위의 응용프로그램을 실행 시키면 항상 같은 위치에서 실행 되는 것을 알 수 있습니다.

    전반적인 흐름을 보면

    Component들을 붙일 QWidget객체를 생성하고(9 Line) Label (11 Line) , Button(14 Line)을 각각 wiget에 포함 시킬 것으로 생성하고 Button을 Click하면 프로그램이 종료하도록 하며(19 Line) Component들을 포함하고 있는 widget을 Main Widget으로 하여(21 Line) 이것을 화면에 표시(22 Line)하고 있습니다.

    ※ 참고

    응용 프로그램을 화면의 중앙에 표시하고자 한다면 다음과 같이 합니다.



    QWidget *desktop =QApplication::desktop(); //Desktop의 정보
    int dx = desktop->width(); //Desktop의 가로 크기
    int dy = desktop->height(); //Desktop의 세로 크기
    int w = 200; //Widget의 가로 크기
    int h = 100; //Widget의 세로 크기

    widget.setGeometry( (dx - w) / 2 , (dy - h) / 2 , w , h);



    Component의 크기를 고려 해야 하기 때문에 dx / 2 또는 dy / 2가 아니라 (dx - w)/2 와 (dy - h)/2 가 됩니다.

  • OOP 답게 Programing해보자

  • 앞으로의 예제들은 대부분 main 함수와 실제 일을 수행하는 Class들로 구분 할 것이며 이것이 좀더 OOP 다울 것입니다. 이번 예제는 두번째 예제와 하는 일이 모두 같고 결과 또한 같습니다.



    1 #include <qapplication.h>
    2 #include <qlabel.h>
    3 #include <qpushbutton.h>
    4 #include <qwidget.h>
    5
    6 #define kor(str) QString::fromLocal8Bit(str)
    7
    8 class Oop : public QWidget{
    9 public:
    10 Oop();
    11
    12 private:
    13 QLabel *label;
    14 QPushButton *quit;
    15 };
    16
    17 Oop::Oop(){
    18 setGeometry(200 , 200 , 200 , 100);
    19 setCaption(kor("OOP 답게~"));
    20
    21 label = new QLabel(kor("라벨이라~~~~네!!") , this);
    22 quit = new QPushButton(kor("쫑!!") , this);
    23
    24 label->setGeometry(50 , 10 , 100 , 30);
    25 quit->setGeometry(50 , 50 , 100 , 30);
    26
    27 connect(quit , SIGNAL(clicked()) , qApp , SLOT(quit()));
    28 }
    29
    30 int main(int argc , char *argv[]){
    31 QApplication a(argc , argv);
    32
    33 Oop *oop = new Oop();
    34 oop->show();
    35
    36 return a.exec();
    37 }



    몇가지 추가적인 것을 설명 하자면, 먼저 이전에는 QWidget형의 객체를 생성했지만 여기에서는 Oop라는 Class에서 QWidget을 상속을 받고 있습니다. 그렇게 때문에 widget.setGeometry()의 형식이 아니라 그냥 setGeometry()와 같이 사용하고 있습니다.

    그리고 19번째 줄에서 setCaption()은 응용프로그램에 제목을 표시하는 부분인데 앞의 두 응용프로그램의 제목은 해당 File이름과 같은 것을 볼 수 있었을 것입니다.

    이 Oop라는 Class의 생성자에서 GUI처리를 모두 하고 있기 때문에 main함수의 크기가 줄어든 것을 볼 수 있을 것입니다.

    일반적인 경우에는 맨 앞의 include 와 Class선언 부분은 .h File 즉 Header파일에 기록하고 나머지를 .cpp File 즉 Source에 기록하는 방식을 사용합니니다 위의
    파일을 이러한 방식으로 나누어 보면..



    ◎ oop.h

    1 #ifndef __OOP__
    2 #define __OOP__
    3
    4 #include <qapplication.h>
    5 #include <qlabel.h>
    6 #include <qpushbutton.h>
    7 #include <qwidget.h>
    8
    9 #define kor(str) QString::fromLocal8Bit(str)
    10
    11 class Oop : public QWidget{
    12 public:
    13 Oop();
    14
    15 private:
    16 QLabel *label;
    17 QPushButton *quit;
    18 };
    19
    20 #endif // __OOP__





    ◎ oop.cpp

    1 #include "oop.h"
    2
    3 Oop::Oop(){
    4 setGeometry(200 , 200 , 200 , 100);
    5 setCaption(kor("OOP 답게~"));
    6
    7 label = new QLabel(kor("라벨이라~~~~네!!") , this);
    8 quit = new QPushButton(kor("쫑!!") , this);
    9
    10 label->setGeometry(50 , 10 , 100 , 30);
    11 quit->setGeometry(50 , 50 , 100 , 30);
    12
    13 connect(quit , SIGNAL(clicked()) , qApp , SLOT(quit()));
    14 }
    15
    16 int main(int argc , char *argv[]){
    17 QApplication a(argc , argv);
    18
    19 Oop *oop = new Oop();
    20 oop->show();
    21
    22 return a.exec();
    23 }



    위와 같이 두개의 File로 나눠 볼 수 있고 이러한 식으로 파일이 두개 이상인 경우에는 progen을 실행 할때 해당 파일들을 모두 명시 해야 합니다.



    [root@localhost qt]# progen -o oop.pro oop.h oop.cpp
    [root@localhsot qt]# tmake -o Makefile oop.pro



    다음 시간에는 Layout Manager에 관한 이야기를 하겠습니다.



    + -

    관련 글 리스트
    2 QT Programing (2) - 기본적인 QT Programming 문의형 10268 2002/05/08
    Google
    Copyright © 1999-2015, borlandforum.com. All right reserved.