QT/X11 2.x.x 버전 대에서 QT Designer를 사용했을 때에는 많이 실망했습니다. 정말 디자인 기능뿐이 없구나 할 정도로 기능이 미약했습니다. 가장 큰 단점은 폼을 디자인하는 중에 코딩을 할 수 없다는 점이 었습니다.

폼, Form Micorsoft Windows Applicatoin 개발 툴 중에 델파이가 있습니다. 지금까지도 저의 주력 개발툴입니다. 델파이에서는 만들려고 하는 윈도우를 Form(폼) 이라고 부릅니다. 윈도우 프로그램에서는 열리는 창 하나하나가 모두 윈도우이고 그 윈도우는 프로그래머에 의해서 일단 모양이 만들어 지는데, 만들어지는 과정의 윈도우를 Form이라고 부릅니다.

글을 작성하면서 습관적으로 폼이라는 단어를 사용할지 모르겠습니다. 또한 디자인되는 윈도우를 폼이라고 부르는 것이 다른 윈도우와 구별도 되기 때문에 말씀 드리기에도 편하기 때문입니다.

디자인은 프로그램이 업그레이드되면서 계속 바뀔수 있는 부분입니다. 제가 잘 알지 인지 모르겠습니다만, QT 2.x.x 버전 대의 QT Designer에서는 위젯들을 배열하고, 그 위젯에서 마우스 클릭과 같은 이벤트가 발생하면, 그 이벤트에 대해 어떻게 처리할 지에 대한 슬롯을 지정해 주는 것 뿐이었습니다.

디자인 후에 만들어 지는 것이 ***.ui 파일입니다. 이 파일에서 ****.cpp 파일과 ****.h 파일이 생성되구요. 문제는 이 파일을 가지고 이벤트를 처리하는 코드를 이 소스에 넣게 됩니다. 물론 외부 모듈에 함수를 구성할 수 있지만, 아무리 최소한으로 작업을 한다고 해도 ***.ui에서 만들어진 cpp 파일을 편집하지 않을 수 없습니다.

이 상태로 프로그램이 완성되면 다행입니다만 다시 폼을 수정해야 한다면, 그래서 ***.ui 파일이 갱신되고 다시 ***.cpp와 ***.h를 만들어야 된다면 또 다시 ***.cpp의 내용을 수정해 주어야 합니다

이벤트, 이벤트 핸들러, 슬롯

Micorsoft Windows에서는 마우스 클릭과 같은 외부 입력 발생을 Event라고 부릅니다. Evnet 종류가 매우 많겠지요. 다양한 Event에 대해서 프로그램마다 처리하는 방법이 프로그램의 목적에 따라 모두 다릅니다. 이렇게 프로그램에서 특정 이벤트가 발생하면 어떻게 처리하겠다라고 지저한 멤버함수를 이벤트 핸들러라고 부릅니다.

이벤트 핸들러에 대해서 리눅스에서는 슬롯이라는 단어를 사용하는 군요. 서로 통일했으면 좋겠는데, 자꾸 새로운 단어가 만들어지니까 저같이 머리 나뿐 사람은 자꾸 머리 나뿐 탓을 하게 됩니다. ^^ ;

처음에 저는, 저의 학습 부족을 탓했습니다. 이런 불편이 뻔히 보이는데 QT에서 과연 이렇게 만들었을까 말이죠. 그래서 QT 디자이너 이곳저곳을 뒤져 보고 웹 검색을 해 보았지만 역시 슬롯에 대한 코딩하는 부분을 찾을 수 없었습니다.

왜 폼 디자인 파일을 하나로 처리했을까? 디자인 부분과 코딩 부분을 나누어서 따로 파일을 분리해서 처리했다면 좋았을 텐데 하는 생각에 매우 아쉬워 했습니다.

이번에 QT를 다시 설치하면서 디자이너를 다시 확인해 보았습니다. 그러나 안타깝게도 이전 모습과 똑 같더군요. 혹시 QT 2.x.x 버전의 디자이너에서도 슬롯에 프로그램 코드를 넣을 수 있나요?

이런 이유로 저는 C++ 언어이니까 TfrmMain을 디자이너로 만들고 사용자 슬롯을 지정해 준 후에, 이 TfrmMain을 상속 받고, 그 상속 받은 소스에서 슬론 프로그램 코드를 넣었습니다. 디자이너로 수저앟면 TfrmMain만 수정되니까요. 그러나 역시 번거롭죠.

그러나 !!

QT 3.x.x 버전의 디자이너에서는 코드를 따로 분리해서 넣을 수 있군요!! 아~ 이렇게 반가울 수가!!.

