버튼과 라벨을 하나씩 배치하고, 버튼이 더블 클릭되면 라벨의 텍스트가 바뀌는 clicks라는 예제입니다.
QPushButton은 한번 클릭한 경우와 두번 클릭한 경우 구분없이 clicked()시그널이 나옵니다.
여기선 더블클릭하면 doubleClicked()라는 시그널을 발생시키는 DoubleButton이란 버튼을 구현하고, 이 시그널을 받아서 처리하도록 슬롯을 만들것입니다.
이번회는 클래스를 두개를 만들기 때문에 소스양이 좀 많습니다.(사실 이건 많은것도 아니죠-_-;)
doublebutton.h
[code]
#include <QPushButton>
class DoubleButton : public QPushButton {
Q_OBJECT
public:
DoubleButton(QWidget *parent = 0);
signals:
void doubleClicked();
protected:
virtual void mouseDoubleClickEvent(QMouseEvent *event);
};
[/code]
doublebutton.cpp
[code]
#include "doublebutton.h"
DoubleButton::DoubleButton(QWidget *parent)
: QPushButton(trUtf8("눌러보세요"), parent) {
}
void DoubleButton::mouseDoubleClickEvent(QMouseEvent *event) {
QPushButton::mouseDoubleClickEvent(event);
emit doubleClicked();
}
[/code]
mainwidget.h
[code]
#include <QWidget>
class DoubleButton; class QLabel;
class MainWidget : public QWidget {
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
private slots:
void setLabelDoubleClicked();
private:
QLabel *label;
DoubleButton *button;
};
[/code]
mainwidget.cpp
[code]
#include <QLabel>
#include "mainwidget.h"
#include "doublebutton.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent) {
button = new DoubleButton(this);
label = new QLabel(trUtf8("클릭 안됨"), this);
connect(button, SIGNAL(doubleClicked()), this, SLOT(setLabelDoubleClicked()));
label->move(100, 0);
resize(200, 50);
}
void MainWidget::setLabelDoubleClicked() {
label->setText(trUtf8("더블 클릭"));
}
[/code]
main.cpp
[code]
#include <QApplication>
#include "mainwidget.h"
int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWidget mw;
mw.show();
return app.exec();
}
[/code]

