Qt 이벤트 및 신호 / 슬롯
Qt 세계에서 이벤트와 신호 / 슬롯의 차이점은 무엇입니까?
하나가 다른 하나를 대체합니까? 이벤트는 신호 / 슬롯의 추상화입니까?
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)
보다? 이 코드는 새로운 추상화, 즉 버튼처럼 작동하지만 추가 기능이있는 위젯을 제공합니다. 이 기능을 매우 편리하게 추가했습니다.
- 가상을 다시 구현했기 때문에 구현은 자동으로 클래스에 캡슐화되었습니다. Qt의 설계자가
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()
교환 할 수 있습니다 - 그들이 관련있어 그냥.
따라서 신호와 이벤트는 서로 다른 목적을 갖습니다 (하지만 두 가지 모두 발생하는 알림을 "구독"할 수 있다는 점에서 관련됨).
지금까지 답변이 마음에 들지 않습니다. – 질문의이 부분에 집중하겠습니다.
이벤트는 신호 / 슬롯의 추상화입니까?
짧은 대답 : 아니요. 긴 대답은 "더 나은"질문을 제기합니다. 신호와 이벤트는 어떤 관련이 있습니까?
An idle main loop (Qt’s for example) is usually “stuck” in a select() call of the operating system. That call makes the application “sleep”, while it passes a bunch of sockets or files or whatever to the kernel asking for: if something changes on these, let the select() call return. – And the kernel, as the master of the world, knows when that happens.
The result of that select() call could be: new data on the socket connect to X11, a packet to a UDP port we listen on came in, etc. – That stuff is neither a Qt signal, nor a Qt event, and the Qt main loop decides itself if it turns the fresh data into the one, the other or ignores it.
Qt could call a method (or several) like keyPressEvent(), effectively turning it into a Qt event. Or Qt emits a signal, which in effect looks up all functions registered for that signal, and calls them one after the other.
One difference of those two concepts is visible here: a slot has no vote on whether other slots registered to that signal will get called or not. – Events are more like a chain, and the event handler decides if it interrupts that chain or not. Signals look like a star or tree in this respect.
An event can trigger or be entirely turned into a signal (just emit one, and don’t call “super()”). A signal can be turned into an event (call an event handler).
What abstracts what depends on the case: the clicked()-signal abstracts mouse events (a button goes down and up again without too much moving around). Keyboard events are abstractions from lower levels (things like 果 or é are several key strokes on my system).
Maybe the focusInEvent() is an example of the opposite: it could use (and thus abstract) the clicked() signal, but I don’t know if it actually does.
Events are dispatched by the event loop. Each GUI program needs an event loop, whatever you write it Windows or Linux, using Qt, Win32 or any other GUI library. As well each thread has its own event loop. In Qt "GUI Event Loop" (which is the main loop of all Qt applications) is hidden, but you start it calling:
QApplication a(argc, argv);
return a.exec();
Messages OS and other applications send to your program are dispatched as events.
Signals and slots are Qt mechanisms. In the process of compilations using moc (meta-object compiler), they are changed to callback functions.
Event should have one receiver, which should dispatch it. No one else should get that event.
All slots connected to the emitted signal will be executed.
You shouldn't think of Signals as events, because as you can read in the Qt documentation:
When a signal is emitted, the slots connected to it are usually executed immediately, just like a normal function call. When this happens, the signals and slots mechanism is totally independent of any GUI event loop.
When you send an event, it must wait for some time until the event loop dispatches all events that came earlier. Because of this, execution of the code after sending event or signal is different. Code following sending an event will be run immediately. With the signals and slots mechanisms it depends on the connection type. Normally it will be executed after all slots. Using Qt::QueuedConnection, it will be executed immediately, just like events. Check all connection types in the Qt documentation.
There is an article that discusses event processing in some detail: http://www.packtpub.com/article/events-and-signals
It discussions the difference between events and signals here:
Events and signals are two parallel mechanisms used to accomplish the same thing. As a general difference, signals are useful when using a widget, whereas events are useful when implementing the widget. For example, when we are using a widget like QPushButton, we are more interested in its clicked() signal than in the low-level mouse press or key press events that caused the signal to be emitted. But if we are implementing the QPushButton class, we are more interested in the implementation of code for mouse and key events. Also, we usually handle events but get notified by signal emissions.
This seems to be a common way of talking about it, as the accepted answer uses some of the same phrases.
Note, please see helpful comments below on this answer from Kuba Ober, that make me wonder if it might be a bit simplistic.
TL;DR: Signals and slots are indirect method calls. Events are data structures. So they are quite different animals.
The only time when they come together is when slot calls are made across thread boundaries. The slot call arguments are packed up in a data structure and get sent as an event to the receiving thread's event queue. In the receiving thread, the QObject::event
method unpacks the arguments, executes the call, and possibly returns the result if it was a blocking connection.
If we're willing to generalize to oblivion, one could think of events as as a way of invoking the target object's event
method. This is an indirect method call, after a fashion - but I don't think it's a helpful way of thinking about it, even if it's a true statement.
Events (in a general sense of user/network interaction) are typically handled in Qt with signals/slots, but signals/slots can do plenty of other things.
QEvent and its subclasses are basically just little standardized data packages for the framework to communicate with your code. If you want to pay attention to the mouse in some way, you only have to look at the QMouseEvent API, and the library designers don't have to reinvent the wheel every time you need to figure out what the mouse did in some corner of the Qt API.
It is true that if you're waiting for events (again in the general case) of some sort, your slot will almost certainly accept a QEvent subclass as an argument.
With that said, signals and slots can certainly be used without QEvents, although you'll find that the original impetus for activating a signal will often be some kind of user interaction or other asynchronous activity. Sometimes, however, your code will just reach a point where firing off a certain signal will be the right thing to do. For example, firing off a signal connected to a progress bar during a long process doesn't involve a QEvent up to that point.
Another minor pragmatic consideration: emitting or receiving signals requires inheriting QObject
whereas an object of any inheritance can post or send an event (since you invoke QCoreApplication.sendEvent()
or postEvent()
) This is usually not an issue but: to use signals PyQt strangely requires QObject
to be the first super class, and you might not want to rearrange your inheritance order just to be able to send signals.)
In my opinion events are completely redundant and could be thrown out. There is no reason why signals could not be replaced by events or events by signals, except that Qt is already set up as it is. Queued signals are wrapped by events and events could conceivably be wrapped by signals, for example:
connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});
Would replace the convenience mouseMoveEvent()
function found in QWidget
(but not in QQuickItem
anymore) and would handle mouseMove
signals that a scene manager would emit for the item. The fact that the signal is emitted on behalf of the item by some outside entity is unimportant and happens quite often in the world of Qt components, even though it is supposedly not allowed (Qt components often circumvent this rule). But Qt is a conglomerate of many different design decisions and pretty much cast in stone for fear of breaking old code (which happens often enough anyway).
I found this question while reading 'Event processing' by Leow Wee Kheng. It also says:
참고URL : https://stackoverflow.com/questions/3794649/qt-events-and-signal-slots
'program story' 카테고리의 다른 글
UIVisualEffectView 및 / 또는 UIBlurEffect를 페이드 인 및 아웃하는 방법은 무엇입니까? (0) | 2020.09.13 |
---|---|
List (of T)와 Collection (of T)의 차이점은 무엇입니까? (0) | 2020.09.13 |
node-jwt-simple이있는 passport-local (0) | 2020.09.12 |
ELF 파일과 bin 파일의 차이점은 무엇입니까? (0) | 2020.09.12 |
개체 목록이 포함 된 구획 가능 개체를 전달하는 방법은 무엇입니까? (0) | 2020.09.12 |