QT 6 Programing [Chapter 07. 데이터 타입과 클래스 - Chapter 12. QMainWindow를 이용한 GUI 구현]

2024. 10. 8. 12:46·LAB/QT_C++

Qt는 개발자의 편의성을 위해 다양한 데이터타입을 제공한다. Qt에서는 이기 종간의 데이터 교환 시 데이터 타입의 변화로 생기는 문제를 해결하기 위한 데이터 타입도 지원한다. 예를 들어 우분투 리눅스 운영체제상에서 Qt로 개발한 어플리케이션 내에 “Hello World” 라는 문자열을 Qt 에서 제공하는 QString 이라는 문자열을 전송한다.

 

* 이기종 간의 데이터 교환 : 사용자에 의해서 입력되는 데이터 교환 처리를 위한 아이디, 패스워드, 데이터를 요청하는 사용자측의 시스템 정보를 포함하는 조건 정보를 수신하면, 기 저장된 정보로부터 상기 조건 정보와 일치하는 정보를 추출하여 제공하는 것을 특징으로 하는 이기종 시스템 간의 데이터 교환 시스템.

Qt 문자열 데이터 타입 클래스

 

Qt는 단순한 문자열을 다루는 클래스 이외에도 데이터 스트림, 멀티 바이트 캐릭터 형태의 유니코드 4.0(Unicode Standard Version) 캐릭터를 지원하는 다양한 클래스를 제공한다.

 

** QString : 유니코드 문자열 캐릭터를 지원하는 클래스 

QString str = "Hello";

=> 16bit QChar를 저장할 수 있는 기능 제공한다.

 

static const QChar data[4] = {0x0055, 0x006e, 0x10e3, 0x03a3 };
QString str(data, 4);

=> QString 은 const char * 와 같은 문자열 상수를 fromUtf8() 함수를 사용해 대체할 수 있는 기능을 제공한다.

 

QString str;
str.resize(4);
str[0] = QChar('U');
str[1] = QChar('n');
str[2] = QChar(0x10e3);
str[3] = QChar(0x03a3);

=> 저장된 문자열의 특정 위치에 QChar 을 저장할 수 있는 기능 제공한다.

 

QString str;
if ( str == "auto" || str == "extern" || str == "static" || str == "register" )
{
// ...
}

=> 문자열을 비교하기 위해 QString 은 if 문을 이용해 다음과 같은 비교가 가능하다.

 

QString str = "We must be <b>bold</b>, very <b>bold</b>";
int j = 0;
while ((j = str.indexOf("<b>", j)) != -1) 
{
	qDebug() << "Found <b> tag at index position" << j;
	++j;
}

=> 찾고자 하는 특정 문자열의 위치를 알고 싶다면 indexOf() 함수를 사용해 찾고자 하는 문자열의 위치를 찾을 수 있다.

 

QStringList

 

QString 에 저장된 문자열을 QList 와 같이 문자열을 배열 형태로 관리할 수 있는 기능을 제공하며 append(), prepend(), insert() 등의 멤버 함수를 제공한다.

 

QStringList strList;
strList << "Monday" << "Tuesday" << "Wednesday";
QString str;
str = strList.join(",");
// 출력하면 str == " Monday, Tuesday, Wednesday"

 


 

08. Container Classes

▶ Container 클래스는 특정 유형의 데이터를 집합 또는 배열 형태로 저장하는데 사용한다.

▶ 예를 들어 QString으로 저장해야 할 항목이 여러 개 있다면 QList<QString>과 같은 Container 클래스를 사용할 수 있다.

▶ Container 클래스들은 STL에서 제공하는 Container들보다 사용하기 쉽고 안전하다. 또한 경량화 되어 있다.

▶ C++의 STL에서 제공하는 Container를 대체해 사용할 수 있다.

 

1. QHash<Key, T> : Hash 테이블 기반의 Dictionary를 제공하는 템플릿 클래스

2. QList<T> : List 형태의 값을 다루기 위해 제공하는 템플릿 클래스

3. QVector<T> : Qt 6에서는 QList 로 통합되었다.

 

QHash<Key, T>

 

QHash 클래스는 해시 테이블 기반의 Dictionary를 제공한다. 데이터를 저장하는 방식은 Key, Value 가 Pair(쌍)로 저장 된다. Key 값으로 찾고자 하는 데이터를 빠르게 검색할 수 있는 기능을 제공한다. QHash는 QMap과 매우 비슷한 기능을 제공하지만 내부
알고리즘은 QMap 보다 빠르다.

