[VEDA] QT Programming 3

나우히즈·2025년 4월 19일

VEDA

목록 보기
15/16

사용자 친화적 인터페이스를 만들기 위해 위젯을 만들고 사용자들이 위젯을 통해 컴터에 친숙한 환경을 만든다.

qt 는 크로스플랫폼이다.

어떤 환경에서도 gui를 만들면 소스코드 변경 없이 윈도우든, rtos, mac 등 다양한 환경에서 사용가능

qt가 확장되면서 데이터 구조, 컨테이너, 네트워크, 스레드 등 개념들이 들어가서 큐티 하나를 가지고 거의 모든 프로그램을 만들 수 있게 되었음.

우리는 사실 그 뒤쪽까진 안하고 그래픽, gui쪽을 보게 될 것.

뒤의 내용들은 같이 못해도, pdf를 보며 예제코드를 분석하다보면 공부할 수 있을것.

현업에서도 gui 위주로 사용되고 있음.

오늘 교재 7장부터 고고


7장. 큐티에서 제공하는 데이터타입과 클래스 부분

미니프로젝트에서 큐티와 C++ 를 다루게 될 것

만들어진 객체들을 큐티로 가져와서 디스플레이시키고, 큐티 인터페이스로 받아온 데이터를 c++데이터로 변환하는 등 과제를 하게 될것임.

숫자 관련해서는 qt도 기존 C++과 대부분 동일한 자료형을 지원

문자, 문자열에서는 좀 다른게, 큐티는 2바이트로 한 문자를 표현함.

2바이트짜리 자료형은 qchar라는 자료형을 가지고 활용하게 된다.

1바이트로 쓴다면 qbyte라는 문자형을 사용해야함.

qstring으로 만들어지는 문자열 객체 또한 유니코드 2바이트 문자셋을 쓰고있음.

C++에서는 std::string → 여기선 1바이트 문자 셋 사용…

자료형이 같아보여도 다른 자료형이다.

C++에서 만든 객체 스트링은 큐티로 가져와서 넘길땐 다이렉트로 넘겨질 수 없다.

변환 과정이 필요함

qstring이라는 클래스를 매뉴얼을 보며 접근해보자.

fromStdString 이라는 함수를 써서 변환할 수 있다.

qstring ↔std::string 변환 함수.자주 사용할테니 잘 알아두도록 하자

QString 변수에 std::string 자료를 넣으려하면, 컴파일 에러가 발생

따라서, std::string을 QString으로 바꿔주는 fromStdString함수를 사용하자.

반대로 qstr → str 은 tostdstring 함수 써서 바꿔주도록 하자.


큐티에도 마찬가지로 컨테이너가 있다.

stl에서 쓰던 컨테이너와 크게 다르지 않고 이름에 Q만 붙여주면 된다.

QVector, QMap, …

사용 방식은 STL과 동일. 약간 다르게 추가기능이 있다.


위젯에서 발생하는 이벤트 (시그널) → 슬롯 함수로 처리

한번 정리해보자면

사용자와의 인터페이스에서는 사용자의 액션이 시그널이 됨.

프로그램 내, 객체 의 결과를 다른 객체로 전달하고자 한다면 임의로 시그널을 발생시켜야 한다.

시그널 발생 시 슬롯함수가 발동하여 특정객체가 받아 처리하게함.

시그널이든 슬롯이든 함수 방식으로 설계가 되어있음.

객체에서 변화가 생겻을 때 시그널 → 슬롯으로 받기.

이를 connect함수로 연결함.

qt에서 시그널을 만들거나 슬롯함수를 만든다면 필요한 매크로가 Q_OBJECT

컴파일러가 클래스 내 존재하는 Q_OBJECT 매크로를 보면 MOC라는 컴파일러를 불러서 시그널 항목 처리, 슬롯 항목 처리를 사전에 처리하고 컴파일러가 동작하게 되어있다.

반드시 이 매크로가 선언되어있어야 시그널-슬롯 처리를 할 수 이씀.

슬롯함수 → public slots: (선언과 구현 함께 적어주어야한다)

시그널 → signals: (선언만 필요하다)

emit 명령을 시그널 발생시킨다.

