在Python中将小部件子类化以与Qt设计器一起使用的最简单方法
我正在使用PyQt5构建一个应用程序,其中(大部分)GUI是使用Qt设计器构建的。我有几个UI元素,它们做的事情基本相同,将它们的代码移动到从基类继承的类中(基类又从QTableWidget继承)似乎是明智的 这看起来非常简单,只是我不知道如何让Qt设计器在生成UI文件时使用这些类。我已经找到了PyQt5的和,但没有涉及使子类在Qt设计器中可用的(最复杂的)方面 如何使使用PyQt5创建的小部件的子类在Qt设计器中可用在Python中将小部件子类化以与Qt设计器一起使用的最简单方法,python,python-3.x,pyqt5,qt5,qt-designer,Python,Python 3.x,Pyqt5,Qt5,Qt Designer,我正在使用PyQt5构建一个应用程序,其中(大部分)GUI是使用Qt设计器构建的。我有几个UI元素,它们做的事情基本相同,将它们的代码移动到从基类继承的类中(基类又从QTableWidget继承)似乎是明智的 这看起来非常简单,只是我不知道如何让Qt设计器在生成UI文件时使用这些类。我已经找到了PyQt5的和,但没有涉及使子类在Qt设计器中可用的(最复杂的)方面 如何使使用PyQt5创建的小部件的子类在Qt设计器中可用 或者,有没有更简单的方法来实现这一点?我不需要更改小部件的外观或功能,我只是
或者,有没有更简单的方法来实现这一点?我不需要更改小部件的外观或功能,我只是在寻找一个有组织的地方来存储一些代码,使它们的数据更易于设置和访问。要在Qt Designer中使用自定义小部件,有以下选项:
- Qt设计器插件: 您必须创建一个从QPyDesignerCustomWidgetPlugin继承的类,该类指示Qt设计器中如何显示该类的特征。此方法的优点是,除了可以创建对话框和菜单以友好方式进行修改外,还可以修改QProperty。“examples/designer/plugins”文件夹中的中有一个示例
- 升级小部件 优点是它不需要创建任何东西,缺点是它不允许超出基类插件提供的定制。因此,有几个例子:
如果您只想定位小部件,则只需升级小部件,如果您想使用Qt Designer修改属性,则需要一个插件。虽然可以为Qt Designer创建插件,但这不是一项容易的任务:官方文档已经过时,有时还不完整,有些函数还没有完全移植到透明的PyQt使用中 最简单的方法是使用升级的小部件 假设您有一个以奇特方式显示当前时间的小部件:
from PyQt5 import QtCore, QtGui, QtWidgets, uic
class TimeFrame(QtWidgets.QFrame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.updateTimer = QtCore.QTimer(interval=60000, timeout=self.update)
self._time = None
@QtCore.pyqtProperty(QtCore.QTime)
def time(self):
return self._time
@time.setter
def time(self, time):
self._time = time
self.update()
def paintEvent(self, event):
super().paintEvent(event)
size = min(self.width(), self.height()) - 10
rect = QtCore.QRect(0, 0, size, size)
rect.moveCenter(self.rect().center())
qp = QtGui.QPainter(self)
qp.setRenderHints(qp.Antialiasing)
qp.drawEllipse(rect)
qp.setPen(QtCore.Qt.NoPen)
qp.setBrush(QtCore.Qt.blue)
time = self._time or QtCore.QTime.currentTime()
minuteAngle = time.minute() * 6
qp.drawPie(rect, 1440, -minuteAngle * 16)
qp.setBrush(QtCore.Qt.red)
hourAngle = (time.hour() % 12 + time.minute() / 60) * 30
qp.drawPie(rect.adjusted(30, 30, -30, -30), 1440, -hourAngle * 16)
这是一个简单的时钟小部件,它显示了一对“馅饼”,大的表示分钟,小的表示小时(在这个屏幕截图中,时间是2:03):
现在,为了能够从Designer添加该小部件,您需要升级一个小部件。升级小部件是Qt扩展添加到UI的小部件的特性和功能的一种方式。
这非常有用,因为您可以以自己的方式扩展任何标准小部件类:例如,如果您向UI添加QTableView并升级它,它允许您从设计器界面设置标准QTableView属性,然后从代码中实现其他功能 一旦你知道它是如何工作的,这个过程就相当简单了
在本例中,我使用QFrame来展示如何扩展类属性。 只需创建界面,并向布局中添加QFrame 如您所见,从对象检查器报告的类仍然是QFrame
右键单击要用于类的小部件,选择“升级到…”,然后将“升级的类名”设置为之前创建的小部件类名,“头文件”设置为包含该类的模块名。我将python文件保存为
promoted.py
,因此字段值将promoted
。考虑头文件路径相对于UI文件加载路径的路径。
然后单击“添加”创建新的升级小部件“类”,最后单击“升级”进行正式升级。之后,您可以将任何小部件升级到先前设置的升级类,只要基类兼容:如果您的界面中有另一个QFrame,您可以右键单击它并从“升级到”子菜单中选择升级的类
现在,对象检查器中显示的类是TimeFrame
因为我们使用的是QFrame,所以我们可以设置它的框架(这是因为我们之前在
paintEvent(event)
方法中也调用了基类实现)
现在您只需要实现主小部件的基类。请记住,每次加载升级的小部件时,都会加载其“头文件”,这意味着其代码将始终运行。这就是为什么在文件中放置if\uuuuu name\uuuu='\uuuu main\uuuu':
代码块非常重要,只要它同时包含主“程序”和升级的小部件类
promoted.py
code:
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
uic.loadUi('test.ui', self)
self.timeEdit.timeChanged.connect(self.updateTimeFrame)
self.timeEdit.setTime(QtCore.QTime.currentTime())
def updateTimeFrame(self):
self.timeFrame.time = self.timeEdit.time()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.show()
sys.exit(app.exec())
现在,显然在Designer中不会显示任何内容,但只要我们运行代码,升级的小部件就会按预期显示
现在你也可以知道我创建这个答案的实际时间了,酷;-) 使用Qt设计器插件并非易事。你确定你真的需要它们吗?升级的小部件通常更易于使用,除非您确实需要在UI文件中设置特定属性和/或需要能够在设计器界面/预览中查看整个界面的外观。如果不是这样的话,那就改用升级的小部件。一点也不!试图弄清楚做这件事有多复杂,还有其他选择。非常感谢您宝贵的2小时27分钟!要计算出这个答案中包含的知识,如果不是几天的话,我可能要花上好几个小时。@Mikraint好吧,实际上那是当前的时间,所以我花了24分钟才完成