analitics

Pages

Friday, June 16, 2017

Python Qt4 - part 002.

This tutorial covers only part of the practice of using G.U.I. (graphical user interface) elements in PyQt4.
First of all, I will start with the theory and then I will simply exemplify how these work.
There are three basic elements called: Event, Signal, and Slot.
Since all GUI applications are driven by events, we will have several elements interconnected with signals and slots.
What do we need to know?
Events are generated mainly by the user of an application into the event processing system.
The event processing system in PyQt4 is built with the signal and slot mechanism.
The event processing system is an event model with three participants:
  • event source 
  • event object 
  • event target 
Signals and slots are used for communication between objects.
A signal is emitted when something of potential interest happens.
If a signal is connected to a slot then the slot is called when the signal is emitted.
Rules of signals and slots:
  • A signal may be connected to many slots.
  • A signal may also be connected to another signal.
  • Signal arguments may be any Python type.
  • A slot may be connected to many signals.
  • Connections may be direct (ie. synchronous) or queued (ie. asynchronous).
  • Connections may be made across threads.
  • Signals may be disconnected.
A signal (specifically an unbound signal) is an attribute of a class that is a subclass of QObject.
Signals are connected to slots using the connect() method of a bound signal.
Signals are disconnected from slots using the disconnect() method of a bound signal.
Signals are emitted from using the emit() method of a bound signal.
Example of a signal used into the myclassapp PyQt4 application:
I create a new signal called closeApp.
closeApp = QtCore.pyqtSignal()
This signal is emitted during a mouse press event.
def mousePressEvent(self, event):
    self.myclassapp.closeApp.emit()
The signal is connected to the close() slot of the QtGui.QMainWindow.
self.myclassapp.closeApp.connect(self.close)
I did not show the entire example here because the reason was to show the direct connection between the signal, the event and the slot.
The events are functions or methods are executed in response to user’s actions like clicking on a button, selecting an item from a collection or a mouse click etc.
Another simple example with o application with two buttons:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

def window():
   app = QApplication(sys.argv)
   win = QDialog()
   mybutton1= QPushButton(win)
   mybutton1.setText("Button1")
   mybutton1.move(50,20)
   mybutton1.clicked.connect(mybutton1_clicked)

   mybutton2= QPushButton(win)
   mybutton2.setText("Button2")
   mybutton2.move(50,50)
   QObject.connect(mybutton2,SIGNAL("clicked()"),mybutton2_clicked)

   win.setGeometry(100,100,200,100)
   win.setWindowTitle("PyQt Event Signal Slot")
   win.show()
   sys.exit(app.exec_())

def mybutton1_clicked():
   print "Button 1 clicked"

def mybutton2_clicked():
   print "Button 2 clicked"

if __name__ == '__main__':
   window()
The result of clicking on these buttons is something like that:
Button 2 clicked
Button 2 clicked
Button 1 clicked
Button 1 clicked
Button 1 clicked
Button 2 clicked
Button 1 clicked
Button 2 clicked
All widgets used to build the G.U.I. (graphical user interface) act as the source of such events, see the mybutton1 source code part.
Now about this part of the source code, I just used to exemplify how the signals are connected to the slots:
QObject.connect(mybutton2,SIGNAL("clicked()"),mybutton2_clicked)
So each PyQt widget (which is derived from QObject class) is designed to emit a signal in response to one or more events.
The signal on its own does not perform any action. Instead, it is connected to a slot. The slot can be any callable Python function.
And this part of the source code is exemplified with mybutton2.
Signals are complex due to their use (how they are used).
More theory about the signals.
To send a signal across threads we have to use the Qt.QueuedConnection parameter.
There is also a special form of a PyQt4 signal known as a short-circuit signal.
The short-circuit signals implicitly declare each argument as being of type PyQt_PyObject.
Short-circuit signals do not have a list of arguments or the surrounding parentheses.
Short-circuit signals may only be connected to slots that have been implemented in Python.
They cannot be connected to Qt slots or the Python callables that wrap Qt slots.
The older style of connecting signals and slots will continue to be supported throughout the life of PyQt4.