수색…
소개
비고
작은 예
신호와 슬롯은 객체 간의 통신에 사용됩니다. 신호와 슬롯 메커니즘은 Qt의 핵심 기능이며 아마도 다른 프레임 워크에서 제공하는 기능과 가장 다른 부분 일 것입니다.
최소 예제는 하나의 신호, 하나의 슬롯 및 하나의 연결을 가진 클래스를 필요로합니다.
counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <QWidget>
#include <QDebug>
class Counter : public QWidget
{
/*
* All classes that contain signals or slots must mention Q_OBJECT
* at the top of their declaration.
* They must also derive (directly or indirectly) from QObject.
*/
Q_OBJECT
public:
Counter (QWidget *parent = 0): QWidget(parent)
{
m_value = 0;
/*
* The most important line: connect the signal to the slot.
*/
connect(this, &Counter::valueChanged, this, &Counter::printvalue);
}
void setValue(int value)
{
if (value != m_value) {
m_value = value;
/*
* The emit line emits the signal valueChanged() from
* the object, with the new value as argument.
*/
emit valueChanged(m_value);
}
}
public slots:
void printValue(int value)
{
qDebug() << "new value: " << value;
}
signals:
void valueChanged(int newValue);
private:
int m_value;
};
#endif
main
은 새로운 가치를 설정합니다. 슬롯이 어떻게 호출되는지 확인하고 값을 출력 할 수 있습니다.
#include <QtGui>
#include "counter.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Counter counter;
counter.setValue(10);
counter.show();
return app.exec();
}
마지막으로, 우리 프로젝트 파일 :
SOURCES = \
main.cpp
HEADERS = \
counter.h
새로운 Qt5 연결 구문
SIGNAL
및 SLOT
매크로를 사용하는 기존의 connect
구문은 런타임에 완전히 작동하지만 두 가지 단점이 있습니다. 즉, 런타임 오버 헤드 (바이너리 크기 오버 헤드가 발생 함)가 있으며 컴파일 타임 정확성 검사가 없습니다. 새로운 구문은 두 가지 문제를 해결합니다. 예제에서 구문을 확인하기 전에 특히 어떤 일이 발생하는지 더 잘 알아야합니다.
우리가 집을 짓고 있고 케이블을 연결하고 싶다고합시다. 이것은 연결 함수가하는 것과 정확히 같습니다. 신호와 슬롯은이 연결을 필요로합니다. 요점은 당신이 하나의 연결을 할 경우, 당신은 더 중첩 연결에주의해야합니다. 신호를 슬롯에 연결할 때마다 신호가 방출 될 때마다 슬롯 함수를 호출하기 만하면 컴파일러에 알려줍니다. 이것은 정확히 일어난 일입니다.
다음은 main.cpp 샘플입니다.
#include <QApplication>
#include <QDebug>
#include <QTimer>
inline void onTick()
{
qDebug() << "onTick()";
}
struct OnTimerTickListener {
void onTimerTick()
{
qDebug() << "OnTimerTickListener::onTimerTick()";
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
OnTimerTickListener listenerObject;
QTimer timer;
// Connecting to a non-member function
QObject::connect(&timer, &QTimer::timeout, onTick);
// Connecting to an object member method
QObject::connect(&timer, &QTimer::timeout, &listenerObject, &OnTimerTickListener::onTimerTick);
// Connecting to a lambda
QObject::connect(&timer, &QTimer::timeout, [](){
qDebug() << "lambda-onTick";
});
return app.exec();
}
힌트 : 이전 구문 ( SIGNAL
/ SLOT
매크로)에서는 슬롯 또는 신호가있는 모든 클래스에 대해 Qt 메타 컴파일러 (MCC)가 실행되어야합니다. 코딩 관점에서 볼 때 이러한 클래스에는 Q_OBJECT
매크로가 있어야 함을 의미합니다 (이 클래스에서 MOC를 실행할 필요성을 나타냄).
반면에 새로운 신택스는 시그널이 작동하려면 MOC가 필요하지만 슬롯은 작동 하지 않아야 합니다. 클래스에만 슬롯과 신호가없는 경우, Q_OBJECT
매크로를 가질 필요가 없으므로 MOC를 호출 할 수 없으므로 최종 바이너리 크기가 줄어들뿐만 아니라 컴파일 시간이 단축됩니다 (MOC 호출이없고 생성 된 컴파일러 호출이 필요 없음). *_moc.cpp
파일).
과부하 된 신호 / 슬롯 연결
Qt5의 새로운 연결 구문은 과부하 된 신호와 슬롯 연결이라는 큰 약점이 있습니다. 컴파일러가 오버로드를 해결할 수 있도록 멤버 함수 포인터에 static_cast
를 사용하거나 (Qt 5.7에서 시작) qOverload
및 friends :
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}
public slots:
void slot(const QString &string) {}
void slot(const int integer) {}
signals:
void signal(const QString &string) {}
void signal(const int integer) {}
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
// using pointers to make connect calls just a little simpler
MyObject *a = new MyObject;
MyObject *b = new MyObject;
// COMPILE ERROR! the compiler does not know which overloads to pick :(
QObject::connect(a, &MyObject::signal, b, &MyObject::slot);
// this works, now the compiler knows which overload to pick, it is very ugly and hard to remember though...
QObject::connect(
a,
static_cast<void(MyObject::*)(int)>(&MyObject::signal),
b,
static_cast<void(MyObject::*)(int)>(&MyObject::slot));
// ...so starting in Qt 5.7 we can use qOverload and friends:
// this requires C++14 enabled:
QObject::connect(
a,
qOverload<int>(&MyObject::signal),
b,
qOverload<int>(&MyObject::slot));
// this is slightly longer, but works in C++11:
QObject::connect(
a,
QOverload<int>::of(&MyObject::signal),
b,
QOverload<int>::of(&MyObject::slot));
// there are also qConstOverload/qNonConstOverload and QConstOverload/QNonConstOverload, the names should be self-explanatory
}
다중 창 신호 슬롯 연결
신호와 슬롯을 사용하는 간단한 멀티 윈도우 예제.
Main Window 뷰를 제어하는 MainWindow 클래스가있다. 웹 사이트 클래스에 의해 제어되는 두 번째 창.
두 클래스는 웹 사이트 창에서 버튼을 클릭하면 MainWindow에서 어떤 일이 발생하도록 연결됩니다 (텍스트 레이블이 변경됨).
나는 GitHub 에도있는 간단한 예제를 만들었다.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "website.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void changeText();
private slots:
void on_openButton_clicked();
private:
Ui::MainWindow *ui;
//You want to keep a pointer to a new Website window
Website* webWindow;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::changeText()
{
ui->text->setText("New Text");
delete webWindow;
}
void MainWindow::on_openButton_clicked()
{
webWindow = new Website();
QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
webWindow->show();
}
website.h
#ifndef WEBSITE_H
#define WEBSITE_H
#include <QDialog>
namespace Ui {
class Website;
}
class Website : public QDialog
{
Q_OBJECT
public:
explicit Website(QWidget *parent = 0);
~Website();
signals:
void buttonPressed();
private slots:
void on_changeButton_clicked();
private:
Ui::Website *ui;
};
#endif // WEBSITE_H
website.cpp
#include "website.h"
#include "ui_website.h"
Website::Website(QWidget *parent) :
QDialog(parent),
ui(new Ui::Website)
{
ui->setupUi(this);
}
Website::~Website()
{
delete ui;
}
void Website::on_changeButton_clicked()
{
emit buttonPressed();
}
프로젝트 구성 :
SOURCES += main.cpp\
mainwindow.cpp \
website.cpp
HEADERS += mainwindow.h \
website.h
FORMS += mainwindow.ui \
website.ui
위스 (Uis)가 구성 될 것이라고 생각하십시오.
- 메인 창 : "텍스트"라는 레이블과 "openButton"이라는 버튼
- 웹 사이트 창 : "changeButton"버튼
따라서 키포인트는 신호와 슬롯 사이의 연결과 윈도우 포인터 또는 참조의 관리입니다.