无法更改的类PySide.QtGui物体

2024-04-23 13:33:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我经常使用PyQt4—有时我喜欢重载一些对象,以便添加一些功能。这在PyQt4中运行良好,例如:

from PyQt4 import QtGui
button = QtGui.QPushButton()
class MyPushButton(QtGui.QPushButton): pass
button.__class__ = MyPushButton

不过,我正在尝试修改我的一些代码,以便它使用PySide而不是PyQt4。我的理解是它们应该具有相同的功能。PySide不允许我做同样的事情。在

^{pr2}$

此错误包含:

TypeError: __class__ assignment: only for heap types

有没有其他方法可以更改对象的类以避免此错误?我不太确定是什么原因造成的。在

注意:由于对象是在pyuic编译的库中创建的,所以我需要在创建后更改对象的类。另外,我的PySide安装没有uic模块。


Tags: 对象代码fromimport功能错误buttonpass
2条回答

猴子修补__class__完全没有必要。相反,您应该promoteQt Designer中的相关小部件,以便它们自动使用您的子类。在

为此,在QtDesigner中,右键单击小部件并选择“升级到…”。在对话框中,将“Promoted class name”设置为子类(例如“MyPushButton”),并将“Header file”设置为包含子类的模块的python导入路径(例如“myapp”,或myapp.gui“,或者别的什么)。在

现在单击“Add”,然后单击“Promote”,您将在objectinspector窗格中看到类从“QPushButton”更改为“mybutton”。在

当您使用pyuicpyside-uic重新生成ui模块时,它将包含如下代码:

class Ui_Window(object):
    def setupUi(self, Window):
        ...
        self.button = MyPushButton(Window)
        self.button.setObjectName("button")
        ...

from myapp import MyPushButton

因此,升级的按钮将被创建为MyPushButton的实例,不再需要对__class__进行黑客攻击。在

这种提升小部件的技术对PyQt和PySide都有效。在

PySide使用Shiboken为Qt生成CPython绑定 它的C++类。所有Qt python类,如QPushButton都是 在C++中实现,这就是为什么你不能覆盖^ {< CD2> }。在

>>> button = QPushButton()
>>> button.__class__ = MyButton
TypeError: __class__ assignment: only for heap types

根据Shiboken的文档,您可以monkey patch (or duck punch) 已经实例化的对象上的方法,只要这些方法 虚拟(可重写):

^{pr2}$

更进一步,您可以将QPushButton子类为MyButton,并且 将来自MyButton的方法动态注入QPushButton 实例。使MyButton成为QPushButton的子类是纯粹的 可选,但允许您创建自己的MyButton实例 除了修改后的QPushButton实例。在

让我们将MyButton定义为QPushButton的子类。在

class MyButton(QPushButton):

    def text(self):
        # This will override QPushButton's text() method.
        print("inside MyButton.text()")
        return QPushButton.text(self)
  • 注意:您必须使用调用父类方法的旧样式。 super()TypeError失败,因为self实际上是QPushButton 当注射该方法时,不是MyButton。在

或者,如果您想采用更多的mixin方法,让我们定义MyButtonOverrides

class MyButtonOverrides(object):

    def text(self):
        # This will override QPushButton's text() method.
        print("inside MyButtonOverrides.text()")
        return self.__class__.text(self)
  • 注意:您可以通过self.__class__直接调用QPushButton.text() 因为您不会直接使用MyButtonOverrides。在

现在让我们定义extend_instance(),它将注入您的覆盖 方法从MyButton(或MyButtonOverrides)到{} 实例:

import inspect

def extend_instance(obj, cls):
    for name, attr in vars(cls).items():
        if inspect.isroutine(attr):
            # Bind instance, class and static methods to *obj*.
            setattr(obj, name, attr.__get__(obj, obj.__class__))

如果您希望您的类方法保持绑定到它们的原始类 (例如,MyButton)然后使用以下方法:

def extend_instance(obj, cls):
    for name, attr in vars(cls).items():
        if inspect.isroutine(attr):
            if isinstance(attr, classmethod):
                # Bind class methods to *cls*.
                setattr(obj, name, attr.__get__(cls, cls))
            else:
                # Bind instance and static methods to *obj*.
                setattr(obj, name, attr.__get__(obj, obj.__class__))

通过我的测试,这在Python2.7和3.3中可以工作,但是应该 在2.6+和3+上工作。在

最后要修改按钮,请使用extend_instance()。在

>>> button = QPushButton()
>>> extend_instance(button, MyButton)
>>> button.text()
inside MyButton.text()
u''

相关问题 更多 >