0

i am trying to learn pyqt5 take look at the following code

qbtn = QPushButton('Quit', self)
qbtn.clicked.connect(QApplication.instance().quit)

clicked signature in qtwidgets.py

 def clicked(self, checked: bool = ...) -> None: ...

where is the implementation of the clicked method ? how it is not callable i mean it's method right ?

  print (qbtn.clicked())

output: TypeError: native Qt signal is not callable

and finally if it doesn't have any implementation how it effects the QPushButton ?

print(qbtn)
print (qbtn.clicked)
print (qbtn.clicked.connect)

output:

<PyQt5.QtWidgets.QPushButton object at 0x7f963ca88160>
<bound PYQT_SIGNAL clicked of QPushButton object at 0x7f963ca88160>
<built-in method connect of PyQt5.QtCore.pyqtBoundSignal object at 0x7f963ca91cc0> 

mehdi
  • 23
  • 2
  • 4
  • Where do you see "clicked signature in qtwidgets.py"? – musicamante Apr 12 '21 at 11:38
  • unfortunately i missed spell the name of file it's .pyi and ''i'' stand for interface therefor in this type of file there is no implementation but the main question remains (how clicked method is not callable) – mehdi Apr 12 '21 at 12:26
  • `qbtn.clicked` is not a method, it's an attribute that is bound to a signal. A signal is emitted by calling its `emit` method i.e. `qbtn.clicked.emit(qbtn.checked())`. – Heike Apr 12 '21 at 12:38

1 Answers1

1

There are two important aspects that should always be kept in mind:

  1. PyQt (similarly to PySide) is a binding: it is an interface to the Qt framework, and as such provides access to it using standard python functions and methods; in order to create it, a special tool is used, SIP, which actually creates the binding from objects exposed to python to those of Qt and viceversa (for PySide, the tool used is called Shiboken);
  2. signals are not methods, they are interfaces to which callable objects can connect to, and those objects will be called whenever the signal is emitted, provided they have a compatible signature;

The file you're referring to is a pyi file. From What does “i” represent in Python .pyi extension?:

The *.pyi files are used by PyCharm and other development tools to provide more information, such as PEP 484 type hints, than it is able to glean from introspection of extension types and methods. They are not intended to be imported, executed or used for any other purpose other than providing info to the tools. If you don't use use a tool that makes use of .pyi files then you can safely ignore this file.

You mentioned the following line:

def clicked(self, checked: bool = ...) -> None: ...

which is only found in those files, and is just that: an information.

Signals in C++ are declared in headers similarly to functions, having arguments that indicate the signal signature(s), and are then "transformed" into signals when Qt (or the program that declares its own signals) is compiled.[1]

Since PyQt and PySide are created using the aforementioned automated tools, the result is that signals might be listed as methods; notably, the official PySide docs list signals even including def: in PySide2 a specific "Signal" section is used, while in PySide6 they are not even identified as such.

In the python bindings, signals are unbound attributes for classes, but when a signal is referenced as a QObject instance, PyQt automatically binds the instance to the signal to create a bound signal.

>>> hasattr(QtWidgets.QPushButton.clicked, 'emit')
False
>>> hasattr(QtWidgets.QPushButton().clicked, 'emit')
True

You can see that the signal is dynamically bound by using a simple id (which should return an unique and constant value for an object):

>>> b = QtWidgets.QPushButton()
>>> id(b.clicked)
2971296616
>>> id(b.clicked)
2971299208
# or even:
>>> b.clicked == b.clicked
False

So, what you see from some documentation or reference file, is primarily the signature used to create the signal, but also the expected signature for the signal emission/receiver, similarly to what can be done in Python when declaring a new signal (with the difference that it's not possible to define default values, like the checked=False of QAbstractButton).

[1] this is a major oversimplification, I don't have enough knowledge of C++ to explain how exactly signal creation works, but it's just for the sake of explanation.

musicamante
  • 41,230
  • 6
  • 33
  • 58