Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中将小部件子类化以与Qt设计器一起使用的最简单方法_Python_Python 3.x_Pyqt5_Qt5_Qt Designer - Fatal编程技术网

在Python中将小部件子类化以与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设计器中可用 或者,有没有更简单的方法来实现这一点?我不需要更改小部件的外观或功能,我只是

我正在使用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属性,然后从代码中实现其他功能

一旦你知道它是如何工作的,这个过程就相当简单了

  • 创建UI并根据要扩展的类添加小部件

  • 在本例中,我使用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分钟才完成