2015. 9. 2. 01:22

0041 - 시그널과 슬롯

참고 영상

QT 에서 시그널과 슬롯() 은 GUI 에서 주로 다루는 객체간의 이벤트들을 주고 받는 동작을 하는데 중요한 역할을 합니다. 지난번에 잠깐 소개해 드렸는데, 조금 더 알아 보도록 하겠습니다.

1. 프로젝트 생성 (중복되는 설명은 앞으로 간단하게 진행하겠습니다.)

프로젝트 생성은 처음 했을때와 동일하게 진행하되 아래 설정을 따라서 진행합니다.

File -> New File or Project

Choose a template : Qt Widgets Application

Choose...

Name : 004_myprogress

Next

Kit Selection : Desktop Qt 5.5.0 MingGW 32bit (환경에 따라 다를 수 있음)

Next

Class Information : 그대로 두기

Next

Project Management : 그대로 두기

Finish

프로젝트가 생성 되면 언제나 그렇듯이 한번 빌드를 해서 정상적으로 결과물이 나오는지 확인합니다.

2. 위젯 추가하기

시그널과 슬롯의 관계를 쉽게 이해하기 위해, 수평 조절 막대(호리즌탈 슬라이더, Horizontal Slider) 를 옮길 때 나오는 신호(시그널, Signal) 를 진행상태 막대(프로그래스 바, Progress Bar) 에서 그 신호을 받아 처리할 수 있는 슬롯(Slot) 에 만들어 구현하려고 합니다.

프로젝트 탐색기에서 Forms 을 선택합니다. 그리고 mainwindow.ui 를 더블 클릭하면 폼 편집기가 열립니다. 폼 편집기가 아닌 창이 나오면 Design 을 누르면 볼 수 있습니다.

프로그래스 바(Progress Bar) 를 추가합니다.

위젯 박스 (Widget Box) 아래 있는 필터 (Filter) 항목에 Progress Bar 를 입력하면 해당 위젯을 바로 볼 수 있습니다.

드래그 앤 드롭으로 창에 옮깁니다.

같은 방법으로 호리즌탈 슬라이더 (Horizontal Slider) 를 추가합니다.

위 그림 처럼, 위젯 박스 (Widget Box) 아래 있는 필터 (Filter) 항목에 Horizontal Slider 를 입력하면 해당 위젯을 바로 볼 수 있습니다.

드래그 앤 드롭으로 창에 옮깁니다.

두 위젯을 나란히 표시하기 위해 컨트롤 키를 누른 상태로 두 위젯을 누른 뒤, 위에 보이는 Lay Out Vertically (수직으로 나열하기) 를 선택합니다.
빨간 선으로 두 개의 위젯들이 그룹 형태로 묶여 있으며 파란 점을 끌면 동시에 위젯의 크기가 변경됩니다.

이제 실행하면 위젯은 추가되어 나오지만 수평 조절 막대를 변경해도 진행상태 막대의 값이 변경되지 않습니다. 이제 이 둘을 연결 해 봅시다.

3. 시그널과 슬롯 연결하기

위젯간 시그널과 슬롯을 연결하는 방법은 몇가지가 있지만, 크게 위젯에서 미리 준비 항목 끼리 연결 (Connect Configuration) 하는 방법과 직접 UI 객체가 생성될 때 connect 매크로를 사용하여 명시적으로 지정하는 방법이 있습니다.

1) 폼 편집기의 연결 설정 기능 이용하기

우선 폼 편집기에서 제공하는 시그널과 슬롯 연결하는 기능을 이용해봅니다. 이전 시간에도 사용해 봤지만, 시각적이기 때문에 처음 접해서 사용하기까지가 비교적 간편합니다.

폼 편집기에서 Edit Signals / Slots 를 선택합니다.

신호의 방향을 생각해서 시그널(신호) 을 주는 수평 조절 막대를 클릭한 뒤 진행상태 막대로 놓으면 Signal : horizontalSlider  -> SlotprogressBar 로 빨간 화살표가 생기며 연결 설정 (Configure Connection) 대화상자가 나타납니다.

