Qt프로그램

Qt Designer 를 이용한 GUI 설계

Barbarian developer 2024. 10. 8.

Qt 는 원하는 GUI 를 쉽게 빠르게 구현할 수 있도록 Qt Designer 를 제공한다. QtDesigner 는 사용자가 GUI 상에 배치할 위젯을 마우스로 드래그 하면서 위젯을 배치할 수 있다.

 

확장자가 ui 파일인 GUI 파일은 아래 소스코드와 같이 XML 포맷으로 되어 있다. 이 파일은 사용자가 마우스를 이용해 위젯을 배치하면 Qt Creator 의 Designer 툴이 자동으로 XML 로 작성한다. 그리고 빌드를 하게 되면 XML 로 되어 있는 GUI 파일을 C++ 소스코드로 변환 후 빌드 한다.

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
	<x>0</x>
	<y>0</y>
    <width>338</width>
	<height>178</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QWidget" name="horizontalLayoutWidget">

 

Qt Designer 를 이용한 예제

새프로젝트 생성 → Qt Widgets Application → CMake → Base Class : Qwidget

 

widget.ui 소스코드를 더블 클릭하면 Designer 화면으로 전환된다.

 

여기까지만 하고 출력하면 위젯이 이렇게 화면으로 출력된다. 

하지만, 이 위젯은 아직 connect되지 않은 상황이기 때문에, 시그널이 발생해도 값에는 아무 변화가 없다.

slide 눈금을 움직이면 spinbox의 값이 바뀌도록 설정 하는 코드를 작성해 보겠다.

 

<widget.h>

#ifndef WIDGET_H  // 중복 포함 방지를 위한 매크로 정의 시작
#define WIDGET_H
#include <QWidget>  // QWidget 클래스 포함

// Ui 네임스페이스 안에 Widget 클래스 선언 (UI 관련 코드 자동 생성)
namespace Ui { class Widget; }

// Widget 클래스 정의 (QWidget을 상속)
class Widget : public QWidget
{
    Q_OBJECT  // Qt의 시그널과 슬롯을 사용하기 위해 필요한 매크로

public:
    // 생성자: 부모 위젯을 선택적으로 받을 수 있음
    Widget(QWidget *parent = nullptr);
    // 소멸자: 메모리 해제를 처리
    ~Widget();

private:
    // UI 구성 요소를 위한 포인터 (자동으로 생성된 ui 클래스)
    Ui::Widget *ui;

private slots:
    // 슬롯 함수들: 슬라이더 값이 변경되면 호출됨
    void slider1_valueChanged(int value);
    void slider2_valueChanged(int value);
    void slider3_valueChanged(int value);
};

#endif // WIDGET_H  // 중복 포함 방지를 위한 매크로 정의 끝
더보기

 

  • #ifndef, #define, #endif: 이 매크로는 헤더 가드라고 불리며, 헤더 파일이 여러 번 포함되더라도 중복 포함을 방지합니다. WIDGET_H가 정의되어 있지 않으면, 이 헤더 파일을 포함하겠다는 의미입니다.
  • Ui::Widget *ui;: 이 포인터는 Qt의 디자이너 툴에서 생성된 UI 요소를 참조하는 역할을 합니다. Qt 디자이너를 사용해 위젯을 구성하면, 자동으로 ui_widget.h 파일이 생성되는데, 이 파일에 정의된 Ui::Widget 클래스에 접근하기 위한 포인터입니다.
  • 슬롯 함수 (private slots): Qt에서 **슬롯(slot)**은 특정 시그널이 발생했을 때 호출되는 함수입니다. 여기서는 세 개의 슬라이더(slider1, slider2, slider3)의 값이 변경될 때 각각 대응하는 슬롯 함수가 호출됩니다. 각각의 슬롯은 해당 슬라이더 값에 따라 스핀박스 값을 변경하는 역할을 합니다.

 

  • private slots:를 새로 선언하고, 슬라이더의 값을 변경할 함수를 선언한다.
  • widget.h 헤더파일에서 ui 를 선언한 Object 명이 있다.
  • 이 오브젝트 명이 Designer 툴에서 배치한 위젯을 접근할 수 있는 접근자이다.