유저 액션에 의한 시그널 발생이 아닌, 특정 객체가 다른 객체로 시그널을 전송하고자 한다면 emit 명령을 통해 특정 시그널을 발생시킨다.

특정 객체에 슬롯 함수를 호출하도록 connect함수에서 미리 등록하고 필요할 때 emit으로 신호를 발생시키는 매커니즘이다.

시그널 등록할 때 헤더파일에 등록하고 시그널 함수를 connect()로 연결하는데,

시그널에는 SIGNAL(@@), 슬롯에는 SLOT($$) 로 입력했었음.

펑터를 써서 함수명, 시그널 명만을 입력해도 된다.

최근에는 람다식를 이용하여 별도의 슬롯함수 선언 없이 진행하기도한다.

커넥트 쓸 때 3번째 인자가 리시버 객체

this라는 현재 수행되는 객체가 3번째 인자라면 굳이 안적어도됨.(생략가능)

근데 컴파일러가 워닝을 띄우긴 하니까 그냥 this 명시하삼

qt관련 코드를 보다보면 커넥트가 3개의 인자로만 되어있는 경우 그냥 리시버가 this이구나 라고 이해하면 된다.


오늘은 디자이너라는 걸 다뤄볼 것

레이아웃 배치 위젯을 통해 좀 더 편리하게 인터페이스를 구성할 수 잇엇음

이보다 더 편한게 큐티 디자이너.

디자이너라는 좋은 도구가 있다.

이를 통해 gui를 간편하게 구성할 수 있음.

디자이너를 통해 시그널 - 슬롯을 연결해줄 수 있다.

위젯 property를 조정하는 것도 가능

.ui 파일 → xml 코드로 만들어짐.

이걸 큐티 컴파일러가 C++로 컨버팅하고 디자인 정보를 가지고 코드를 만들어준다 자동으로.

qt 프로젝트 생성 시, form file은 생성안하고 햇는데, 이제 이걸 생성해서 디자인을 해보자.

이제 edit창에 forms가 생성.

widget.ui를 눌러보면 다양한 위젯들이 존재함.

드래그 앤 드랍 방식으로 위젯을 설계하면 됨.

디자이너에서 설계하면 설계한 내용이 XML파일로 생성되어있따.

디자이너를 통해 디자인한 위젯은 widget.cpp에 ui 객체를 상속받게 만들어진다.

여기서 추가적인 작업은

ui 포인터를 참조하여(→) 접근하면 ui 내의 위젯들에 접근이 가능하다.

디자이너에서 F4 하면 시그널/슬롯 에디팅이 가능함.

그럼 위젯마다 드래그로 연결할 수 잇게됨.
근데 지금은 그냥 기본 시그널/슬롯함수만 존재함. (제약이 많음)
XML에 커넥트한 내용들이 적혀져 업데이트된다.


직접 connect 추가도 가능함.

그냥 디자이너로는 전체적인 윈도우의 레이아웃 설계를 진행하고,

그 세부적인 연결은 직접 connect 시키는것이 좋아보임.

connect를 사용하는 상황에선 old style, new style, 람다식 모두 가능.

예전버전에서는 매크로방식만 가능했다고 함.
새로운 슬롯함수를 만든다면…

디자이너에는 등록되지 않앗으니 직접 connect함수를 통해 슬롯함수가 호출되도록 연결해주어야할것이다.

헤더파일에 슬롯함수 하나 만들고 테스트 해보도록 하자.

시그널 선언, 슬롯함수 선언 정의, 커넥트 함수 연결은 수동으로 해줘야한다.
사용자가 만든 슬롯함수도 잘 등록되어 동작하고있따.


다이얼로그

사용자와 프로그램이 서로 대화할 필요가 있을 때 사용하는 위젯

