[Qt] Signal & Slot

Signal과 Slot은 객체(Object)들간의 통신을 하기 위해 사용됩니다. Signal & Slot 메커니즘은 Qt에서만 사용할 수 있는 대표적인 기능이고, 익혀두면 Qt 어플리케이션을 개발할 때 매우 유용하게 사용할 수 있습니다.

Signal은 말 그대로 신호를 발생 시키는 것을 의미하며 Slot은 발생한 신호를 받아들이는 것을 의미합니다.
예를 들어 리모컨에서 전원 버튼을 눌러 발생되는 신호(Signal)를, TV 수신 안테나(Slot)가 신호를 수신하여 화면을 켜는 동작과 비슷하다고 보시면 됩니다.

이러한 Signal과 Slot을 연결하기 위해서는 connect 함수를 사용합니다. connect 함수는 QObject에 아래와 같이 선언되어 있습니다.

QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
const QObject *receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection)

어려워 보이지만 아래와 같이 사용할 수 있습니다.

connect(객체1, 시그널 함수, 객체2, 슬롯 함수);

위 이미지처럼 signal 함수와 slot 함수를 여러 개 만들어서 Object끼리 connect를 할 수 있습니다.

예제 코드를 만들어 보겠습니다. 위에서 예시를 들었던 리모컨 클래스와 텔레비전 클래스를 만들어 보겠습니다.
리모컨 클래스는 RemoteCtrl, 텔레비전은 Tv로 클래스를 만들겠습니다.

우선 아래와 같이 RemoteCtrl 클래스를 만들어 줍니다.

#ifndef REMOTECTRL_H
#define REMOTECTRL_H

#include <QObject>

class RemoteCtrl : public QObject
{
    Q_OBJECT
public:
    explicit RemoteCtrl(QObject *parent = nullptr);

    void clickTvOnButton();

signals:
    void signal_TvOn();

};

#endif // REMOTECTRL_H

signal 함수를 만들기 위해서는 signals 한정자 아래에 signal 함수를 선언하면 됩니다. 함수를 정의하실 필욘 없습니다.

#include "remotectrl.h"
#include <QDebug>

RemoteCtrl::RemoteCtrl(QObject *parent)
    : QObject{parent}
{

}

void RemoteCtrl::clickTvOnButton()
{
    qDebug() << "Click Tv On Button";

    emit signal_TvOn();
}

signal 이벤트를 발생하기 위해서는 emit 키워드를 사용하여 시그널을 발생시킵니다.

그 다음 Tv 클래스를 만들어줍니다.

#ifndef TV_H
#define TV_H

#include <QObject>

class Tv : public QObject
{
    Q_OBJECT
public:
    explicit Tv(QObject *parent = nullptr);

public slots:
    void slot_TvOn();

};

#endif // TV_H

slot 함수는 slots 한정자 아래에 slot 함수를 선언하고 아래와 같이 slot 함수를 정의하시면 됩니다.
slots 한정자는 앞에 public, protected, private 접근 제한자를 붙일 수 있습니다.

#include "tv.h"
#include <QDebug>

Tv::Tv(QObject *parent)
    : QObject{parent}
{

}

void Tv::slot_TvOn()
{
    qDebug() << "Do Tv On";
}

그리고 main 함수에 아래와 같이 구현합니다.

#include <QCoreApplication>
#include "remotectrl.h"
#include "tv.h"

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

    RemoteCtrl *pRmc = new RemoteCtrl;
    Tv *pTv = new Tv;

    QObject::connect(pRmc, SIGNAL(signal_TvOn()), pTv, SLOT(slot_TvOn()));

    pRmc->clickTvOnButton();

    return a.exec();
}

실행 하면 아래와 같이 출력 합니다.

시그널 슬롯 함수를 사용하는데 몇 가지 주의 사항이 있습니다.

  • QObject를 상속받고 클래스 내부에 Q_OBJECT를 포함해야함.
  • signal과 slot함수의 인자를 일치하게 사용해야함
  • signal을 발생하는 객체에서는 연결된 객체의 slot에 수신하는지 여부를 알지 못함. 반대로 slot도 signal이 연결되어 있는지 여부를 알 수 없음(독립적인 구성요소를 생성한다는 것을 알 수있음)
  • 단일 슬롯에 원하는 만큼 많은 신호 연결 가능.
  • Callback과 비교할 때 시그널 슬롯은 약 10배정도 느림.

이상으로 Signal, Slot에 대해 알아보았습니다.

깃허브: https://github.com/3001ssw/qt_cpp_study/tree/main/2SignalSlot