본 포스팅은 프로젝트 QILT를 진행하며 알게 된 소소한 팁을 기록하기 위한 포스팅입니다.
Qt Signal/Slot
- Qt에서 제공하는 오브젝트간의 통신 시스템을 의미
- 한 문장으로 표현하면 " A 오브젝트에서 Signal이 발생하면 B 오브젝트의 Slot을 호출하여라 " 이다.
- 글쓴이는 Qt 개발의 짬(?)이 부족하여 상세한 내용을 제외하고 Qt에서 제공하는 Qt Designer를 이용하여 사용하는 방법과 개발자가 커스텀하여 사용하는 두 방법에 대해 설명할 것이다
- 초심자가 보기 쉽게 설명은 스크린샷으로 진행, 사용된 코드는 맨 하단에 git gist로 제공할 것이다.
프로젝트 생성
- 본 작성글은 Qt Widget 프로젝트를 이용해 진행된다

- Signal/Slot을 사용하기 위해서는 Signal/Slot을 등록/호출 할 Widget Class와 ui파일만을 사용한다

Qt Designer를 이용한 Signal/Slot 사용 방법
- 본 글에서는 QMenu의 Item을 클릭하였을때 프로그램(MainWindow)가 종료되는 예제를 설명한다. 해당 예제를 이용하여 다양하게 활용해보도록 하자.
- Fig2 사진의 QtSignalSlot.ui 파일을 실행하면 아래와 같이 Qt Designer가 실행될 것이다

- 간단한 예제를 위해 QMenuBar(menuBar)에 menu item을 하나 생성한 뒤 등록되어 있는 signal과 slot을 이용하는 방법을 설명할 것이다
- Fig3을 보면 "여기에 입력하십시오"라고 나와 있는 부분이 QMenuBar(menuBar) 부분으로, 더블클릭 후 텍스트를 입력하고 엔터를 누르면 QMenu가 생성되는 것을 알 수 있다.
- 그 뒤 생성된 QMenu를 클릭하여 나오는 "여기에 입력하십시오"를 더블클릭하여 텍스트를 입력하면 QAction 또한 자동으로 생성된다.

- QMenu는 일반적인 프로그램의 메뉴바에서 상위 메뉴 아이템을 의미하며, QAction은 하위 메뉴 아이템을 뜻한다고 생각하면 된다.
- QAction은 특정한 event(Signal)이 발생될때 등록된 함수(Slot)을 실행하는 역할을 하는 아이템이다
- Fig4의 하단을 보면 시그널/슬롯 편집기가 있는 것이 확인할 수 있다.
- Qt 프레임워크는 이곳에서 시스템에 등록된 오브젝트( Widget, Action, etc ...)에 Qt 시스템이 제공하는 기본적인 event(Signal)과 함수(Slot)을 이용해 특정 동작을 구현할 수 있도록 제공한다.

- Fig5와 같이 시그널/슬롯 편집기의 " + " 아이콘을 클릭하면 새로운 Signal/Slot을 생성할 수 있다.
- 여기서 송신자는 Signal이 발생할 오브젝트로 예제에서는 Fig4에서 생성한 "Window exit" Action이 된다
- 시그널은 송신자가 어떠한 event(trigger)를 받았음을 확인하는 역할로 대표적으로 Button의 Press()나 Action의 Trigger()가 존재한다. 자세한 것은 Qt Documentation을 확인하자
- 수신자는 송신자가 시그널이 발생했을때 호출할 함수의 오브젝트( Widget, Action, Item, etc ... ) 를 의미한다. 예제에서는 MainWindow를 종료할 것이기에 수신자는 MainWindow가 된다.
- 슬롯은 수신자가 송신자로부터 시그널이 발생했음을 확인받았을때 실행할 함수를 의미한다. 예제에서는 MainWindow를 종료하기 위해 close 함수를 등록할 것이다.

- 여기서 송신자와 수신자를 선택할 때는 아래 Fig7에서 볼 수 있듯이 객체 탐색기에서 시그널/슬롯을 등록할 오브젝트의 이름을 찾아 시그널/슬롯 편집기에서 선택하면 된다.

이로써 시스템에 등록된 Signal/Slot 등록 과정이 끝났다. 참 간단하죠?
이대로 프로그램을 실행시켜 Window exit 아이템을 클릭하면 프로그램 창이 종료되는 것을 확인할 수 있다.

다만, 이대로 끝내기에는 실제 프로젝트에서 활용하기에 너무도 빈약한 정보이다.
중요한 것은 개발자 Signal/Slot을 커스텀하여 원하는 함수를 자유롭게 호출하는 방식이라고 생각한다.
Signal/Slot 사용자 정의 방법
- 본 글에서는 위와 같이 QMenu에서 QAction을 하나 생성하여 QMessageBox를 띄우는 예제를 설명한다. 해당 예제에서 Slot에 등록될 함수를 자유롭게 수정하면 이제 당신도 Signal/Slot을 활용할 줄 안다고 할 수 있다!
- 우선 Qt Designer에서 등록된 내용이 저장되는 ui_'메인 클래스 이름'.h 파일을 살펴보자
- 아래 Fig9와 같이 생성된 Qt 프로젝트의 메인 클래스의 헤더파일에 선언된 Ui 네임스페이스를 ctrl + 클릭을 통해 파일을 확인할 수 있다 ( 정의로 이동 )