정보를 주거나 입력하거나 할 때 대화창을 띄워 제공한다.

  • Modal vs non-modal vs semi-modal modal, semi-modal, non-modal — 이 세 가지는 사용자가 다이얼로그와 어떻게 상호작용할 수 있는지를 정하는 방식

    🔍 각 모드 자세히 설명

    1. ✅ Modal Dialog (모달 다이얼로그)

    사용자가 해당 다이얼로그를 닫기 전까지는 부모 윈도우나 다른 창을 조작할 수 없음

    • Qt에서 exec()로 띄우는 다이얼로그가 이 타입
    • QFileDialog, QMessageBox::question() 등 기본 모달
    • 예시:
      ```cpp
      Dialog dlg;
      if (dlg.exec() == QDialog::Accepted) {
          // OK 눌렀을 때 처리
      }
      ```
      

    ✔️ 특징

    • 부모 윈도우 블로킹됨 (막힘)

    • exec()는 함수 리턴값으로 결과 받음

    • 중요한 결정, 경고, 입력 등에서 사용


      2. ✅ Non-modal Dialog (비모달 다이얼로그)

      다이얼로그가 떠 있어도 메인 윈도우 포함한 모든 창 조작 가능

    • Qt에서 show()로 띄우는 다이얼로그가 이 타입

      Dialog *dlg = new Dialog(this);
      dlg->show();  // 비모달로 띄움

      ✔️ 특징

    • 다이얼로그 열려 있어도 다른 작업 가능

    • 메모장에서 "찾기" 창처럼, 동시에 여러 작업 가능할 때 사용

    • 종료 결과는 시그널로 받는 경우 많음 (accepted() 등)


      3. ✅ Semi-modal Dialog (세미 모달)

      다이얼로그가 특정 윈도우만 막고, 전체 애플리케이션은 막지 않음

    • Qt에선 setWindowModality()로 설정할 수 있어

    • 예시:

      ```cpp
      dlg->setWindowModality(Qt::WindowModal);     // 부모 창만 막음
      dlg->show();
      
      ```

      ✔️ 종류

      설명
      Qt::NonModal완전 비모달
      Qt::WindowModal부모 창만 블록
      Qt::ApplicationModal전체 애플리케이션 블록 (= exec()와 비슷)

용어의미
Modal"이 창 닫기 전까지 다른 창 못 건드림"
Non-modal"이 창 띄워도 다른 창 조작 가능함"
Semi-modal"제한적으로 막음, 특정 창만 차단하고 나머지는 열어둠"

모달창 설정여부는 setModal 함수를 이용하여 모달모드 설정.

image.png

다이얼로그 함수는 정적멤버함수로 설계되어 객체생성할 필요가 없음

getText로 텍스트를 받아보자.

image.png

컬러다이얼로그로 색상을 입력받을 수 있다.

getColor도 만들어보자

image.png

텍스트에딧을 하나 만들어서 색상값이 잘 반영되는지 확인해보자

#include "widget.h"

#include <QApplication>
#include <QColorDialog>
#include <QTextEdit>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // Widget w;
    QTextEdit *Te = new QTextEdit();
    Te->resize(100,100);

    QColor color = QColorDialog::getColor(Te->textColor());
    if (color.isValid())
    {
        qDebug() << Q_FUNC_INFO << "유효한 색상.";
        Te->setTextColor(color);
        Te->setText("Hello");
    }

    Te->show();
    // w.show();
    return a.exec();
}

파일 다이얼로그를 쓰면 탐색기 창이 뜨면서 파일을 선택할 수 있게 나타난다.
다이얼로그창은 어플리케이션창과 달리 임시적으로 생성되엇다가 작업이 완료되면 꺼진다.


QFontDialog

폰트선택해야하는 상황에서 사용할 수 있따.

QProgressDialog

막대그래프에 진행사항을 보여주는 다이얼로그

progressBar라는 클래스를 가지고 만들어졌음

QT에서 타이머 설정이 필요하다면 QTimer 만들고 ms 단위 시간을 기입하여 start.

#include <QApplication>
#include <QProgressDialog>
#include <QTimer>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QProgressDialog pd;
    pd.setWindowModality(Qt::WindowModal);
    pd.setAutoClose(true);
    pd.show( );
    QTimer t;
    int n = 0;
    QObject::connect(&t, &QTimer::timeout, &pd, [&]{ pd.setValue(++n); if(n>pd.maximum( )) pd.close( ); });
    t.start(3000);
    return a.exec();
}

QMessageBox

가장 많이 사용될 다이얼

모달방식임.

선택적으로 메시지박스를 골라서 질문, 정보, 경고, 위험 메시지를 보내줄 수 있따.

다양한 버튼들도 존재한당.

필요한 다이얼로그를 만드는 경우도 있다.

프로젝트 생성 시 QDialog로 베이스 클래스를 선택