QHash<QString, int> hash;
hash["one"] = 1;
hash["three"] = 3;
hash["seven"] = 7;

 

hash.insert("twelve", 12);
int num1 = hash["thirteen"];
int num2 = hash.value("thirteen");

=> QHash에 Key, Value를 쌍으로 저장하기 위한 방법으로 insert( ) 함수를 사용할 수 있다. 그리고 Value 값을 알기 위해 value( ) 멤버 함수를 사용할 수 있다.

 

QList<T>

 

QList<T>는 빠른 인덱스 기반의 액세스가 가능하며 저장된 데이터 삭제도 매우 빠르다. QList는 인덱스 기반의 클래스이며 QLinkedList의 Iterator 기반보다 사용하기 편리하며 데이터 저장 시 메모리 할당하는 속도에서 QVector 보다 빠르다.

QList<int> integerList;
QList<QDate> dateList;
QList<QString> list = { "one", "two", "three" };

 

if (list[0] == "Bob")
list[0] = "Robert";

=> QList는 비교 연산자를 통해 리턴 값을 아래 예와 같이 사용할 수 있다.

 

for (int i = 0 ; i < list.size() ; ++i)
{
if (list.at(i) == "Jane")
cout << "Found Jane at position " << i << endl;
}

=> QList는 at( ) 함수를 이용하면 리스트 상에 저장된 위치를 쉽게 검색 할 수 있다.

 


 

09. Signal and Slot

▶ Qt는 이벤트를 처리하기 위한 메커니즘으로 시그널(Signal)과 슬롯(Slot)을 사용한다. 예로 어떤 버튼이 클릭했다는 행위는 Qt에서 시그널(Signal) 이라고 한다. 그리고 시그널이 발생하면 호출 하는 함수를 슬롯(Slot) 함수라고 한다. 시그널 이라는 이벤트가 발생하면 시그널과 연결된 슬롯 함수가 호출된다.

** 시그널 : 어떠한 상황에 발생하는 이벤트

 

▶ 네트워크 채팅 프로그램을 Qt의 시그널 슬롯을 사용하지 않고 채팅 프로그램을 개발한다고 가정해보자. 여러 개의 쓰레드(Thread) 구조의 프로그램을 개발해야 한다.

▶ Qt에 제공하는 모든 GUI 위젯은 미리 정해진 다양한 시그널을 가지고 있다. 예를 들어 QPushButto의 click, double click, mouse over 등과 같이 다양한 시그널이 정의되어 있다.

 

 

=> 그림과 같이 Object1에 signal1이 발생하면 Object2의 slot1이 구동된다.

=> connect를 이용하여 connect(Object1,signal1,Object2,slot2);

=> Object1의 signal1과 Object2의 slot2을 연결한다.

 

[widget.h]

#ifndef WIDGET_H
#define WIDGET_H

#include <QLabel>

class SignalSlot : public QObject
 {
     Q_OBJECT

 public:
    void setValue(int val) {
        emit valueChanged(val);
    }

 signals: // 시그널 함수 불러올 위치
     void valueChanged(int newValue);

 private:
     int m_value;
};


class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    QLabel *lbl;

public slots:
// slots 키워드는 public , private와 함께 사용된다.
// Slot 함수 정의
    void setValue(int val);

};

#endif // WIDGET_H

 

[widget.cpp]

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    lbl = new QLabel("", this);
    lbl->setGeometry(10, 10, 250, 40);

    SignalSlot myObject;


    // New Style (Qt 5.5 이상버전에서 사용하는 방식)
    connect(&myObject, &SignalSlot::valueChanged,
            this,      &Widget::setValue);

    //Old Style (Qt 5.5 이하버전에서 사용하는 방식)
    /*
    connect(&myObject, SIGNAL(valueChanged(int)),
            this,      SLOT(setValue(int)));
    */

    myObject.setValue(50);
}


void Widget::setValue(int val)
{
// setValue() 멤버함수가 호출되면 함수 내에 emit 이라는 키워드를 사용한 소스코드를 확인할 수 있다.
// emit 키워드는 시그널 이벤트를 발생한다.

    QString labelText = QString("Signal emmit, Value : %1").arg(val);
    lbl->setText(labelText);
}

Widget::~Widget()
{
}

=> 이 예제 소스코드는 시그널이 발생하면 윈도우 상에 배치된 라벨의 텍스트를 출력하는 예제이다.

 

[main.cpp]

