我已经使用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的模块。
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)
以这进一步,你可以子类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
,因为自己居然是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''
猴修补__class__
是完全不必要的。 相反,你应该推动在Qt Designer中的相关部件,让他们自动使用你的子类。
要做到这一点,在Qt Designer中,右键单击窗口小部件,然后选择“提升到......”。 在对话框中,将“促进类名”为子类(如“MyPushButton”),并设置“头文件”为包含子模块蟒蛇进口路径(例如“MYAPP”,或“myapp.gui”管他呢)。
现在,单击“添加”,然后是“促进”,你会看到“QPushButton”到“MyPushButton”在Object Inspector面板类变化。
当您重新生成您的UI模块pyuic
或pyside-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工作。