답변:
Qt는 문서는 아마도 가장 잘 설명 :
Qt에서 이벤트는 추상
QEvent
클래스 에서 파생 된 객체로, 애플리케이션 내에서 또는 애플리케이션이 알아야하는 외부 활동의 결과로 발생한 일을 나타냅니다. 이벤트는QObject
서브 클래스 의 모든 인스턴스에서 수신하고 처리 할 수 있지만 특히 위젯과 관련이 있습니다. 이 문서는 일반적인 애플리케이션에서 이벤트가 전달되고 처리되는 방법을 설명합니다.
따라서 이벤트와 신호 / 슬롯은 동일한 작업을 수행하는 두 개의 병렬 메커니즘입니다. 일반적으로 이벤트는 외부 엔티티 (예 : 키보드 또는 마우스 휠)에 의해 생성되며 .NET의 이벤트 루프를 통해 전달됩니다 QApplication
. 일반적으로 코드를 설정하지 않으면 이벤트가 생성되지 않습니다. QObject::installEventFilter()
적절한 함수를 재정 의하여 하위 클래스 개체에서 이벤트를 필터링 하거나 처리 할 수 있습니다 .
신호와 슬롯은 생성 및 수신이 훨씬 더 쉽고 두 개의 QObject
하위 클래스를 연결할 수 있습니다 . 메타 클래스를 통해 처리되지만 (자세한 내용은 moc_classname.cpp 파일을 참조하십시오) 생성 할 클래스 간 통신의 대부분은 신호와 슬롯을 사용합니다. 신호는 즉시 전달되거나 대기열을 통해 지연 될 수 있습니다 (스레드를 사용하는 경우).
신호가 생성 될 수 있습니다.
Qt에서 신호와 이벤트는 모두 Observer 패턴의 구현입니다 . 강점과 약점이 다르기 때문에 다양한 상황에서 사용됩니다.
먼저 'Qt 이벤트'가 의미하는 바를 정확히 정의 해 보겠습니다. Qt 클래스의 가상 함수, 이벤트를 처리하려면 기본 클래스에서 다시 구현해야합니다. 템플릿 메서드 패턴 과 관련이 있습니다.
" 핸들 " 이라는 단어를 어떻게 사용했는지 주목 하세요. 실제로 신호와 이벤트의 의도 사이의 기본적인 차이점은 다음과 같습니다.
차이점은 이벤트를 "처리"할 때 클래스 외부에서 유용한 동작으로 "응답"할 책임이 있다는 것입니다. 예를 들어, 번호가있는 버튼이있는 앱을 생각해보십시오. 앱은 사용자가 버튼에 초점을 맞추고 "위"및 "아래"키보드 키를 눌러 숫자를 변경할 수 있도록해야합니다. 그렇지 않으면 버튼이 정상처럼 작동해야합니다 QPushButton
(클릭 할 수 있음). Qt에서 이것은 재사용 가능한 작은 "컴포넌트"(의 하위 클래스 QPushButton
) 를 생성하여 수행되며 QWidget::keyPressEvent
. 의사 코드 :
class NumericButton extends QPushButton
private void addToNumber(int value):
// ...
reimplement base.keyPressEvent(QKeyEvent event):
if(event.key == up)
this.addToNumber(1)
else if(event.key == down)
this.addToNumber(-1)
else
base.keyPressEvent(event)
보다? 이 코드는 새로운 추상화, 즉 버튼처럼 작동하지만 추가 기능이있는 위젯을 제공합니다. 이 기능을 매우 편리하게 추가했습니다.
keyPressEvent
신호를 만들었다면 우리는 신호를 상속할지 아니면 QPushButton
외부에서 연결 할지 결정해야합니다 . 그러나 그것은 어리석은 일입니다. Qt 에서는 사용자 정의 동작 (재사용 성 / 모듈 화성)을 사용하여 위젯을 작성할 때 항상 상속받을 것으로 예상되기 때문입니다. 따라서 keyPressEvent
이벤트 를 만들어 keyPressEvent
기능의 기본 구성 요소 인 의도를 전달 합니다. 신호라면 의도하지 않았을 때 사용자를 향한 것처럼 보일 것입니다.keyPressEvent
신호 라면 거의 불가능하다는 것을 알 수 있습니다 .Qt의 디자인은 잘 짜여져 있습니다. 그들은 옳은 일을 쉽게하고 잘못된 일을 어렵게함으로써 성공의 구덩이에 빠지게 했습니다 (keyPressEvent를 이벤트로 만들어서).
반면에, 간단한 사용을 고려 QPushButton
- 그냥 인스턴스화과 클릭 때 통지를 얻는 :
button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())
이것은 클래스 의 사용자 가 수행해야하는 작업입니다 .
QPushButton
클릭을 알리는 버튼을 원할 때마다 서브 클래스 를해야한다면 정당한 이유없이 많은 서브 클래스가 필요할 것입니다 ! messagebox
클릭 할 때 항상 "Hello world"를 표시하는 위젯 은 한 가지 경우에만 유용하므로 완전히 재사용 할 수 없습니다. 다시 말하지만, 우리는 외부 적으로 연결함으로써 올바른 일을 할 수밖에 없습니다.clicked()
연결하거나 여러 신호를에 연결할 수 sayHello()
있습니다. 신호로는 소란이 없습니다. 서브 클래 싱을 사용하면 적절한 디자인을 결정할 때까지 몇 가지 클래스 다이어그램을 숙고해야합니다.QPushButton
방출 하는 장소 중 하나 clicked()
는 mousePressEvent()
구현에 있습니다. 그 뜻은 아닙니다 clicked()
와 mousePressEvent()
교환 할 수 있습니다 - 그들이 관련있어 그냥.
따라서 신호와 이벤트는 서로 다른 목적을 갖습니다 (하지만 두 가지 모두 발생하는 알림을 "구독"할 수 있다는 점에서 관련됨).
지금까지 답변이 마음에 들지 않습니다. – 질문의이 부분에 집중하겠습니다.
이벤트는 신호 / 슬롯의 추상화입니까?
짧은 대답 : 아니요. 긴 대답은 "더 나은"질문을 제기합니다. 신호와 이벤트는 어떤 관련이 있습니까?
유휴 메인 루프 (예 : Qt)는 일반적으로 운영 체제의 select () 호출에서 "고착"됩니다. 이 호출은 응용 프로그램을 "잠자기"상태로 만들고, 소켓이나 파일 또는 커널에 요청하는 모든 것을 전달하는 동안 다음을 요청합니다. 이러한 항목이 변경되면 select () 호출이 반환되도록합니다. – 그리고 세계의 주인 인 커널은 그것이 언제 일어나는지 알고 있습니다.
select () 호출의 결과는 다음과 같습니다. 소켓의 새 데이터가 X11에 연결되고, 우리가 수신하는 UDP 포트에 대한 패킷이 들어 왔습니다. – 그 것은 Qt 신호도 아니고 Qt 이벤트도 아닙니다. Qt 메인 루프는 새로운 데이터를 하나, 다른 하나 또는 무시할지 여부를 스스로 결정합니다.
Qt는 keyPressEvent ()와 같은 메서드 (또는 여러 메서드)를 호출하여 효과적으로 Qt 이벤트로 변환 할 수 있습니다. 또는 Qt는 신호를 방출하여 사실상 해당 신호에 등록 된 모든 함수를 조회하고 차례로 호출합니다.
이 두 가지 개념의 한 가지 차이점은 여기에서 볼 수 있습니다. 슬롯은 해당 신호에 등록 된 다른 슬롯이 호출되는지 여부에 대한 투표가 없습니다. – 이벤트는 체인과 비슷하며 이벤트 핸들러는 해당 체인을 중단할지 여부를 결정합니다. 이 점에서 신호는 별이나 나무처럼 보입니다.
이벤트는 트리거되거나 신호로 완전히 바뀔 수 있습니다 (하나만 내보내고 "super ()"를 호출하지 않음). 신호는 이벤트로 변환 될 수 있습니다 (이벤트 핸들러 호출).
케이스에 의존하는 것을 추상화하는 것 : clicked ()-신호는 마우스 이벤트를 추상화합니다 (너무 많이 움직이지 않고 버튼이 위아래로 다시 내려갑니다). 키보드 이벤트는 낮은 수준의 추상화입니다 (果 또는 é와 같은 것은 내 시스템의 여러 키 입력 임).
아마도 focusInEvent ()는 그 반대의 예일 수 있습니다. clicked () 신호를 사용할 수 있고 추상화 할 수는 있지만 실제로 사용하는지 모르겠습니다.
이벤트는 이벤트 루프에 의해 전달됩니다. 각 GUI 프로그램에는 Qt, Win32 또는 기타 GUI 라이브러리를 사용하여 Windows 또는 Linux로 작성하는 이벤트 루프가 필요합니다. 또한 각 스레드에는 자체 이벤트 루프가 있습니다. Qt에서 "GUI Event Loop"(모든 Qt 애플리케이션의 메인 루프)는 숨겨져 있지만 다음을 호출하여 시작합니다.
QApplication a(argc, argv);
return a.exec();
OS 및 기타 응용 프로그램이 프로그램에 보내는 메시지는 이벤트로 전달됩니다.
신호와 슬롯은 Qt 메커니즘입니다. moc (meta-object compiler)를 사용한 컴파일 과정에서 콜백 함수로 변경됩니다.
이벤트에는 하나의 수신자가 있어야하며이를 전달해야합니다. 다른 누구도 그 이벤트를 받아서는 안됩니다.
방출 된 신호에 연결된 모든 슬롯이 실행됩니다.
Qt 문서에서 읽을 수 있듯이 Signals를 이벤트로 생각해서는 안됩니다.
신호가 방출되면 연결된 슬롯은 보통 일반 함수 호출처럼 즉시 실행됩니다. 이 경우 신호 및 슬롯 메커니즘은 GUI 이벤트 루프와 완전히 독립적입니다.
이벤트를 보낼 때 이벤트 루프가 이전에 발생한 모든 이벤트를 전달할 때까지 잠시 기다려야합니다. 이로 인해 이벤트 나 시그널을 보낸 후 코드 실행이 다릅니다. 이벤트 전송 후 코드가 즉시 실행됩니다. 신호 및 슬롯 메커니즘을 사용하면 연결 유형에 따라 다릅니다. 일반적으로 모든 슬롯 후에 실행됩니다. Qt :: QueuedConnection을 사용하면 이벤트처럼 즉시 실행됩니다. Qt 문서에서 모든 연결 유형을 확인하십시오 .
When you send an event, it must wait for time when event loop dispatch all events that came earlier. Because of this, execution of the cod after sending event or signal is different
이벤트 처리에 대해 자세히 설명하는 기사가 있습니다. http://www.packtpub.com/article/events-and-signals
여기서 이벤트와 신호의 차이점에 대해 설명합니다.
이벤트와 신호는 동일한 작업을 수행하는 데 사용되는 두 개의 병렬 메커니즘입니다. 일반적인 차이점으로 신호는 위젯을 사용할 때 유용하지만 이벤트는 위젯을 구현할 때 유용합니다. 예를 들어, QPushButton과 같은 위젯을 사용하는 경우, 신호가 방출되도록 한 낮은 수준의 마우스 누르기 또는 키 누르기 이벤트보다 clicked () 신호에 더 관심이 있습니다. 그러나 QPushButton 클래스를 구현하는 경우 마우스 및 키 이벤트에 대한 코드 구현에 더 관심이 있습니다. 또한 일반적으로 이벤트를 처리하지만 신호 방출로 알림을받습니다.
받아 들여지는 답변이 동일한 문구 중 일부를 사용하기 때문에 이것은 그것에 대해 말하는 일반적인 방법 인 것 같습니다.
Kuba Ober 의이 답변에 대한 아래의 유용한 의견을 참조하십시오. 이로 인해 약간 단순한 지 궁금합니다.
event
. 신호와 슬롯은 구체적 으로 메소드이며, 연결 메커니즘은 신호가 연결된 것으로 나열된 하나 이상의 슬롯을 호출 할 수 있도록하는 데이터 구조입니다. 신호 / 슬롯을 이벤트의 "하위 집합"또는 "변형"으로 말하는 것은 말도 안되며 그 반대도 마찬가지라는 것을 알기를 바랍니다. 그들은 정말 다른 것들 일 일부 위젯의 맥락에서 유사한 목적에 사용되는. 그게 다야. 더 많이 일반화할수록 IMHO가되는 데 덜 도움이됩니다.
요약 : 신호와 슬롯은 간접 메서드 호출입니다. 이벤트는 데이터 구조입니다. 그래서 그들은 아주 다른 동물입니다.
이들이 함께 모이는 유일한 시간은 스레드 경계를 넘어 슬롯 호출이 이루어질 때입니다. 슬롯 호출 인수는 데이터 구조에 압축되어 수신 스레드의 이벤트 큐에 이벤트로 전송됩니다. 수신 스레드에서 QObject::event
메서드는 인수의 압축을 풀고 호출을 실행하며 차단 연결 인 경우 결과를 반환 할 수 있습니다.
망각으로 일반화하려는 경우 이벤트를 대상 객체의 event
메서드 를 호출하는 방법으로 생각할 수 있습니다. 이것은 유행을 따르는 간접적 인 메서드 호출입니다. 그러나 그것이 진정한 진술이라하더라도 그것에 대해 생각하는 데 도움이되는 방법이라고 생각하지 않습니다.
이벤트 (사용자 / 네트워크 상호 작용의 일반적인 의미에서)는 일반적으로 신호 / 슬롯이있는 Qt에서 처리되지만 신호 / 슬롯은 다른 많은 작업을 수행 할 수 있습니다.
QEvent 및 하위 클래스는 기본적으로 프레임 워크가 코드와 통신 할 수 있도록 표준화 된 데이터 패키지입니다. 어떤 식 으로든 마우스에주의를 기울이고 싶다면 QMouseEvent API를 살펴보기 만하면됩니다. 라이브러리 디자이너는 마우스가 한 구석에서 무엇을했는지 알아 내야 할 때마다 휠을 재발 명 할 필요가 없습니다. Qt API.
어떤 종류의 이벤트 (일반적인 경우)를 기다리고 있다면 슬롯은 거의 확실하게 QEvent 서브 클래스를 인수로 받아들입니다.
즉, 신호를 활성화하는 원래의 원동력은 종종 일종의 사용자 상호 작용이나 기타 비동기 활동이 될 것이지만 신호와 슬롯은 QEvents없이 확실히 사용할 수 있습니다. 그러나 때로는 코드가 특정 신호를 발사하는 것이 올바른 일인 지점에 도달 할 수 있습니다. 예를 들어, 긴 프로세스 동안 진행률 표시 줄에 연결된 신호를 발생시키는 것은 해당 지점까지 QEvent를 포함하지 않습니다.
Leow Wee Kheng의 '이벤트 처리' 를 읽으 면서이 질문을 발견했습니다 . 또한 다음과 같이 말합니다.
Jasmine Blanchette 말한다 :
표준 함수 호출이나 신호 및 슬롯이 아닌 이벤트를 사용하는 주된 이유는 이벤트를 동기식 및 비동기식으로 (sendEvent () 또는 postEvents () 호출 여부에 따라) 사용할 수있는 반면, 함수를 호출하거나 슬롯은 항상 동기식입니다. 이벤트의 또 다른 장점은 필터링 할 수 있다는 것입니다.
제 생각에는 이벤트는 완전히 중복되어 버릴 수 있습니다. Qt가 이미있는 그대로 설정되어 있다는 점을 제외하고는 신호를 이벤트 또는 신호로 이벤트로 대체 할 수없는 이유가 없습니다. 대기중인 신호는 이벤트로 래핑되며 이벤트는 신호로 래핑 될 수 있습니다. 예를 들면 다음과 같습니다.
connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});
( 더 이상은 아님) 에서 mouseMoveEvent()
찾은 편의 기능을 대체하고 장면 관리자가 항목에 대해 방출 할 신호를 처리 합니다. 신호가 일부 외부 엔티티에 의해 항목을 대신하여 방출된다는 사실은 중요하지 않으며 허용되지 않는 것으로 추정되는 경우에도 Qt 구성 요소의 세계에서 자주 발생합니다 (Qt 구성 요소는이 규칙을 우회하는 경우가 많습니다). 그러나 Qt는 많은 다른 디자인 결정의 대기업이며 오래된 코드를 깨는 것에 대한 두려움 때문에 (어쨌든 충분히 자주 발생합니다) 돌로 던졌습니다.QWidget
QQuickItem
mouseMove
QObject
필요한 경우 상위-하위 계층 을 전파하는 이점이 있습니다. 신호 / 슬롯 연결은 특정 조건이 충족 될 때 직접 또는 간접적으로 함수를 호출하겠다는 약속 일뿐입니다. 신호 및 슬롯과 관련된 처리 계층 구조가 없습니다.
accepted
그것을 처리하는 신호 및 슬롯을 참조 매개 변수를 또는 당신은있는 참조 매개 변수로 구조를 가질 수 accepted
필드. 그러나 Qt는 디자인 선택을했고 이제는 결정적으로 설정되었습니다.