#include <QtWidgets/QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;

    w.resize(400, 300);
    w.setWindowTitle("Custom Signal Slot");

    w.show();

    return a.exec();
}

 

** Signal 과 Slot 함수는 다른 클래스에만 구현되어 있어야 되는 것은 아니다. 동일한 클래스에 존재하는 Signal 이 Slot 함수를 호출 할 수 있다. Signal 은 Slot함수 외에도 Signal을 호출 할 수 있다.

 

cnt1 = new Counter("counter 1");
cnt2 = new Counter("counter 2");
connect(cnt1, SIGNAL(valueChagned(int)), cnt2, SIGNAL(valueChagned(int)));
connect(cnt2, SIGNAL(valueChagned(int)), cnt2, SLOT(setValue(int)));

=> Signal 과 Slot을 사용하는 클래스 상단에 보면 Q_OBJECT 라는 키워드를 사용한 것을 확인할 수 있다. 이 키워드는 Qt에서 Signal 과 Slot을 사용할 때 반드시 필수로 Q_OBJECT를 클래스 헤더에 보는 것과 같이 명시 해야한다.

=> Q_OBJECT를 선언하지 않고 Signal 과 Slot을 사용하는 경우가 있는데, 이럴 경우 에러가 발생하므로 주의해야 한다.


 

10. Qt Designer 를 이용한 GUI 설계

Qt Designer 는 사용자가 GUI 상에 배치할 위젯을 마우스로 드래그 하면서 위젯을 배치할 수 있다.

 

 

[widget.ui]

 

중첩 레이아웃 사용

 

Object Name => 변수명 

 

[widget.h]

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;

// Slot 함수는 Designer에서 배치한 QSlider의 값이 변경되면 호출되는 Slot함수이다.
private slots:
    void slider1_valueChanged(int value);
    void slider2_valueChanged(int value);
    void slider3_valueChanged(int value);
};
#endif // WIDGET_H

 

[widget.cpp]

#include "widget.h"
#include "./ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    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)));

}

Widget::~Widget()
{
    delete ui;
}
// QSpinBox 에서 제공하는 valueChanged( ) 멤버 함수는 Overloaded 된 멤버 함수로
// int 형과 QString 형인 두가지 멤버 함수를 제공
void Widget::slider1_valueChanged(int value)
{
    ui->spinBox1->setValue(value);
}
void Widget::slider2_valueChanged(int value)
{
    ui->spinBox2->setValue(value);
}
void Widget::slider3_valueChanged(int value)
{
    ui->spinBox3->setValue(value);
}

 

[main.cpp]

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

 

 


11. 다이얼로그

다이얼로그는 어플리케이션이 동작 중에 이벤트가 발생했을 때 사용자에게 메시지를 전달하기 위한 목적으로 사용된다.

종류 설명
QInputDialog 사용자로부터 값을 입력 받을 수 있는 다이얼로그
QColorDialog 특정 컬러를 선택할 수 있는 다이얼로그
QFileDialog 파일 또는 디렉토리를 선택하는 GUI 인터페이스를 제공.
QFontDialog 폰트를 선택하기 위한 다이얼로그
QProgressDialog 퍼센트와 같은 진행사항을 보여주기 위한 다이얼로그
QMessageBox 모달 방식의 다이얼로그

 

QInputDialog

 

QInputDialog 클래스는 사용자로부터 값을 입력 받을 수 있다.

 

[dialog.h]

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QInputDialog> // QInputDialog 사용하기 위한 선언

QT_BEGIN_NAMESPACE
namespace Ui {
class Dialog;
}
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

private:
    Ui::Dialog *ui;
};
#endif // DIALOG_H

[dialog.cpp]

#include "dialog.h"
#include "./ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    bool retValue;

    int i = QInputDialog::getInt(this, "정수입력", "퍼센트: ",25,0,100,1,&retValue);

    if(retValue)
    {
        qDebug("true %d",i);
    }


}

Dialog::~Dialog()
{
    delete ui;
}

[main.cpp]

#include "dialog.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();
    return a.exec();
}

 

[입력 후 다이얼 로그 실행]

 

[실수 입력 QInputDialog]

double dVal = QInputDialog::getDouble(this, "실수 입력", "값 입력: ",48.56,-100,100,2,&retValue);
    if(retValue)
    {
        //qDebug("true %d",i);
        qDebug("true %f",dVal);
    }

 

[콤보박스 QInputDialog]

 items << "봄" << "여름" << "가을" << "겨울";
    bool ok;

    QString item = QInputDialog::getItem(this,"항목선택", "계절 선택 : ",items,0,false,&ok);