#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.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");
    edit = new QLineEdit("");

    okbtn = new QPushButton("Confirm");
    cancelbtn = new QPushButton("Cancel");

    QHBoxLayout *hlay1 = new QHBoxLayout();
    hlay1->addWidget(lbl);
    hlay1->addWidget(edit);

    QHBoxLayout *hlay2 = new QHBoxLayout();
    hlay2->addWidget(okbtn);
    hlay2->addWidget(cancelbtn);

    QVBoxLayout *vlay = new QVBoxLayout();
    vlay->addLayout(hlay1);
    vlay->addLayout(hlay2);
    setLayout(vlay);

    connect(okbtn, &QPushButton::clicked, this, &Dialog::slot_okbtn);
    connect(cancelbtn, &QPushButton::clicked, this, &Dialog::slot_cancelbtn);
}

void Dialog::slot_okbtn()
{
    accept();
}

void Dialog::slot_cancelbtn()
{
    reject();
}

Dialog::~Dialog()
{
}

QMainWindow 클래스

gui프로그램마다 창이 다 다르게 구성

창이 다른 어플리케이션들을 만들어야할 때도 있다.

qt에서도 윈도우 기반으로 프로그램을 만들 수 있고, QMainWindow를 기반으로 한다.

윈도우는 모양새가 어느정도 맞춰줘있다.

큐티에서도 정해진 틀이 있고, 그 틀에 맞추어서 프로그램을 만들게된다.

프로젝트 생성 시 QMainWindow로 생성해보자.

메인 윈도우 : gui 어플의 폼으로 사용되는 윈도우

QMainWindow → QMenuBar/QMenu, QToolBar, QStatusBar 클래스와 함께 사용

여러표준 위젯들의 집합으로 구성

툴 팁 제공 기능 사용자의 편의를 위해 제공되는 풍선 도움말 중앙 영역에는 대부분의 위젯을 사용

SDI를 지원하기 위해 일반적인 위젯의 사용 가능

MDI를 지원하기 위해 QMdiArea위젯과 사용.

QMdiSubWindow 클래스와 함께 사용

QMenuBar/QMenu, QToolBar, QStatusBar 클래스 인스턴스 만들고 메인 윈도우에 설정해주면 됨.

QT에디터 클래스 편집기 구성하기.

TextEdit Widget을 메인윈도우 중앙에 배치

Menubar에서 선택하는 매뉴에 따라 액션을 지정해야하는데,

예를들어 메모장에서 파일→새로만들기 를 하게 된다면, 새로운창이뜨거나, 저장을 누르면 탐색기창이 뜨면서 지정된 루틴이 동작함.