일단 제가 왜 이렇게 좋아하는지 알아 보기 위해, 또한 이곳은 포럼이기 때문에 QT 2.x.x의 디자이너 사용법을 간다히 말씀 드리고 QT 3.x.x 버전의 QT 디자이너에 대한 말씀을 올리겠습니다. QT 2.x.x 버전 대를 사용하지 않는 분이라도 가벼운 마음으로 읽어 주시면 감사하겠습니다. 또한 틀린 내용이 있으면 소중한 지적의 말씀도 아울러 부탁드립니다.

QT 2.x.x 디자이너

버튼이 달랑 하나있고, 버튼을 클릭하면 종료하는 프로그램을 만들어 보겠습니다.

  1. File 메뉴 >> New 메뉴 클릭
  2. Dialog 를 선택

생성할 위젯을 소스로 만들기 위해서는 Class 이름을 지정해 주어야 합니다.
즉, 내 프로그램에서 폼을 생성해서 화면에 출력해 주려면 그 폼에 대한 클래스 이름이
필요합니다. 그러므로 폼에 대한 적당한 Class 이름부터 지정해 줍니다.

  1. Edit 메뉴 >> Form Settings 메뉴 클릭
    1. Calss Name 에 클래스 이름을 입력: TfrmMain
    2. Comment와 Author에 적적한 문장을 넣어 준다.
      여기서 입력한 문장은 디자인 파일에만 저장되며,
      소스 파일에는 주석에도 반영되지 않습니다.

  2. 좌측의 속성창에서 아래의 속성을 변경
    1. name -> frmMain
    2. caption -> form - TfrmMain

  3. QPushButton 을 폼에 배치한 후, 속성을 변경합니다.
    1. name -> btnClose
    2. text -> 종료


버튼을 클릭하면 윈도우가 종료되도록 하고 싶습니다. 즉, 버튼 클릭 시그널이 발생하면 윈도우가 종료되도록 슬롯을 지정해 줍니다.

  1.       F3 키를 누르거나 화살표 키 옆에 있는 빵깡과 파랑으로 촌스럽게 그려진 알약 버튼
     클릭합니다.
  2. 버튼을 마우스로 누른 상태에서 폼 쪽으로 드래그한 후에 마우스 버튼을 놓습니다.


  3. 시그널과 스롯을 연결해 주는 대화상자가 출력이된다.


    btnClose 에서 clicked() 를 선택하고 frmMain 의 accept() 슬롯을 클릭하면 하단에, Connections: 에 시그널과 슬롯이 연결된 모습을 보여 준다.

  4. 이제 파일을 저장합니다. 위젯 이름과 같은 파일명을 사용해도 되므로, frmMain 으로 저장합니다.

이제 Makefile 을 만들고 컴파일을 하면 될까요? 아닙니다. C 언어의 실행 입구인 main() 함수가 없습니다. 우리가 만든 TfrmMain을 생성해서 화면에 출력해 주는 main() 함수를 만들어야 합니다.

  1. main() 함수 작성
    main.cpp
    #include <qapplication.h>
    #include "frmMain.h"
    
    int main( int argc, char **argv)
    {
      QApplication app( argc, argv);
    
      TfrmMain frm;
      app.setMainWidget( &frm);
      frm.show();
    
      return app.exec();  
    }
    

예전에는 uic를 이용해서 직적 frmMain.ui 파일에서 frmMain.cpp와 frmMain.h를 만들어야 했습니다. 그러나 최근에는 qmake 한 방이면 끝입니다. ^^
또한 앞서 "QT - Makefile 만들기" 글에서 말씀 드렸듯이 pro 파일과 Makefile을 만들기 위해 progen과 tmake를 사용할 필요가 없습니다. 그냥 qmake만 있으면 됩니다. 아이쿠 편해라....^^

qmake -project -o sample.pro를 실행하여 프로젝트 파일을 만듭니다.

  1. ]# qmake -project -o sample.pro

만들어진 sample.pro를 vi로 열어서, TARGET = 행을 추가해서 앞으로 만들어질 실행파일의 이름을 지정합니다.

TARGET = show_form

프로젝트 파일에서 Makefile을 생성하고 make를 실행하여 실행파일을 생성합니다.

  1. ]# qmake
  2. ]# make

이때, 실행파일이 만들어지기 전에 frmMain.ui 파일에서 frmMain.cpp와 frmMain.h 파일이 만들어지고 이후 컴파일 과정을 거쳐서 실행파일이 생성됩니다.

2.x.x QT 디자이너의 문제

이번 예제에서는 윈도우가 종료되는 슬롯을 TfrmMain이 가지고 있기 때문에 무리없이 처리할 수 있었습니다. 그냥 시그널과 슬롯을 연결하면 되니까요.

그러나 종료가 아니라 어떤 경고 메시지를 출력해야 한다면 어떻게 해야 될까요?