[item 선택 후 Dialog 출력]

 

 

[텍스트 입력 후 Dialog 실행]

 bool ok;
    QString text = QInputDialog::getText(this,"텍스트 입력","이름: ",QLineEdit::Normal, "이름 입력",&ok);

 

 

 

QColorDialog

 

QColorDialog 클래스는 사용자가 색상표를 보고 원하는 색상을 선택하기 위한 기능을 제공한다.

 

[컬러 선택 후 Dialog 실행]

#include "dialog.h"
#include "./ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    QColor color;

    color = QColorDialog::getColor(Qt::green, this, "컬러선택",QColorDialog::DontUseNativeDialog);

    if(color.isValid())
    {
        qDebug() << Q_FUNC_INFO << "유효한 색상.";
    }
    // bool retValue;
    // QStringList items;

    // items << "봄" << "여름" << "가을" << "겨울";
    // bool ok;
    // QString text = QInputDialog::getText(this,"텍스트 입력","이름: ",QLineEdit::Normal, "이름 입력",&ok);
    //QString item = QInputDialog::getItem(this,"항목선택", "계절 선택 : ",items,0,false,&ok);
    //int i = QInputDialog::getInt(this, "정수입력", "퍼센트: ",25,0,100,1,&retValue);
    // double dVal = QInputDialog::getDouble(this, "실수 입력", "값 입력: ",48.56,-100,100,2,&retValue);
    // if(retValue)
    // {
    //     //qDebug("true %d",i);
    //     qDebug("true %f",dVal);
    // }


}

Dialog::~Dialog()
{
    delete ui;
}

 

 

QFileDialog

 

▶ QFileDialog 클래스는 사용자로부터 파일을 선택할 수 있는 다이얼로그를 제공한다. 특정 확장자 또는 특정 파일을 필터링하여 사용자에게 보여줄 수 있다.

▶ QFileDialog 클래스의 getOpenFileNames( ) 멤버 함수는 디렉토리 내에 존재하는 파일을 다중 선택할 수 있는 기능을 제공한다. getExistingDirectory( ) 멤버 함수는 사용자가 디렉토리를 선택할 수 있다. 그리고 getSaveFileName( ) 멤버 함수는 사용자가 저장할 파일을 지정할 수 있다.

 

[dialog.cpp]

#include "dialog.h"
#include "./ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);

    QFileDialog::Options options;

    options = QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly;
    options |= QFileDialog::DontUseNativeDialog;

    QString directory = QFileDialog::getExistingDirectory(this, "파일 다이얼로그","home:",options);
    // QColor color;

    // color = QColorDialog::getColor(Qt::green, this, "컬러선택",QColorDialog::DontUseNativeDialog);

    // if(color.isValid())
    // {
    //     qDebug() << Q_FUNC_INFO << "유효한 색상.";
    // }
    // bool retValue;
    // QStringList items;

    // items << "봄" << "여름" << "가을" << "겨울";
    // bool ok;
    // QString text = QInputDialog::getText(this,"텍스트 입력","이름: ",QLineEdit::Normal, "이름 입력",&ok);
    //QString item = QInputDialog::getItem(this,"항목선택", "계절 선택 : ",items,0,false,&ok);
    //int i = QInputDialog::getInt(this, "정수입력", "퍼센트: ",25,0,100,1,&retValue);
    // double dVal = QInputDialog::getDouble(this, "실수 입력", "값 입력: ",48.56,-100,100,2,&retValue);
    // if(retValue)
    // {
    //     //qDebug("true %d",i);
    //     qDebug("true %f",dVal);
    // }


}

Dialog::~Dialog()
{
    delete ui;
}

 

상수 설명
QFileDialog::ShowDirsOnly 디렉토리만 표시
QFileDialog::DontResolveSymlinks 심볼릭 링크를 표시하지 않기 위해 사용
QFileDialog::DontConfirmOverwrite 덮어쓰기 할 때 경고 메시지를 표시하지 않기
QFileDialog::DontUseNativeDialog 시스템 기본 파일 다이얼로그를 사용하지 않기 위해 사용
QFileDialog::ReadOnly 읽기 모드로 파일 다이얼로그를 사용
QFileDialog::HideNameFilterDetails 필터를 이용해 파일을 감추기 위해 사용

 

 

QFontDialog

 