워드 프로그램같은 경우 메뉴바 뿐 아니라 툴바도 존재해서 다양한 도구들을 사용해볼 수 있게 되어있다.

  • QAction 메뉴, 툴바, 단축키, 컨텍스트 메뉴 등등 "어떤 동작"을 하나로 정의해서 여러 곳에서 공유할 수 있게 해주는 클래스

    ✅ QAction이란?

    사용자 인터페이스에서의 "동작(Action)"을 표현하는 클래스

    • 메뉴 항목
    • 툴바 버튼
    • 단축키
    • 오른쪽 클릭 메뉴
    …이런 UI 요소들이 전부 QAction 하나로 관리될 수 있어!

    🧩 주요 요소

    항목설명
    텍스트메뉴/툴바에 표시될 이름 ("Open" 등)
    아이콘버튼/메뉴에 표시될 아이콘
    단축키Ctrl+N 같은 키보드 단축키
    상태 팁상태 표시줄에 나타나는 설명
    시그널triggered() → 사용자가 액션을 실행했을 때 발생

    ✨ 기본 사용 예제

    QAction *openAct = new QAction(QIcon(":/icons/open.png"), tr("&Open"), this);
    openAct->setShortcut(QKeySequence::Open);
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, &QAction::triggered, this, &MainWindow::openFile);

    🔄 QAction은 어디에 쓸 수 있나?

    대상사용법
    메뉴menu->addAction(action);
    툴바toolbar->addAction(action);
    컨텍스트 메뉴menu.addAction(action);
    단축키 처리action->setShortcut(...) 만으로 작동

    즉, 하나의 QAction을 메뉴 + 툴바 + 단축키에 동시에 연결 가능!

    동작은 한 번만 정의해도 되니까 유지보수에도 좋아.


    📌 주요 메서드 정리

    메서드설명
    setText("Save")표시될 이름 지정
    setIcon(QIcon(...))아이콘 설정
    setShortcut(QKeySequence(...))단축키 지정
    setStatusTip("...")상태 표시줄 도움말
    setCheckable(true)토글 가능한 액션 (ON/OFF)
    setEnabled(false)비활성화

    📡 주요 시그널

    시그널설명
    triggered()액션이 실행되었을 때
    toggled(bool)체크 상태가 바뀌었을 때 (setCheckable(true)인 경우)

    🔘 체크 가능한 액션 (예: 토글 버튼)

    QAction *boldAct = new QAction(tr("&Bold"), this);
    boldAct->setCheckable(true);
    
    connect(boldAct, &QAction::toggled, this, [](bool checked){
        qDebug() << "굵게 상태:" << checked;
    });
    

    ✅ 요약 한 줄

    QAction은 사용자의 어떤 "행동"을 정의하는 객체이고,

    메뉴, 툴바, 단축키 등 다양한 UI 요소에 재사용 가능중앙집중형 동작 정의 도구야!


    이제 QMenuBar, QToolBar, QContextMenuEvent 등에서 QAction이 어떻게 연결되는지도 쉽게 이해할 수 있을 거야! 혹시 QActionGroup으로 여러 액션 묶어서 토글하는 것도 궁금해? 그것도 실전에서 많이 써! 😎
  • 아래 코드 설명 Qt에서 메뉴나 툴바 버튼을 만들 때 쓰는 QAction 설정 과정

    ✅ 전체 목적:

    “메모장의 New(파일 만들기)” 기능을 메뉴/툴바/단축키에 등록하는 코드


    🔍 코드 분석

    newAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentNew),
                         tr("&New"), this);

    ✔️ new QAction(...)

    • QAction 객체 생성 → "New" 메뉴 항목 또는 버튼

    • QIcon::fromTheme(...) → 아이콘 지정 (OS 테마에서 가져옴)

    • tr("&New") → 표시될 텍스트 (&는 Alt+N 단축키 의미)

    • this → 부모 (MainWindow가 부모)


      newAct->setShortcuts(QKeySequence::New);

      ✔️ 단축키 설정

    • Ctrl+N 같은 표준 "새로 만들기" 단축키 자동 등록

    • Qt는 QKeySequence::New처럼 표준 동작에 맞는 키 할당 제공함


      newAct->setStatusTip(tr("Create a new file"));

      ✔️ 상태표시줄 도움말

    • 메뉴 위에 마우스를 올렸을 때 하단 상태표시줄(status bar) 에 보여질 설명 텍스트


      connect(newAct, &QAction::triggered, this, &MainWindow::newFile);

      ✔️ 시그널 연결

    • 사용자가 이 액션을 클릭하거나 단축키 누르면 → triggered() 시그널 발생

    • 이 시그널이 → MainWindow::newFile() 슬롯과 연결됨

    • 즉, 사용자가 메뉴에서 "New" 누르면 newFile() 실행됨


      🎯 결과적으로 하는 일 요약

      단계동작
      1"New" 액션 생성 (아이콘 + 이름)
      2단축키 (Ctrl+N) 설정
      3도움말 설명 (Create a new file) 설정
      4눌렀을 때 newFile() 함수 실행되도록 연결

      📌 이 액션은 보통 메뉴/툴바에 추가돼!

      fileMenu->addAction(newAct);     // 메뉴에 넣기
      fileToolBar->addAction(newAct);  // 툴바에 넣기

      🔧 newFile() 함수는 이렇게 생겼을 수도 있어:

      void MainWindow::newFile()
      {
          // 새 문서 초기화 작업
          textEdit->clear();
          setCurrentFile(QString());
      }
      
    newAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentNew),
                         tr("&New"), this);
    newAct->setShortcuts(QKeySequence::New);
    newAct->setStatusTip(tr("Create a new file"));
    connect(newAct, &QAction::triggered, this, &MainWindow::newFile);

액션을 설정해서 동작을 용이하게 등록-관리를 할 수 있다

0개의 댓글