- ui_'메인 클래스 이름'.h 파일을 잘 살펴보면 QObject::connect ... 으로 선언된 내용을 확인할 수 있을 것이다.
- 이 부분이 바로 위에서 Qt Designer를 이용해 생성한 시그널/슬롯 동작을 코드로 작성된 부분이다.
- 우리는 이 방법과 유사한 방법으로 메인 클래스에서 특정 QMenu item을 선택하면 QMessage Box를 호출하도록 함수를 만들고 Signal/Slot을 등록할 것이다.
- 우선은 Signal을 발생시킬 QMenu item을 하나 생성하도록 한다

- 위와 같이 생성한 뒤 프로젝트를 실행하고 나면 ui_메인 클래스.h 에 QMessageBox를 위한 QAction 변수가 생성되는 것을 확인할 수 있다.

- 그 다음 Fig9 내용에서 설명했던 것 ui_메인 클래스.h에 작성되어있던 Signal/Slot 함수 호출 코드를 활용해 사용자 정의 Signal/Slot을 작성한다.
-> 1. Signal/Slot을 등록할 Class Header파일에 Slot 함수를 등록한다. 예제에서는 " void on_triggered_menu_QMessage() " 라는 함수를 등록할 것이다

- Fig12를 보면 private slots: 이라는 키워드를 등록하였는데, 이것은 Qt Framework에 해당 Qt클래스에 slot 함수를 등록할 것을 알리기 위함으로 생각하면 된다.
- slots 키워드를 통해 선언한 함수는 해당 Qt클래스 파일에 내용을 정의해주면 된다.

* 중요한 점 1. Fig12의 코드 line 8 을 확인하면 Q_OBJECT 키워드가 선언되있는 볼 수 있다. 이처럼 Q_OBJECT가 선언되어있어야 signal/slot 등록이 가능하며
** 중요한 점 2. 사용자 함수를 정의할때 송신자 클래스 멤버함수로 정의하여야한다.
이 말인 즉, Fig13의 line 11과 같이 retrun_type Class :: Function_name(Param) 와 같이 Class 부분이 시그널을 받을 송신자 클래스여야 한다는 뜻이다.
- 마지막으로 선언/정의한 함수를 connect 함수로 signal/slot 등록을 해주면 된다. 가급적 클래스 생성자에서 등록하기를 권하는 바이다.

- connect 함수의 매개변수는 다음과 같은 의미를 가진다
- connect ( param 1 , param2, param3, param4 );
- param 1 : 송신자 매개변수로 signal을 발생시킬 오브젝트를 의미한다.
- param 2 : signal 함수, 예제의 SIGNAL(triggered())는 Qt에서 제공하는 기본 시그널 함수로, QAction 아이템을 클릭할때 발생된다. 자세한 것은 Qt Documentation을 참고하자
- param 3 : 수신자 매개변수로 여기서 this는 QtSignalSlot 클래스 자체를 의미. 즉, 프로그램에서 MainWindow를 담당하는 객체가 되는 것이다
- param 4 : slot 함수, signal 함수가 발생했을때 호출될 함수로 본 예제에서는 QMessageBox를 띄우는 사용자 정의 함수를 등록하였다.
예제 결과

이처럼 방법만 알면 Qt Signal/Slot을 활용하는 것은 매우 손쉽게 이용할 수 있다.
다만 글쓴이는 Qt에 관련된 책이나 강의를 듣지 않고 Qt Documentation과 구글링만을 이용해 프로젝트를 개발하다보니 시간이 좀 걸린 부분이었기에 내용을 남기는 바이다
#include "QtSignalSlot.h" | |
#include <QMessageBox> | |
QtSignalSlot::QtSignalSlot(QWidget *parent) | |
: QMainWindow(parent) | |
{ | |
ui.setupUi(this); | |
connect(ui.actionQMessageBox, SIGNAL(triggered()), this, SLOT(on_triggered_menu_QMessage())); | |
} | |
void QtSignalSlot::on_triggered_menu_QMessage() | |
{ | |
QMessageBox MsgBox; | |
MsgBox.setText("Signal/Slot example"); | |
// MsgBox.setInformativeText("프로그램을 종료하시겠습니까?"); | |
MsgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); | |
MsgBox.setDefaultButton(QMessageBox::Ok); | |
if (MsgBox.exec() == QMessageBox::Ok) | |
{ | |
MsgBox.close(); | |
} | |
} |
#pragma once | |
#include <QtWidgets/QMainWindow> | |
#include "ui_QtSignalSlot.h" | |
class QtSignalSlot : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
QtSignalSlot(QWidget *parent = Q_NULLPTR); | |
private slots: | |
void on_triggered_menu_QMessage(); | |
private: | |
Ui::QtSignalSlotClass ui; | |
}; |
'QT > VS based QT' 카테고리의 다른 글
OpenCV 이미지를 QT로 출력하기 ( C++) (0) | 2020.07.23 |
---|---|
Visual Studio 2019 QT 환경설정 (2) | 2020.07.23 |