QFontDialog는 사용자로부터 폰트를 선택할 수 있는 다이얼로그를 제공한다. 첫 번째 인자는 사용자가 다이얼로그 하단에 위치해 있는 [OK] 버튼과 [CANCEL] 버튼 중 어떤 버튼을 클릭했는지 확인하기 위한 변수를 지정 한다.

 

[dialog.cpp]

#include "dialog.h"
#include "./ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    bool ok;
    QFont font;
    font = QFontDialog::getFont(&ok, QFont("Courier 10 Pitch"),this);

    // QFileDialog::Options options;

    // options = QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly;
    // options |= QFileDialog::DontUseNativeDialog;

    // QString directory = QFileDialog::getExistingDirectory(this, "파일 다이얼로그","home:",options);
    // QColor color;

    // color = QColorDialog::getColor(Qt::green, this, "컬러선택",QColorDialog::DontUseNativeDialog);

    // if(color.isValid())
    // {
    //     qDebug() << Q_FUNC_INFO << "유효한 색상.";
    // }
    // bool retValue;
    // QStringList items;

    // items << "봄" << "여름" << "가을" << "겨울";

    // QString text = QInputDialog::getText(this,"텍스트 입력","이름: ",QLineEdit::Normal, "이름 입력",&ok);
    //QString item = QInputDialog::getItem(this,"항목선택", "계절 선택 : ",items,0,false,&ok);
    //int i = QInputDialog::getInt(this, "정수입력", "퍼센트: ",25,0,100,1,&retValue);
    // double dVal = QInputDialog::getDouble(this, "실수 입력", "값 입력: ",48.56,-100,100,2,&retValue);
    // if(retValue)
    // {
    //     //qDebug("true %d",i);
    //     qDebug("true %f",dVal);
    // }


}

Dialog::~Dialog()
{
    delete ui;
}

 

 

 

QProgressDialog

 

QProgressDialog 클래스는 사용자에게 현재 진행 사항을 보여주기 위한 목적으로 사용한다. 예를 들어 대용량 파일 복사와 같이 시간이 다소 걸리는 사항에 대해서 다이얼로 그창에 진행사항을 보여 줄 수 있다.

 

[widget.h]

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QProgressDialog>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QProgressDialog *pd;
    QTimer *timer;
    int steps;

public slots:
    void perform();
    void cancel();
};

#endif // WIDGET_H

 

[widget.cpp]

#include "widget.h"
#include "./ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    steps = 0;
    pd = new QProgressDialog("File copy progress", "Cancel", 0, 100);
    connect(pd, SIGNAL(canceled()), this, SLOT(cancel()));

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(perform()));
    timer->start(1000);
}

void Widget::perform()
{
    pd->setValue(steps);
    steps++;

    if (steps > pd->maximum())
        timer->stop();
}

void Widget::cancel()
{
    timer->stop();
}


Widget::~Widget()
{
    delete ui;
}

=> QTimer 는 1초에 한번씩 타이머 이벤트를 호출해 QProgressDialog 의진행사항 값을 1%씩 증가하기 위해 사용하였다. 다음 소스코드는 widget.cpp 소스코드 이다.

[main.cpp]

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

 

QMessageBox

 

▶ QMessageBox 클래스는 모달(Modal) 방식의 다이얼로그를 제공한다. 사용자에게 정보를 전달할 수 있으며 QMessageBox 클래스가 다이얼로그 창에서 사용가능하도록 제공하는 버튼들은 다음 표에서 보는 것과 같이 다양한 버튼을 사용할 수 있도록 제공한다.

▶ QMessageBox 클래스는 information( ), question( ), warning( ) 멤버 함수를 제공한다.

상수 설명
QMessageBox::Ok OK 버튼
QMessageBox::Open 파일 열기 버튼
QMessageBox::Save 저장 버튼
QMessageBox::Cancel 취소 버튼
QMessageBox::Close 닫기 버튼
QMessageBox::Discard 저장하지 않고 버리기 버튼
QMessageBox::Apply APPLY 버튼
QMessageBox::Reset RESET 버튼
QMessageBox::RestoreDefaults 다시 저장하기 버튼
QMessageBox::Help 도움말 버튼
QMessageBox::SaveAll 모두 저장하기 버튼
QMessageBox::Yes YES 버튼
QMessageBox::YesToAll 모두 YES 적용하기 버튼
QMessageBox::No NO 버튼
QMessageBox::NoToAll 모두 NO 적용하기 버튼
QMessageBox::Abort 중지 버튼
QMessageBox::Retry 재시도 버튼
QMessageBox::Ignore Ignore(무시) 버튼
QMessageBox::NoButton An invalid button

 

