tags:

views:

103

answers:

4

In the Qt world what is the difference of events and signal/slots? Does one replace the other? Are events an abstraction of signal/slots?

Thanks in advance

+3  A: 

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.

jkerian
"Events are typically handled in Qt with signals/slots" - actually no... QEvent objects are always passed around via overloaded virtuals! For example, there's no signal "keyDown" in QWidget - instead, keyDown is a virtual function.
Stefan Monov
Agree with stefan, actually a pretty confusing piece of Qt
Harald Scheirich
@Stefan: I would argue that few enough Qt apps override keyDown (and instead mostly use signals such as QAbstractButton::clicked and QLineEdit::editingFinished) to justify "typically". I've certainly snagged keyboard input before, but it's not the usual way of handling events.
jkerian
@jkerian: after your edit (clarifying what you mean by "event"), your post is now correct. I refrain from reusing words like that, though. Things are muddy enough without calling signals "a type of events".
Stefan Monov
+1  A: 

The Qt Documentation probably explains it best

In Qt, events are objects, derived from the abstract QEvent class, that represent things that have happened either within an application or as a result of outside activity that the application needs to know about. Events can be received and handled by any instance of a QObject subclass, but they are especially relevant to widgets. This document describes how events are delivered and handled in a typical application.

So events and signal/slots are two parallel mechanisms accomplishing the same things, in general an event will be generated by an outside entity (e.g. Keyboard, Mouswheel) and will be delivered through the event loop in QApplication. In general unless you set up the code you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.

Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more) but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivers immediately or deferred via a queue (if you are using threads) A signal can be generated

Harald Scheirich
+4  A: 

In Qt, signals and events are both implementations of the Observer pattern. They are used in different situations because they have different strengths and weaknesses.

First of all let's define what we mean by 'Qt event' exactly: a virtual function in a Qt class, which you're expected to reimplement in a base class of yours if you want to handle the event. It's related to the Template method pattern.

Note how I used the word "handle". Indeed, here's a basic difference between the intent of signals and events:

  • You "handle" events
  • You "get notified of" signal emissions

The difference is that when you "handle" the event, you take on the responsibility to "respond" with a behavior that is useful outside the class. For example, consider an app that has a button with a number on it. The app needs to let the user focus the button and change the number by pressing the "up" and "down" keyboard keys. Otherwise the button should function like a normal QPushButton (it can be clicked, etc). In Qt this is done by creating your own little reusable "component" (subclass of QPushButton), which reimplements QWidget::keyPressEvent. Pseudocode:

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)

See? This code presents a new abstraction: a widget that acts like a button, but with some extra functionality. We added this functionality very conveniently:

  • Since we reimplemented a virtual, our implementation automatically became encapsulated in our class. If Qt's designers had made keyPressEvent a signal, we would need to decide whether to inherit QPushButton or just externally connect to the signal. But that would be stupid, since in Qt you're always expected to inherit when writing a widget with a custom behavior (for good reason - reusability/modularity). So by making keyPressEvent an event, they convey their intent that keyPressEvent is just a basic building block of functionality. If it were a signal, it'd look like a user-facing thing, when it's not intended to be.
  • Since the base-class-implementation of the function is available, we easily implement the Chain-of-responsibility pattern by handling our special cases (up&down keys) and leaving the rest to the base class. You can see this would be nearly impossible if keyPressEvent were a signal.

The design of Qt is well thought out - they made us fall into the pit of success by making it easy to do the right thing and hard to do the wrong thing (by making keyPressEvent an event).

On the other hand, consider the simplest usage of QPushButton - just instantiating it and getting notified when it's clicked:

button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())

This is clearly meant to be done by the user of the class:

  • if we had to subclass QPushButton everytime we want some button to notify us of a click, that would require a lot of subclasses for no good reason! A widget that always shows a "Hello world" messagebox when clicked is useful only in a single case - so it's totally not reusable. Again, we have no choice but to do the right thing - by connecting to it externally.
  • we may want to connect several slots to clicked() - or connect several signals to sayHello(). With signals there is no fuss. With subclassing you would have to sit down and ponder some class diagrams until you decide on an appropriate design.

Note that one of the places QPushButton emits clicked() is in its mousePressEvent() implementation. That doesn't mean clicked() and mousePressEvent() are interchangable - just that they're related.

So signals and events have different purposes (but are related in that both let you "subscribe" to a notification of something happening).

Stefan Monov
We might be having version issues here, but don't you mean 'keyPress/ReleaseEvent'?
jkerian
@jkerian: Yep - thanks!
Stefan Monov
+1  A: 

Events are dispatched by event loop. Each GUI program need event loop, whatever you write it Windows or Linux, using Qt, WinApi or any other GUI library. As well each thread has it's own event loop. In Qt "GUI Event Loop" (witch is 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 mechanism, in process of compilations using moc (meta-object compiler), it is changed to callback functions.

Event should have one receiver, witch should dispatch it. No one else should get that event.

All slots connected to emitted signal will be executed.

You shouldn't think of Signals as events, because as you can read in Qt doc:

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 time when event loop dispatch all events that came earlier. Because of this, execution of the cod after sending event or signal is different. Cod fallowing sending event will be run immediately. With signals and slots mechanism it depend on connection type. Normally it will be executed after all slots. Using Qt::QueuedConnection, it will be executed immediately, just like events. Check all connections type at Qt Doc

firescreamer