无法更改__class__ PySide.QtGui对象(Unable to change __cl

2019-07-29 12:16发布

我已经使用PyQt4的相当多的 - 有时候我喜欢超负荷的一些对象,让我增加一些功能。 这PyQt4中,如能正常工作:

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

不过,我想,这样它使用PySide而不是PyQt4的适应我的一些代码。 我的理解是,他们应该具有相同的功能。 PySide不会让我做同样的事情。

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

这个错误有:

TypeError: __class__ assignment: only for heap types

有另一种方式我可以改变我的类对象,以避免这个错误? 我真的不知道是什么导致了它。

注:我需要改变对象的类在创建后的对象在由pyuic编译库创建。 另外我PySide安装没有UIC的模块。

Answer 1:

PySide使用Shiboken从其C ++类生成的Qt的CPython的绑定。 所有Qt的Python类如QPushButton是用C ++实现这就是为什么你不能覆盖__class__

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

按照Shiboken的文档,你可以猴子补丁(或鸭冲)已经实例化对象的方法,只要方法是虚拟(重写):

import types

def override_text(self):
    return 'overridden'

# Bind override_text() to button.
button.text = types.MethodType(override_text, button, QPushButton)

以这进一步,你可以子类QPushButtonMyButton ,并动态地注入从方法MyButtonQPushButton实例。 使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 ,因为自己居然是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)
  • 注意:您可以拨打QPushButton.text()直接通过self.__class__ ,因为你不会使用MyButtonOverrides直接。

现在,让我们来定义extend_instance()将注入从您的重写方法MyButton (或MyButtonOverrides )到QPushButton实例:

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__))

经过我的测试这部作品在Python 2.7和3.3,而应该在2.6+和3+工作。

最后修改按钮,使用extend_instance()

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


Answer 2:

猴修补__class__是完全不必要的。 相反,你应该推动在Qt Designer中的相关部件,让他们自动使用你的子类。

要做到这一点,在Qt Designer中,右键单击窗口小部件,然后选择“提升到......”。 在对话框中,将“促进类名”为子类(如“MyPushButton”),并设置“头文件”为包含子模块蟒蛇进口路径(例如“MYAPP”,或“myapp.gui”管他呢)。

现在,单击“添加”,然后是“促进”,你会看到“QPushButton”到“MyPushButton”在Object Inspector面板类变化。

当您重新生成您的UI模块pyuicpyside-uic ,它将包含这样的代码:

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

from myapp import MyPushButton

因此,推动按钮,将作为实例被创建MyPushButton ,有不再需要破解__class__

促进小部件的这种技术将两者的PyQt和PySide工作。



文章来源: Unable to change __class__ of PySide.QtGui objects