使用PyQt4的uic.loadUi,我想加载.ui文件并在其中使用自定义小部件。这意味着使用package
的第三个uic.loadUi
参数,该参数将导入包含自定义小部件类的包。
但是,我希望在与我调用uic.loadUi
的文件相同的文件中定义自定义窗口小部件的类。我正试图这样做:
class MyCustomClass(QtWidgets.QPushButton):
""" This is my custom class for my custom widget """
def __init__(self, *args):
QtWidgets.QPushButton.__init__(self, *args)
...
sys.modules['mycustompackage'] = MyCustomClass
uic.loadUi('my_ui.ui', self, 'mycustompackage') # Loads .ui file which contains the MyCustomWidget widget
但是,这会返回以下错误:
AttributeError: type object 'MyCustomClass' has no attribute 'MyCustomWidget'
我有什么办法可以让它真正起作用吗?我怀疑MyCustomClass
没有以uic.loadUi
期望的方式定义。
在Qt Designer中,我推广了MyCustomWidget
:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="MyCustomWidget" name="customWidget">
<property name="geometry">
<rect>
<x>50</x>
<y>70</y>
<width>113</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>MyCustomWidget</class>
<extends>QPushButton</extends>
<header>MyCustomClass</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
我使用上面的.ui文件解决了这个问题:
class MyCustomClasses(object):
class MyCustomWidget(QtWidgets.QPushButton):
def __init__(self, *args):
QtWidgets.QPushButton.__init__(self, *args)
...
sys.modules['MyCustomClasses'] = MyCustomClasses
uic.loadUi('my_ui.ui', self) # Loads .ui file which contains MyCustomWidget
答案 0 :(得分:1)
引用您链接到的文档,loadUi
的第三个参数是:
自定义小部件相对导入的基础包的可选包[强调添加]
必须在ui
文件本身中指定要从中导入自定义类的实际模块名称。在Qt Designer中,这是通过将“Header file”设置为适当的值来实现的,它将存储在<header>
文件中的ui
标记中。请注意,此值可以是模块的完全限定的包路径(例如“pkg.mymodule”) - 在这种情况下,不必使用loadUi
的第三个参数。永远不需要sys.module
黑客。
loadUi
功能非常简单。它只是以与命令行工具完全相同的方式生成python模块,然后使用exec
加载它。
答案 1 :(得分:1)
这是三种可能的方式。 例如,您有模块 QtCustomWidgets.widgets.mybutton 它是项目中带有 MyButton 类的文件 QtCustomWidgets / widgets / mybutton.py 和 QtCustomWidgets / python / mybuttonplugin.py 。 / p>
第一种方法将 QtCustomWidgets / python / mybuttonplugin.py 中的 includeFile 方法定义为:
def includeFile(self):
return "QtCustomWidgets.widgets.mybutton"
第二种方法是将uic.loadUi与packadge路径一起使用: uic.loadUi('my_ui.ui',self,packadge ='QtCustomWidgets.widgets')
但是您必须在模块名称中使用点( includeFile 是 QtCustomWidgets / python / mybuttonplugin.py 中的方法):
def includeFile(self):
return ".mybutton"
,因此在标题中它必须看起来像这样:
<customwidgets>
<customwidget>
<class>MyButton</class>
<extends>QPushButton</extends>
<header>.mybutton</header>
</customwidget>
</customwidgets>
结果方式仍然是“ QtCustomWidgets.widgets” +“ .mybutton”
有PyQt源代码自定义小部件加载程序( qobjectcreator.py ),您可以自己找到它:
class _CustomWidgetLoader(object):
def __init__(self, package):
# should it stay this way?
if '.' not in sys.path:
sys.path.append('.')
self._widgets = {}
self._modules = {}
self._package = package
def addCustomWidget(self, widgetClass, baseClass, module):
assert widgetClass not in self._widgets
self._widgets[widgetClass] = module
def search(self, cls):
module_name = self._widgets.get(cls)
if module_name is None:
return None
module = self._modules.get(module_name)
if module is None:
if module_name.startswith('.'):
if self._package == '':
raise ImportError(
"relative import of %s without base package specified" % module_name)
if self._package.startswith('.'):
raise ImportError(
"base package %s is relative" % self._package)
mname = self._package + module_name
else:
mname = module_name
try:
module = __import__(mname, {}, {}, (cls,))
except ValueError:
# Raise a more helpful exception.
raise ImportError("unable to import module %s" % mname)
self._modules[module_name] = module
return getattr(module, cls)
第三种方式: 要将路径添加到sys.path中的小部件(您必须导入sys):
sys.path.append( "./QtCustomWidgets/widgets" )
uic.loadUi('my_ui.ui', self)