[QMessageBox 클래스를 이용해 Abort, Retry, Ignore 버튼 사용]

 

[dialog.cpp]

#include "dialog.h"
#include "./ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);

    QMessageBox::StandardButton reply;

    reply = QMessageBox::critical(this, "Critical 다이얼로그","디스크가 존재하지 않습니다."
                                  , QMessageBox::Abort | QMessageBox::Retry | QMessageBox::Ignore);

    if(reply == QMessageBox::Abort)
    {
        qDebug() << "Abort 선택";
    }
    else if(reply == QMessageBox::Retry)
    {
        qDebug() << "Retry 선택";
    }
}

Dialog::~Dialog()
{
    delete ui;
}

[QMessageBox :: critical]

 

[QMessageBox :: question]

 

[dialog.cpp]

#include "dialog.h"
#include "./ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);

    QMessageBox::StandardButton reply;

    //reply = QMessageBox::critical(this, "Critical 다이얼로그","디스크가 존재하지 않습니다."
    //                              , QMessageBox::Abort | QMessageBox::Retry | QMessageBox::Ignore);
    reply = QMessageBox::question(this, "Question 다이얼로그", "파일을 저장 하시겠습니까?"
                                    , QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    if(reply == QMessageBox::Yes)
    {
        //qDebug() << "Abort 선택";
        qDebug() << "Yes 선택";
    }
    else if(reply == QMessageBox::No)
    {
        //qDebug() << "Retry 선택";
        qDebug() << "No 선택";
    }
    else if(reply == QMessageBox::Cancel)
    {
        qDebug() << "Cancel 선택";
    }
}

Dialog::~Dialog()
{
    delete ui;
}

 

 

 

[사용자 정의 다이얼로그 구현]

 

[dialog.h]

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QLabel      *lbl;
    QLineEdit   *edit;
    QPushButton *okbtn;
    QPushButton *cancelbtn;

private slots:
    void slot_okbtn();
    void slot_cancelbtn();

};


#endif // DIALOG_H

 

[dialog.cpp]

이 다이얼로그는 이름을 입력 받을 수 있으며 버튼 두개를 배치 하였다.

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle("Custom Dialog");

    lbl = new QLabel("Name");
    // QLabel 객체 lbl은 "Name"이라는 텍스트를 표시합니다.
    edit = new QLineEdit("");
    // QLineEdit 객체 edit은 사용자로부터 입력을 받기 위한 텍스트 입력 필드입니다.
    okbtn = new QPushButton("Confirm");
    // QPushButton 객체 okbtn은 "Confirm"이라는 텍스트가 표시된 확인 버튼입니다.
    cancelbtn = new QPushButton("Cancel");
    // QPushButton 객체 cancelbtn은 "Cancel"이라는 텍스트가 표시된 취소 버튼입니다.

    QHBoxLayout *hlay1 = new QHBoxLayout();
    hlay1->addWidget(lbl);
    hlay1->addWidget(edit);
    // hlay1는 수평 레이아웃(QHBoxLayout)으로, lbl과 edit을 나란히 배치합니다.

    QHBoxLayout *hlay2 = new QHBoxLayout();
    hlay2->addWidget(okbtn);
    hlay2->addWidget(cancelbtn);
    // hlay2는 okbtn과 cancelbtn을 나란히 배치하는 수평 레이아웃입니다.

    QVBoxLayout *vlay = new QVBoxLayout();
    // vlay는 두 개의 수평 레이아웃을 세로로 배치하는 QVBoxLayout입니다.
    vlay->addLayout(hlay1);
    vlay->addLayout(hlay2);
    setLayout(vlay);
    // setLayout(vlay)는 최종적으로 이 레이아웃을 대화 상자의 레이아웃으로 설정합니다.

    connect(okbtn,&QPushButton::clicked, this, &Dialog::slot_okbtn);
    connect(cancelbtn,&QPushButton::clicked, this, &Dialog::slot_cancelbtn);
    // QObject::connect()를 사용하여 버튼과 슬롯을 연결해야 합니다. 예를 들어, 다음과 같이 버튼과 슬롯을 연결할 수 있습니다
}

