如何从.ui文件中为Qt按钮添加函数? [英] How to add functions to Qt buttons from .ui file?
问题描述
我刚刚开始使用和发现PyQt5和Qt。我把它安装在一起
pip install pyqt5
。然后我打开pyqt-tools
附带的designer.exe
并进行了设计。
之后,我使用pyuic design.ui > dialog.py
将其从.ui
转换为.py
。
当我运行app.py
时,它运行得很好,用户界面也运行得很好。但现在我的问题是:我如何添加在按下按钮时调用的函数?
以下是我的app.py代码:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from dialog import Ui_Form
class AppWindow(QDialog)
def __init__(self):
super().__init__()
self.ui = Ui_Form()
self.ui.setupUi(self)
self.show()
app = QApplication(sys.argv)
w = AppWindow()
w.show()
sys.exit(app.exec_())
推荐答案
您的方法实际上是正确的(至少是正确的方法之一):pyuic
生成的文件不应该修改,除非您真的(真的)知道您在做什么以及为什么。此外,永远不应该模仿他们的行为,因为没有理由这样做。
作为(我想说是强制性的)参考,您可以在using Designer的官方PyQt指南上阅读有关此主题的更多信息。
让我就这个主题做一个重要的前提。
您所做的被称为单继承方法,这意味着您正在创建一个仅从您正在使用的QWidget子类(在本例中为QDialog)继承的子类,并使用被称为窗体类的方法在其之上构建UI。Form类是一个标准的object
类型,它负责在调用其setupUi
函数时在主子类实例之上创建所有子窗口小部件。
结果是,子类实例将始终在其作用域内引用self
,而其所有子实例都可以通过self.ui
对象访问。
类似的(也是更常见的)方法是多重继承方法。通过这种方式,您可以从继承QWidget子类(QDialog)和UI对象。用户界面结果将是相同的,但使用self.objectName
而不是self.ui.objectName
可以更直接地使用小部件。
使用哪种方法取决于您的选择,请记住,只要您使用多重继承方法,setupUi
可能会覆盖任何以前设置的实例属性,如果您为已有的对象名称创建新属性,则该对象将无法再(直接)访问。
最后,让我给你另一个建议:虽然不是完全错,但另一个答案中的link posted不仅给出了一个非常误导性的建议,而且甚至没有更多地挖掘它所指的上一篇文章为什么是错误的。底线是pyuic
创建的文件不应该被修改(也不应该试图模仿它们的行为),原因有很多:不仅如果您需要更改您的UI,您将需要将已经修改的代码与新的代码合并(希望您没有使用pyuic
覆盖它),而且这还会导致对整个对象结构的误解。
因此,在您的情况下(使用单一继承方法),在Designer中创建的所有对象实际上都可以使用self.ui.objectName
访问,而objectName
就是在Designer的对象检查器中显示的对象。
假设您创建了一个只有一个按钮的UI,并且您想要在按下该按钮时打印一些内容。如果您没有对您的用户界面进行过多的测试和修改,则该按钮的对象名称可能是。
然后,您的代码可能如下所示:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from dialog import Ui_Form
class AppWindow(QDialog)
def __init__(self):
super().__init__()
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print('button clicked!')
app = QApplication(sys.argv)
w = AppWindow()
w.show()
sys.exit(app.exec_())
请注意,Qt对象名称不是唯一的。从理论上讲,您可以为多个QObject(或QWidget)设置相同的对象名称,但这样做没有任何用处。从Python的角度考虑这一点:每个变量都应该有自己的名称,如果您覆盖了已经存在的变量名称,前一个变量将变得不可访问(如果不是垃圾收集的话)。
设计师足够聪明(并不是说它需要这么多……)为了防止创建共享相同对象名称的对象,这就是为什么如果您添加另一个按钮,它将被命名为pushButton_2
、pushButton_3
等。无论您使用的是pyuic
文件还是uic.loadUi()
,通过为所有对象名称创建唯一的实例属性,PyQt将从中受益。
为完整起见,以下是多重继承方法在执行上述示例时的外观:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from dialog import Ui_Form
class AppWindow(QDialog, Ui_Form)
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print('button clicked!')
app = QApplication(sys.argv)
w = AppWindow()
w.show()
sys.exit(app.exec_())
根据上面的解释,考虑属性名称问题:如果在调用self.setupUi
之前创建了一个名为self.pushButton
的属性,那么在该调用之后self.pushButton
将是对按钮的引用,之前设置的值将丢失;如果您在调用self.setupUi
之后创建了一个名为self.pushButton
的新属性,您将无法再访问QPushButton实例。
现在,虽然在正常使用时它们的行为通常是相同的,但使用pyuic
生成的文件或uic.loadUiType()
和更直接的uic.loadUi
之间存在微小但仍然重要的差异,不幸的是,这些差异没有正式记录(坦率地说,我不记得所有这些差异)。
eyllanesc以前曾在问题Size of verticalLayout is different in Qt Designer and PyQt program中报告过一个示例。
考虑这些是非常具体的异常(甚至可能在未来的PyQt版本中解决,特别是现在Qt6即将发布),并且它们通常不会对标准编程造成重大问题。
最后(终于!),虽然设计师通常很聪明,但也不是很完美。例如,在技术上不重要的&q;对象作为Q操作分隔符被视为&q;匿名&q;,而Designer甚至不应用它们的对象名称:如果您向菜单添加一个分隔符,即使您主动命名它,也无法直接访问它。
这篇关于如何从.ui文件中为Qt按钮添加函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!