경고 메시지를 출력하는 슬롯은 TfrmMain에 없습니다. 프로그래머가 직접 코드를 넣어 주어야 하는데, QT 디자이너 안에서 코드를 넣을 방법이 없습니다.

그러므로 하는 수 없이 frmMain.ui에서 만들어진 frmMain.cpp의 내용을 수정해야 됩니다. 그러나 이렇게 되면 다음 make의 실행으로 애써 넣은 코드가 사라지게 됩니다.

폼 상속 코딩 방법

디자인 파일이 변경되면 함께 변경되는 fmrMain.cpp 파일 대신에 TfrmMain을 상속 받아서 사용하는 방법에 대해 말씀을 드립니다.

우선 사용자 슬롯함수를 만들고 버튼의 시그널을 연결하겠습니다. QT 디자이너에서 사용자 슬롯함수를 선언합니다.

  1. Edit 메뉴 >> Slots... 메뉴를 선택


  2. Slot Properties 에 슬롯함수의 함수명을 적습니다. 여기에서는 OnBtnCloseClicked() 라고 적었습니다.



  3. 이제 F3 키를 누르거나 빨강/파랑 알약버튼을 클릭하고, 마우스 버튼을 드래그한 후에 폼에서 마우스를 놓습니다.


  4. frmMain 의 슬롯함수 목록에서 OnBtnCloseClicked()를 선택합니다.

여기서 재미있는 것은 Signal 에 대해서 슬롯을 하나 이상을 지정할 수 있다는 점입니다. Signal에 대해서 슬롯을 여러 개 지정해 놓으면 지정된 슬롯함수 모두 수행이 됩니다. 그러므로 btnClose 의 clicked() 에 대해 frmMain 의 OnBtnCloseClicked() 와 reject() 를 지정하면 버튼이 클릴될 때, 두 슬롯이 모두 수행 됩니다.

이제 OnBtnCloseClicked() 슬롯함수에 프로그램 코드를 넣어야 하는데, 아래와 같이 TfrmMain에 넣으면 나중에 디자인이 바뀌면 사라질 것입니다.

   void TfrmMain::OnBtnCloseClicked()
   {
      qWarning( "TfrmMain::OnBtnCloseClicked(): Not implemented yet!" );
   }

여기서 frmMain.h 를 보면,

   protected slots:
      virtual void OnBtnCloseClicked();

이와 같이 상속을 받을 수 있도록 선언되어 있기 때문에 TfrmMain 를 상송받는 TfrmMainChild 를 만들고, OnBtnCloseClicked() 를 완성합니다.

  1. TfrmMain 을 상속받는 TfrmMainChild 를 생성
    frmMainChild.h
    #ifndef FRM_MAIN_CHILD
    #define FRM_MAIN_CHILD
    
    #include "frmMain.h"
    
    class TfrmMainChild: public TfrmMain
    {
    Q_OBJECT
    protected
    slots: virtual void OnBtnCloseClicked(); }; #endif

    frmMainChild.cpp
    #include <qmessagebox.h>
    #include "frmMainChild.h"
    
    void TfrmMainChild::OnBtnCloseClicked()
    {           
      TfrmMain::OnBtnCloseClicked();
      QMessageBox::information( this, "caption", "message");
    }
              

물론 main.cpp 에서 TfrmMain을 TfrmMainChild 로 변경해야 합니다.

  1. main.cpp 수정
    main.cpp
    #include <qapplication.h>
    #include "frmMainChild.h"
    
    int main( int argc, char **argv)
    {
      QApplication app( argc, argv);
    
      TfrmMainChild frm;
      app.setMainWidget( &frm);
      frm.show();
    
      return app.exec();  
    }
    

새로 만들어진 frmMainChild.cpp와 frmMainChild.h를 프로젝트 파일에 추가하고 make를 수행하시면 됩니다.

qmake -project를 다시 실행해도 좋습니다만 이정도는 간단한 수정이므로 sample.pro를 직접 열어 수정하셔도 좋습니다.

TEMPLATE = app
CONFIG -= moc
INCLUDEPATH += .
# Input INTERFACES += frmMain.ui
HEADERS += frmMainChild.h
SOURCES += main.cpp \
           frmMainChild.cpp
TARGET = show_form

Makefile을 다시 만들어야 하므로 qmake를 실행해 주시고 make로 실행파일을 만드시면 됩니다.

이렇게 폼을 상속받아서 처리해도 되겠습니다만 폼마다 파일이 딸린다는 것은 여러 모로 불편하고 번거롭죠. 다음 시간에는 QT 3.x.x 버전의 디자이너를 이용하면 이런 작업이 얼마나 편리해 지는 지에 대해 말씀을 드리겠습니다.

긴 글을 읽어 주셔서 고맙습니다. ^^