void Dialog::slot_okbtn()
{
    qDebug() << "slot_okbtn 함수 실행";
    //emit accepted();
    // emit은 특정 시그널을 명시적으로 발생시키는 키워드입니다.
    // 이는 객체에서 어떤 이벤트가 발생했음을 다른 객체에게 알리는 방식입니다. 시그널을 슬롯에 연결하면, 시그널이 발생할 때 자동으로 슬롯이 호출됩니다.
    accept();
    //accept()는 대화 상자를 닫고, 수락 처리(logic)를 수행하는 함수입니다.
    //accepted()는 대화 상자가 수락되었을 때 발생하는 시그널로, 다른 슬롯과 연결하여 추가적인 동작을 처리할 수 있습니다.
}

void Dialog::slot_cancelbtn()
{
    qDebug() << "slot_cancelbtn 함수 실행";
    reject();
   
}


Dialog::~Dialog()
{
}

=> slot_okbtn( ) Slot 함수는 다이얼로그의 [확인] 버튼을 클릭 시 호출된다. slot_cancelbtn( ) Slot 함수는 [취소] 버튼을 클릭하면 호출된다.

** emit accepted()나 emit rejected() 같은 시그널을 호출할 때, 별도로 시그널을 선언할 필요는 없습니다. 

 

[main.cpp]

#include <QApplication>
#include <QDebug>
#include "dialog.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Dialog dlg;

    int retVal = dlg.exec();
    if(retVal == QDialog::Accepted)
        qDebug() << Q_FUNC_INFO << "QDialog::Accepted";
    else if(retVal == QDialog::Rejected)
        qDebug() << Q_FUNC_INFO << "QDialog::Rejected";

    return a.exec();
}

=> Dialog 클래스의 dlg 오브젝트는 사용자가 [확인] 버튼 클릭 시 int 값 1을 리턴 한다. [취소] 버튼 클릭 시 0을 리턴 한다.

 


 

12. QMainWindow 를 이용한 GUI 구현

지금까지 다룬 방식은 QWidget 을 이용해 한 개의 윈도우 화면만 존재하는 방식으로 GUI를 구성하였다.

QMainWindow 를 이용해 GUI를 구현하는 것이 사용자에게 직관적인 GUI를 제공할 수 있을 것이다.
예를 들어 Menu Bar, Toolbars, Status Bar, Dock Widget, Central Widget 등으로 위젯들을 특정 영역에 배치할 수 있다.

 

 

Qt는 MDI(Multi Document Interface) 방식을 구현할 수 있다. MDI 방식은 QMdiArea 클래스를 이용해 구현할 수 있다. 복잡한 윈도우 GUI를 구현해야 한다면 QMainWindow 와 더불어 QMdiArea 클래스를 함께 사용하는 것을 권장한다.

QMainWindow

 

MainWindow 클래스는 QMainWindow 클래스를 상속받아 구현 메인 윈도우 GUI 이다. 이 클래스는 Menu Bar, Tool Bar, Central Widget 영역 등이 구현되어 있다.

 

MDIMainWindow 클래스는 QTextEdit 위젯 클래스를 상속받는 위젯 클래스이다. 이 클래스는 MainWindow 중앙 배치할 다중 에디트 위젯으로 사용한다. 즉 울트라 에디터, 노트패드 등과 같이 여러 개의 텍스트 파일을 하나의 윈도우 영역 안에서 편집할 수
있는 기능을 제공하기 위해 구현된 클래스 이다.

 

[mainwindow.h]

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "MDIMainwindow.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:

private slots:
    void newFile();
    // newFile( ) Slot 함수는 메뉴 바에서 [New] 메뉴를 클릭했을 때 호출된다.
    void open();
    // open( ) 함수는 [Open] 메뉴를 클릭하면 호출된다.
};

#endif // MAINWINDOW_H

 

[MDIMainwindow.h]

#ifndef QMDIMAINWINDOW_H
#define QMDIMAINWINDOW_H

#include <QMainWindow>
#include <QObject>

class MDIMainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MDIMainWindow(QWidget *parent = nullptr);
};

#endif // QMDIMAINWINDOW_H

[main.cpp]

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

 

[mainwindow.cpp]

