Python:如何使用不同的基类来改变或动态替换类 [英] Python: How to rebase or dynamically replace a class with a different base class
问题描述
我想创建一个公共类,我想在不同的应用程序中使用。
这个想法:可以用作ui创作的基类。这个类将基于它的特定gui系统(PySide或PyQt)中的应用程序的小部件。
遵循相同的代码流来生成gui的。我喜欢在我的管道中有相同的结构,并且使用相同的命令在不同的应用程序中工作更容易。
问题: PyQt和PySide是用C ++编译的,不遵循Python类结构
我尝试了很多不同的东西,
-
尝试(rebase):
在这次尝试中,我使用
__ class __
来重命名类本身。
从PyQt4导入QtGui,QtCore
类UiMainBase(对象)
PARENT = QtGui.QMainWindow
def __init __(self,uiFile = None,parent = None):
如果父代:self.PARENT = parent
self .__ class__ = self。 PARENT
如果__name__ ==__main__:
import sys
从PySide导入QtGui作为PySideGui
类MyGui(UiMainBase) :
def __init __(self,uiFile):
super(MyGui,self).__ init __(uiFile,PySideGui.QMainWindow)
Ui = rC:\pythonTest\\ \\ui\test.ui
app = PySideGui.QApplication(sys.argv)
win = MyGui(Ui)
win.show()
sys.exit .exec_())
我得到的错误是合理的,不必解释。
#1错误:
回溯(最近一次调用):
#[..]
文件C:/pythonTest/ui/ui.py行18,在__init__
self .__ class__ = self.PARENT
TypeError:__class__赋值:仅适用于堆类型
#2错误(不解析父
#参数to_init__ of super in MyGui):
Traceback(最近最后调用):
#[..]
文件C:/pythonTest/ui/uiTest.py,第18行,in __init__
self .__ class__ = self.PARENT
TypeError:__class__ assignment:'MyGui'对象布局与'QMainWindow'不同
-
尝试(rebase):
我使用
__ bases __
来重命名类本身。
从PyQt4导入QtGui,QtCore
类UiMainBase(对象)
PARENT = QtGui.QMainWindow
def __init __(self,uiFile = None,parent = None):
如果父代:self.PARENT = parent
self .__ bases __ = .PARENT,)
如果__name__ ==__main__:
import sys
从PySide导入QtGui作为PySideGui
类MyGui (UiMainBase):
def __init __(self,uiFile):
super(MyGui,self).__ init __(uiFile,PySideGui.QMainWindow)
Ui = rC: \\ pythonTest\ui\test.ui
app = PySideGui.QApplication(sys.argv)
win = MyGui(Ui)
print win .__ bases__#< - 对象有
win.show()
sys.exit(app.exec_())
在这个结果中,我们可以看到对象现在得到了正确的基础,但是没有得到它的方法和变量即使我在设置
__ bases __
后调用super
< type'PySide.QtGui.QMainWindow' ; #< - 基础
Traceback(最近最后调用):
文件C:/pythonTest/ui/uiTest.py,第34行,在< module>
win.show()
AttributeError:'MyGui'对象没有属性'show'
$ b b
-
尝试(装饰):
而不是rebase一个对象我试图替换类与另一个有正确的基础
从PyQt4 import QtGui,QtCore
def GetUiObject(uiClass):
parentWidget = uiClass.PARENT#< - 获取原始值,
#不是最新的,为什么?
class ParentUI(parentWidget,uiClass):
def __init __(self,* args,** kwargs):
super(ParentUI,self).__ init __()
uiClass .__ init__ (self,* args,** kwargs)
#[..]
def __call __(self,cls):
for func in uiClass .__ dict__:
setattr(cls, func,uiClass .__ dict __ [func])
#ParentUI = type(ParentUI,(parentWidget,),ParentUI .__ dict __。copy())
return ParentUI
@ GetUiObject
class UiMainBase(object):
PARENT = QtGui.QMainWindow
def __init __(self,uiFile = None,* args,** kwargs):
构造函数。 。
#[..]
如果__name__ ==__main__:
import sys
从PySide导入QtGui as PySideGui
UiMainBase.PARENT = PySideGui.QMainWindow#< - 指定应用程序
#ui架构为父
class MyGui(UiMainBase):
def __init __(self,uiFile = None):
#这个基类定义的变体不允许解析
#parent参数与它的
#(__init__将执行后基本设置)
super(MyGui,self).__ init __(uiFile = None)
print self.menuBar()#< - check used ui architecture
此变体的结果不会出错,
< PyQt4.QtGui.QMenuBar对象在0x00000000021C9D38>
,但MyGui
不是基于PySideGui.QMainWindow
像我预期的
EDIT: b
$ b
为什么不用基础定义类
PySide
code> PyQt4 ?:
一个genral使用和以后的扩展。应该可以自由地设置一个由应用程序( PySide
或 PyQt
)定义的父窗口小部件。但每个应用程序都有自己的方法或函数来获取它的MainWindow。因此,如果你想扩展这个MainWindow的一些小部件,或者只是父的一个新的ui到它,你需要将其定义为父,或直接基于它。一些应用程序和它的API不支持从 PySide.QtGui.QMainWindow
或的自由生成的ui PyQt4.QtGui.QMainWindow
。这是我试图以这种方式做的主要原因。当然,我可以为每个应用程序创建一个 UiMainWindow
类,并将其放到主窗口(这是我现在做的),但我试图使它更通用
此示例使用示例:
是用于3DS-Max和其管道集成的一个模块。 从pythonLibrary.file import Path
从qtLibrary .ui import UiMainBase
from blurdev.gui import Window
UiMainBase.PARENT = Window
类UiWidget(UiMainBase):
此类创建一个为父目标的小部件
到3DS-Max中的模糊的Python
的PySide实现
def __init __(self,uiFile = None):
super(UiWidget,self).__ init __()
如果uiFile:self.loadUi(uiFile,self)
self.show()
#[..]
$ b b类PublishUi(UiWidget):
def __init __(self):
uiFile = Path.Combine(__ file __,self .__ class __.__ name __ +。ui)
super(PublishUi,self) .__ init __(uiFile)
#[..]
如果__name__ ==__main__:
#这应该从3DS- Max
publishWindow = PublishUi()
任何人都有这种情况的解决方案吗?
干杯,
Michael
函数,动态生成正确的基类。在现实生活中,你可能会记住工厂,这样它总是为给定的父类返回相同的类对象,而不是创建多个相同的类。
从PyQt4 import QtGui,QtCore
def BaseFactory(parent):
class UiMainBase(parent):
....
return UiMainBase
如果__name__ ==__main__:
import sys
从PySide导入QtGui作为PySideGui
#UiMainBase = BaseFactory(QtGui.QMainWindow)
UiMainBase = BaseFactory(PySideGui.QMainWindow)
class MyGui(UiMainBase):
...
Ui = r \pythonTest\ui\test.ui
app = PySideGui.QApplication(sys.argv)
win = MyGui(Ui)
I am trying to create a common class which I want to use inside different applications.
The idea: a class which could be used as a base class for ui creations. This class will be based to a widget of the applications in it's specific gui system (PySide, or PyQt)
This would allow me to follow the same code flow to generate gui's. I like to have same structures inside my pipeline and it makes it much easier to work in different applications with the same commands.
The problem: PyQt and PySide are compiled in C++ and do not follow the Python class structure
I tried a lot of different things to get it to work, but every time I got stock at some point and doesn't get the result I want.
Try (rebase):
in this try I used
__class__
to rebase the class itself.from PyQt4 import QtGui, QtCore class UiMainBase(object): PARENT = QtGui.QMainWindow def __init__(self, uiFile=None, parent=None): if parent: self.PARENT = parent self.__class__ = self.PARENT if __name__ == "__main__": import sys from PySide import QtGui as PySideGui class MyGui(UiMainBase): def __init__(self, uiFile): super(MyGui, self).__init__(uiFile, PySideGui.QMainWindow) Ui = r"C:\pythonTest\ui\test.ui" app = PySideGui.QApplication(sys.argv) win = MyGui(Ui) win.show() sys.exit(app.exec_())
The errors I get are reasonable and doesn't has to be explained.
# 1st Error :
Traceback (most recent call last):
#[..]
File "C:/pythonTest/ui/ui.py", line 18, in __init__
self.__class__ = self.PARENT
TypeError: __class__ assignment: only for heap types
# 2nd Error (without parsing the parent
# argument to __init__ of super in MyGui) :
Traceback (most recent call last):
#[..]
File "C:/pythonTest/ui/uiTest.py", line 18, in __init__
self.__class__ = self.PARENT
TypeError: __class__ assignment: 'MyGui' object layout differs from 'QMainWindow'
Try (rebase):
in this try I used
__bases__
to rebase the class itself.from PyQt4 import QtGui, QtCore class UiMainBase(object): PARENT = QtGui.QMainWindow def __init__(self, uiFile=None, parent=None): if parent: self.PARENT = parent self.__bases__= (self.PARENT,) if __name__ == "__main__": import sys from PySide import QtGui as PySideGui class MyGui(UiMainBase): def __init__(self, uiFile): super(MyGui, self).__init__(uiFile, PySideGui.QMainWindow) Ui = r"C:\pythonTest\ui\test.ui" app = PySideGui.QApplication(sys.argv) win = MyGui(Ui) print win.__bases__ # <- shows what base the object has win.show() sys.exit(app.exec_())
In this result, we can see that the object now get's the right base, but don't get it's methods and variables (not even if I call
super
after setting__bases__
).
<type 'PySide.QtGui.QMainWindow'> # <- the base
Traceback (most recent call last):
File "C:/pythonTest/ui/uiTest.py", line 34, in <module>
win.show()
AttributeError: 'MyGui' object has no attribute 'show'
Try (decorator) :
instead of rebase an object I tried to replace the class with another one that has the right base
from PyQt4 import QtGui, QtCore def GetUiObject(uiClass): parentWidget = uiClass.PARENT # <- Gets the original value, # not the latest, why? class ParentUI(parentWidget, uiClass): def __init__(self, *args, **kwargs): super(ParentUI, self).__init__() uiClass.__init__(self, *args, **kwargs) #[..] def __call__(self, cls): for func in uiClass.__dict__: setattr(cls, func, uiClass.__dict__[func]) #ParentUI = type("ParentUI", (parentWidget,),ParentUI.__dict__.copy()) return ParentUI @GetUiObject class UiMainBase( object ): PARENT = QtGui.QMainWindow def __init__(self, uiFile=None, *args, **kwargs): """constructor..""" #[..] if __name__ == "__main__": import sys from PySide import QtGui as PySideGui UiMainBase.PARENT = PySideGui.QMainWindow # <- specify the application # ui architecture as parent class MyGui(UiMainBase): def __init__(self, uiFile=None): # This variant of base class definition doesn't allow parsing # the parent argument with with it # (__init__ will be executed after base is set) super(MyGui, self).__init__(uiFile=None) print self.menuBar () # <- check used ui architecture
Th e result of this variant doesn't error and prints:
<PyQt4.QtGui.QMenuBar object at 0x00000000021C9D38>
, butMyGui
is not based toPySideGui.QMainWindow
like I expected
EDIT:
Why do not defining classes with a base of
PySide
and one with a base ofPyQt4
?:
Because I want to leave it open for a genral use and later extensions. It should be free to set a parent widget, which is defined by the application (PySide
or PyQt
). But each application has it's own method or function to get it's MainWindow. So if you want extend some widgets of this MainWindow, or just parent a new ui to it you need to define it as the parent, or directly base from it. Some applications and it's API's do not support a free generated ui from type PySide.QtGui.QMainWindow
or PyQt4.QtGui.QMainWindow
. That's the main reason I was trying to do it in this way. Of course I could create a UiMainWindow
class for each application and base it to it's main window (this is what I do for now), but I was trying to make it more generic and global for my pipeline API.
Example of usage:
This example is for 3DS-Max and inside a module of it's pipeline integration.
from pythonLibrary.file import Path
from qtLibrary.ui import UiMainBase
from blurdev.gui import Window
UiMainBase.PARENT = Window
class UiWidget( UiMainBase ):
"""
This class creates a widget which is parented
to the PySide implementation of blur's Python
in 3DS-Max
"""
def __init__(self, uiFile=None):
super(UiWidget, self).__init__()
if uiFile: self.loadUi(uiFile, self)
self.show()
#[..]
class PublishUi(UiWidget):
def __init__(self):
uiFile = Path.Combine(__file__,self.__class__.__name__+".ui")
super(PublishUi, self).__init__(uiFile)
#[..]
if __name__ == "__main__":
# This should be called from a menu entry inside 3DS-Max
publishWindow = PublishUi()
Does anyone has a solution for this situation?
Cheers, Michael
Make a factory function which dynamically generates the correct base class. In real life, you'd probably memorize the factory so that it always returns the same class object for a given parent, rather than creating multiple identical classes.
from PyQt4 import QtGui, QtCore
def BaseFactory(parent):
class UiMainBase(parent):
....
return UiMainBase
if __name__ == "__main__":
import sys
from PySide import QtGui as PySideGui
# UiMainBase = BaseFactory(QtGui.QMainWindow)
UiMainBase = BaseFactory(PySideGui.QMainWindow)
class MyGui(UiMainBase):
...
Ui = r"C:\pythonTest\ui\test.ui"
app = PySideGui.QApplication(sys.argv)
win = MyGui(Ui)
这篇关于Python:如何使用不同的基类来改变或动态替换类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!