<widget.cpp>

#include "widget.h"  // Widget 클래스 헤더 파일 포함
#include "./ui_widget.h"  // Qt 디자이너로부터 생성된 UI 파일 포함

// 생성자: 부모 위젯을 선택적으로 받음, ui 객체를 초기화
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    // UI를 설정하는 함수, ui 위젯들을 초기화
    ui->setupUi(this);

    // 슬라이더와 슬롯을 연결 (구 스타일, SIGNAL과 SLOT 사용)
    connect(ui->slider1, SIGNAL(valueChanged(int)),
            this,        SLOT(slider1_valueChanged(int)));
    connect(ui->slider2, SIGNAL(valueChanged(int)),
            this,        SLOT(slider2_valueChanged(int)));
    connect(ui->slider3, SIGNAL(valueChanged(int)),
            this,        SLOT(slider3_valueChanged(int)));
}

// 소멸자: 동적으로 할당된 ui 포인터 삭제
Widget::~Widget()
{
    delete ui;  // 동적으로 할당된 ui 메모리 해제
}

// slider1의 값이 변경되었을 때 호출되는 슬롯 함수
void Widget::slider1_valueChanged(int value)
{
    // slider1의 값을 spinBox1에 반영
    ui->spinBox1->setValue(value);
}

// slider2의 값이 변경되었을 때 호출되는 슬롯 함수
void Widget::slider2_valueChanged(int value)
{
    // slider2의 값을 spinBox2에 반영
    ui->spinBox2->setValue(value);
}

// slider3의 값이 변경되었을 때 호출되는 슬롯 함수
void Widget::slider3_valueChanged(int value)
{
    // slider3의 값을 spinBox3에 반영
    ui->spinBox3->setValue(value);
}
더보기

 

  • 생성자 (Widget::Widget):
    • new Ui::Widget을 사용하여 ui 객체를 동적으로 할당하고, setupUi(this)를 호출하여 UI 요소를 초기화합니다. 이는 .ui 파일에서 설정된 위젯과 레이아웃을 실제 객체로 생성하는 역할을 합니다.
    • connect() 함수는 슬라이더의 값이 변경되었을 때 해당 슬롯 함수를 호출하도록 시그널-슬롯 연결을 설정합니다. Qt의 구 스타일로 시그널과 슬롯을 연결할 때는 SIGNAL()과 SLOT() 매크로를 사용합니다.
  • 소멸자 (Widget::~Widget):
    • 동적으로 할당한 ui 객체를 삭제합니다. 이는 메모리 누수 방지를 위해 필수적인 작업입니다.
  • 슬롯 함수들:
    • slider1_valueChanged, slider2_valueChanged, slider3_valueChanged는 각각 슬라이더의 값이 변경될 때 호출됩니다. 전달된 값(int value)을 해당 스핀박스의 값으로 설정하는 역할을 합니다. 예를 들어, slider1의 값이 변경되면 spinBox1에 그 값이 반영됩니다.

 

  • 위의 예제에서 한가지 주의해야 할 점은 connect( ) 함수의 인자를 Old Style 형태로사용했다는 점이다. 
  • 만약 New Style 을 사용하면 “no matching member function for callto ‘connect’” 라는 에러가 발생한다.
  • 이런 에러가 발생하는 이유는 QSpinBox 에서제공하는 valueChanged( ) 멤버 함수는 Overloaded 된 멤버 함수로 int 형과 QString형인 두가지 멤버 함수를 제공하기 때문이다.
  • Overloaded 된 시그널이 있다면 Old Style 을 사용해야 한다. 

'Qt프로그램' 카테고리의 다른 글

QMainWindow 를 이용한 GUI 구현  (1) 2024.10.08
다이얼로그  (0) 2024.10.08
Signal and Slot  (1) 2024.10.08
Layout  (0) 2024.10.08
Qt GUI widgets(2)  (1) 2024.10.08

댓글