#include "mainwindow.h"
#include <QMenu>
#include <QAction>
#include <QMenuBar>
#include <QToolBar>
#include <QDockWidget>
#include <QListWidget>
#include <QStatusBar>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QMenu *fileMenu;
    QAction *newAct;
    QAction *openAct;

    newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this);
    newAct->setShortcuts(QKeySequence::New);
    newAct->setStatusTip(tr("Create a new file"));
    connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

    openAct = new QAction(QIcon(":/images/open.png"), tr("&Open"), this);
    openAct->setShortcuts(QKeySequence::Open);
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(newAct);
    fileMenu->addAction(openAct);

    QToolBar *fileToolBar;
    fileToolBar = addToolBar(tr("File"));
    fileToolBar->addAction(newAct);
    fileToolBar->addAction(openAct);

    QDockWidget *dock = new QDockWidget(tr("Target"), this);
    // QDockWidget 은 MDI 윈도우 좌측에 위치하고 사용자가 GUI상에서 새로운 창으로 분리할 수 있는 GUI를 제공한다.
    dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);

    QListWidget *customerList = new QListWidget(dock);
    customerList->addItems(QStringList()
            << "One"
            << "Two"
            << "Three"
            << "Four"
            << "Five");

    dock->setWidget(customerList);
    addDockWidget(Qt::RightDockWidgetArea, dock);

    setCentralWidget(new MDIMainWindow());


    statusBar()->showMessage(tr("Ready"));

}

MainWindow::~MainWindow()
{

}

// [SLOTS]
void MainWindow::newFile()
{
    qDebug() << Q_FUNC_INFO;
}

void MainWindow::open()
{
    qDebug() << Q_FUNC_INFO;
}

=> MainWindow 클래스의 생성자 에서는 MDI 윈도우 GUI상에서 메뉴와 툴바에 배치할 메뉴 항목을 정의한다. 그리고 각 메뉴의 클릭 시 Signal 이벤트 발생시 Slot 함수와 연결한다.

 

[MDIMainwindow.cpp]

#include "MDIMainwindow.h"
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QPushButton>

MDIMainWindow::MDIMainWindow(QWidget *parent)
    : QMainWindow(parent)
{
// MDIMinWindow 클래스는 MDI 윈도우에서 Child 윈도우로 사용한다. 
// 즉 GUI 내에 여러 개의 Child 윈도우를 제공하는 것과 같은 기능을 제공한다.
    setWindowTitle(QString::fromUtf8("My MDI"));

    QMdiArea* area = new QMdiArea();
    area->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    // MdiSubWindow 생성
    QMdiSubWindow* subWindow1 = new QMdiSubWindow();
    // QMdiArea 클래스와 QMdiSubWindow 클래스를 이용해 MDIMainWindow 하위에 서브 윈도우로 등록할 윈도우를 생성한다.
    subWindow1->resize(300, 200);

    QPushButton *btn = new QPushButton(QString("Button"));
    subWindow1->setWidget(btn);


    QMdiSubWindow* subWindow2 = new QMdiSubWindow();
    subWindow2->resize(300, 200);

    // MDIMainWindows에 서브 윈도우 추가
    area->addSubWindow(subWindow1);
    area->addSubWindow(subWindow2);

    setCentralWidget(area);
}

 

Ctrl + N / Ctrl + O 단축키 , 아이콘 버튼 누르기 , File -> New, File -> Open 선택 시 출력 

'LAB > QT_C++' 카테고리의 다른 글

QT 6 Programing [Chapter 28. Essential Network Programing]  (2) 2024.10.09
QT 6 Programing [Chapter 13. Stream - Chapter 16. Model and View]  (0) 2024.10.08
QT 6 Programming [Chapter 01. Qt6 - Chapter 06. Layout]  (2) 2024.10.07
'LAB/QT_C++' 카테고리의 다른 글
  • QT 6 Programing [Chapter 28. Essential Network Programing]
  • QT 6 Programing [Chapter 13. Stream - Chapter 16. Model and View]
  • QT 6 Programming [Chapter 01. Qt6 - Chapter 06. Layout]
it-lab-0130
it-lab-0130
it-lab-0130 님의 블로그 입니다.
  • it-lab-0130
    빠냐냐~
    it-lab-0130
  • 전체
    오늘
    어제
    • 분류 전체보기 (69)
      • 개인 (2)
        • 개발TIP Program (2)
      • LAB (47)
        • Python (5)
        • C (13)
        • TCP_IP (7)
        • C++ (9)
        • QT_C++ (4)
        • C# (9)
      • Project (0)
        • 오류 모음 (0)
        • Python (0)
        • C 와 TCP_IP소켓 (0)
        • C++ (0)
      • Study_ (17)
        • 예제_문제풀이 (10)
        • 학습일지 (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • Python
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
it-lab-0130
QT 6 Programing [Chapter 07. 데이터 타입과 클래스 - Chapter 12. QMainWindow를 이용한 GUI 구현]
상단으로

티스토리툴바