실행화면
일단 Q_OBJECT라는 키워드는 나중에 설명할테니 패스하시구요, 우선 doublebutton.h파일의 7번째 줄을 보시면 처음보는 키워드가 보일 것입니다.
바로 signals 라는 키워드인데요, 뒤에 :를 붙여서 마치 public이나 private같은 접근한정자처럼 쓰였습니다.
이 키워드가 함수를 시그널로 만들어주는 키워드입니다.
사용법도 public등과 같이 signals:라고 그 다음부터 다른 한정자가 나오기 전까지는 전부 시그널로 처리됩니다.
일반적으로 시그널은 직접 호출될 일이 없기 때문에 원형만 선언하고 내용은 정의하지 않아도 됩니다.(물론 호출해서 일반함수로 쓰는 것도 가능하며, 이경우는 당연히 함수 정의도 있어야겠지요)
이제 그 다음줄에 있는 doubleClicked()라는 함수는 시그널로 이용할 수 있습니다.
남은 문제는 언제 이것을 발생시키느냐입니다.
이름을 그럴싸하게 지었다고 지가 알아서 튀어나올리는 만무하겠죠?
그럼 버튼이 더블클릭되는 시점이 언제인지를 알아야겠습니다.
이를 위해서 어떤 위젯이 더블클릭되면 호출되는 이벤트 처리 함수인 mouseDoubleClickEvent 함수를 오버라이딩하기로 합니다.
doublebutton.cpp파일의 8-11번째 줄을 보면 다음과 같이 적혀있습니다.
[code]
void DoubleButton::mouseDoubleClickEvent(QMouseEvent *event) {
QPushButton::mouseDoubleClickEvent(event);
emit doubleClicked();
}
[/code]
여기서 QPushButton::mouseDoubleClickEvent(event);를 호출하는 이유는, 혹시 모를 더블클릭관련된 다른 이벤트들이 처리되도록하기 위해서입니다.
제가아는 한에서 QPushButton이나 그 상위의 QWidget은 딱히 더블클릭에 대해서 아무것도 하지 않는 걸로 알고 있으므로 이경우는 저 라인이 있으나 없으나 똑같을 것입니다.
중요한건 그다음줄인데요, 여기서 또 emit 이라는 처음보는 키워드가 나옵니다.
사전을 찾아보시면 emit은 뱉다 라는 뜻이라고 나옵니다.
예, 말그대로 emit doubleClicked(); 라고 적으면 doubleClicked() 시그널을 뱉어냅니다.
참고로 이부분은 doubleClicked()를 호출하는 구문이 아닙니다.
큐티용 전처리기인 moc를 거쳐서 이부분은 (직접 그자리에서 치환되진 않지만 결과적으로 보면) 여기에 연결된 슬롯들을 호출하는 구문으로 치환될 것입니다.
이렇게 하여 시그널을 만들고 그것을 뱉는발생시키는 방법을 알아보았습니다.
참고로 signals는 다른 public같은 한정자와 같이 쓰면안됩니다.
signals 자체에 protected 한정자가 포함되어있기 때문입니다.(즉, 모든 시그널은 protected 멤버함수입니다.)
다음으로 슬롯을 만드는 방법을 알아보겠습니다.
(여기서도 일단 Q_OBJECT는 패스합니다)mainwidget.h를 보면 역시나 처음보는 키워드가 있습니다.
9번째 줄의 slots라는 키워드인데요, 뻔합니다. 이게 슬롯선언을 위한 키워드죠.
슬롯은 시그널과 달리 직접 호출되는 함수이기 때문에 원형만 선언하고 정의하지 않으면 링크단계에서 에러가 나며, 또 꼭 시그널에 의해 호출되지 않고 평범한 함수호출로도 자주 이용되기 때문에 접근 한정자가 없습니다.
그러므로 이경우는 private slots: 와 같이 private라는 접근 한정자를 달아주었습니다.
외부에서 호출가능하게 만들려면 public slots: 와 같이 해야겠지요.
signals와 마찬가지로 slots다음부터 다른 한정자가 다올때까지 선언된 함수들은 모두 슬롯으로 이용가능해집니다.
그러므로 다음줄에 적힌 setLabelDoubleClicked() 함수는 다른 시그널에 연결가능한 슬롯이 되었습니다.
그리고 mainwidget.cpp의 setLabelDoubleClicked()의 구현을 보면 심플합니다.
그냥 label의 setText()함수를 이용해서 더블클릭이란 글자로 바뀌도록 합니다.
이제 더블클릭되면 발생할 시그널과, 이를 연결할 슬롯이 준비되었으므로 둘을 연결하기만 하면됩니다.
mainwidget.cpp에서 MainWidget의 생성자를 봅시다.
connect(button, SIGNAL(doubleClicked()), this, SLOT(setLabelDoubleClicked()));
라고 적혀있죠? button의 시그널인 doubleClicked()와 this(MainWidget)의 setLabelDoubleClicked()를 연결합니다.
생성자에서 뭔가 하고싶은 말이 있으신 분이 계실지도 모르겠는데, 잠시 참아주세요.
이제 컴파일해보고 실행하고 버튼을 더블 클릭하면 라벨의 텍스트가 더블 클릭으로 바뀝니다.
별거 아닌 예제지만 시그널과 슬롯을 이용하기 위한 것들을 하나빼고 다 설명했습니다.
그럼 빠진 하나는? 기억력좋으신 분은 제가 Q_OBJECT를 패스라고 설명한걸 기억하실 텐데요, 바로 이 키워드가 핵심키워드입니다.
사실 이글에서 이 키워드와, 그리고 생성자에서 느낀 위화감을 설명해줄 Qt의 Meta-Object 시스템까지 소개할려고 했는데, 내용이 길어져서 다음회로 넘겨야 겠습니다.
이리하여, 다음회는 Meta-Object 시스템입니다.





