horizontalSlider 에서 제공하는 시그널 중에 사용자의 입력으로 값이 변경되었을 때 발생하는 valueChanged(int) 라는 시그널이 있습니다. 이 항목과 오른쪽에 진행 상태 막대의 값을 지정하는 setValue(int) 슬롯이 있는데, 이 둘을 연결한 뒤 OK 를 눌러서 연결을 완료 합니다.

이 두 위젯(QSlider, QProgressBar) 모두 QWidget 에서 상속 받았으므로 Show signals and slots inherited from QWidget (QWidget 에서 상속받은 시그널과 슬롯 표시) 을 선택시 더 다양한 시그널과 슬롯 관계를 설정할 수 있습니다.

회로도 처럼 신호가 연결되었다는 표시가 두 위젯(객체) 간에 표시가 됩니다.

이제 실행을 하면 조절 막대의 변경에 따라 진행 상태막대도 같이 변경됨을 알 수 있습니다.


2) 직접 코드에서 시그널과 슬롯을 명시하기

폼 편집기에서 시그널과 슬롯 관계를 맺었다는 것이 별도의 XML 설정로 되어 있어도 결국은 UIC (User Interface Compiler) 라는 도구에 의해 CPP 파일내에 정의되게 되어 있습니다.

이를 직접 CPP 상에서 정의할 수 있습니다. 해당 기능은 위젯이 아닌 다른 객체들 사이에서 정의하는데에도 이용될 수 있습니다.

우선 이전에 맺어둔 시그널과 슬롯 관계를 삭제합니다. Edit Signals/Slots 를 누른 상태에서 빨간색으로 표시된 화살표를 선택한 후 Del 키를 누르면 삭제가 됩니다.

폼 편집기를 벗어나기 전에 UI 를 구성하는 위젯인 horizontalSlider 와 progressBar 라는 객체 이름을 확인합니다. 이 둘은 Object Inspector 를 통해 확인이 가능합니다.

폼 편집기는 여기까지 보고 mainwindow.cpp 파일을 열어서 아래와 같이 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->progressBar, SLOT(setValue(int)));
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
s

여기서 connect 매크로에 대해서 알아 봅니다.

connect 매크로는 QT 에서 제공하는 시그널과 슬롯관계를 맺어주는 연결과 관련된 매크로로, 컴파일시 관련된 시그널과 슬롯관련 코드들이 매크로 안에 있는 값들을 기반으로 작성됩니다.

MainWindow 가 생성 중일때 connect 를 이용하는데,

connect(시그널을 전달하려는 객체, SIGNAL(시그널 이름), 시그널을 받는 객체, SLOT(슬롯 이름));

을 방식로 작성하면 됩니다.

이렇게 하면 연결 설정에서 지정한 것과 마찬가지로 시그널과 슬롯이 정의되어 동작됩니다.

시그널은 발생시 여러 슬롯에게 전달이 가능하므로 진행상태 막대 (프로그래스 바) 를 하나 더 만들어서도 연결을 정의할 수 있습니다.

폼 편집기에서 진행상태 막대 (프로그래스 바, Progress Bar) 를 추가하고 추가한 UI 위젯의 이름을 확인합니다.

connect 매크로를 활용해서 MainWindow 생성자에 아래 코드를 반영 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->progressBar, SLOT(setValue(int)));
    connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->progressBar_2, SLOT(setValue(int)));
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
 
cs

3) 연결된 시그널과 슬롯을 제거하기

반대로 연결된 시그널과 슬롯을 disconnect 라는 매크로를 이용해서 연결된 관계를 동적으로 해제할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->progressBar, SLOT(setValue(int)));
    connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->progressBar_2, SLOT(setValue(int)));
 
    disconnect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->progressBar, SLOT(setValue(int)));
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
 
cs

이렇게 정의를 하면 두개 중 하나만 연결이되어서 막대의 변화에 반응합니다.

작업 코드

004_myprogress.zip