In this chapter, we saw that it is possible to create hybrid console–GUI applications. This can actually be taken much further—for example, by including all the GUI code within the scope of an if block and executing it only if PyQt is installed. This would allow us to create a GUI application that could fall back to "console mode" if some of our users did not have PyQt.
We also saw that unlike conventional batch-processing programs, GUI applications have an event loop that runs continuously, checking for user events like mouse clicks and key presses, and system events like timers timing out or windows being revealed, and terminating only when requested to do so.
The Calculate application showed us a very simple but structurally typical dialog __init__() method. The widgets are created, laid out, and connected, and one or more other methods are used to respond to user interaction. The Currency application used the same approach, only with a more sophisticated interface, and more complex behavior and processing. The Currency application also showed that we can connect multiple signals to a single slot without formality.
PyQt's signals and slots mechanism allows us to handle user interaction at a much higher level of abstraction than the specific details of mouse clicks and key presses. It lets us focus on what users want to do rather than on how they asked to do it. All the PyQt widgets emit signals to announce state changes and other important occurrences; and most of the time we can ignore the signals. But for those signals that we are interested in, it is easy to use QObject.connect() to ensure that the function or method of our choice is called when the signal is emitted so that we can respond to it. Unlike C++/Qt, which must designate certain methods specially as slots, in PyQt we are free to use any callable, that is, any function or method, as a slot.
We also saw how to connect multiple signals to a single slot, and how to use partial function application or the sender() method so that the slot can respond appropriately depending on which widget signalled it.
We also learned that we do not have to formally declare our own custom signals: We can simply emit them using QObject.emit(), along with any additional parameters we want to pass.