虽然可以为 Qt Designer 创建插件,但not一个简单的任务:官方文档已经过时,有时不完整,并且某些功能尚未完全移植以实现透明的 PyQt 使用。
The easiest方法是使用推广的小部件.
假设您有一个以一种奇特的方式显示当前时间的小部件:
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):
![fancy clock widget](https://i.stack.imgur.com/jLLlQ.png)
现在,为了能够从设计器添加该小部件,您需要promote一个小部件。推广小部件是 Qt 扩展添加到 UI 的小部件的特性和功能的一种方式。
这非常有用,因为您可以扩展any以您自己的方式标准小部件类:例如,如果您将 QTableView 添加到 UI 并提升它,它允许您从 Designer 界面设置标准 QTableView 属性,然后从代码中实现其他功能。
一旦您知道它是如何工作的,该过程就非常简单。
- 创建 UI 并根据要扩展的类添加小部件
在本例中,我使用 QFrame 来展示如何扩展该类属性。
只需创建您的界面,然后将 QFrame 添加到布局中即可。
![basic GUI](https://i.stack.imgur.com/2tiwh.png)
正如您所看到的,从对象检查器报告的类仍然是 QFrame。
- 推广小部件
右键单击要用于课堂的小部件,然后选择Promote to...
,然后将“Promoted class name”设置为之前创建的widget类名,并将“头文件”设置为模块名称包含该类。我将 python 文件保存为promoted.py
,所以字段值将是promoted
。请考虑头文件路径相对于加载 UI 文件的路径。
![promote widget in Designer](https://i.stack.imgur.com/VQYXj.png)
然后点击“添加”创建新推广的小部件“类”,最后点击“推广”正式推广它。之后,您可以将任何小部件提升为先前设置的提升类,只要基类兼容:如果您的界面中有另一个QFrame,您可以右键单击它并从“提升到”中选择提升的类子菜单。
现在对象检查器中显示的类是TimeFrame
.
![The object class has changed](https://i.stack.imgur.com/pYiJT.png)
- 设置对象属性,保存,创建代码并运行
由于我们使用的是 QFrame,因此我们可以设置它的框架(这是因为我们还在paintEvent(event)
之前的方法)。
![Watch, a raised frame!](https://i.stack.imgur.com/GItTx.png)
现在您只需实现主小部件的基类即可。请记住,每次加载升级的小部件时,都会加载其“头文件”,这意味着其代码将always被运行。这就是为什么重要的是if __name__ == '__main__':
只要代码块包含主“程序”和升级的小部件类,就会将代码块放置在文件中。
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 中不会显示任何内容,but一旦我们运行代码,升级的小部件就会按预期显示!
![The promoted widget at work! Cool!](https://i.stack.imgur.com/OTn2p.png)
And now you can also know the actual time it took me to create this answer, cool ;-)