pyqt5:QPushButton类,单击方法并连接



我正在尝试学习pyqt5——看看下面的代码

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

qtwidgets.py 中的点击签名

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

点击方法的实现在哪里?它怎么不可调用?我的意思是它的方法对吗?

print (qbtn.clicked())

输出:TypeError: native Qt signal is not callable

最后,如果它没有任何实现,它将如何影响QPushButton?

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

输出:

<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> 

有两个重要方面需要始终牢记:

  1. PyQt(类似于PySide(是一个绑定:它是Qt框架的接口,因此可以使用标准的python函数和方法访问它;为了创建它,使用了一个特殊的工具SIP,它实际上创建了从暴露于python的对象到Qt和viceversa的对象的绑定(对于PySide,使用的工具称为Shiboken(
  2. 信号是而不是方法,它们是可调用对象可以连接到的接口,只要这些对象具有兼容的签名,则只要发出信号,就会调用这些对象

您所指的文件是pyi文件。从"i"在Python.pyi扩展中代表什么?:

PyCharm和其他开发工具使用*.pyi文件来提供比从扩展类型和方法的内省中收集到的信息更多的信息,如PEP 484类型提示。除了向工具提供信息外,它们不打算被导入、执行或用于任何其他目的。如果您不使用使用.ppy文件的工具,则可以安全地忽略此文件。

您提到了以下行:

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

它只在这些文件中找到,并且只是:信息

C++中的信号在类似于函数的标头中声明,具有指示信号签名的自变量,然后被";转化的";当Qt(或声明其自身信号的程序(被编译时,转换为信号[1]

由于PyQt和PySide是使用上述自动化工具创建的,因此结果是信号可能被列为方法;值得注意的是,官方PySide文档列表信号甚至包括def:在PySide2中;信号";部分,而在PySide6中,它们甚至没有被标识为这样。

在python绑定中,信号是类的未绑定属性,但当信号被引用为QObject实例时,PyQt会自动将该实例绑定到信号,以创建绑定的信号。

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

您可以看到,通过使用一个简单的id(它应该为对象返回一个唯一且恒定的值(来动态绑定信号:

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

因此,您从一些文档或参考文件中看到的,主要是用于创建信号的签名,但也是信号发射/接收器的预期签名,类似于在Python中声明新信号时可以执行的操作(不同的是,无法定义默认值,如QAbstractButton的checked=False(。

[1]这是一个过于简单化的问题,我对C++没有足够的知识来解释信号创建是如何工作的,但这只是为了解释

最新更新