2016-08-05 32 views
1

Mit PyQt4 uic.loadUi möchte ich eine .ui-Datei laden und ein benutzerdefiniertes Widget verwenden. Dies bedeutet, dass das dritte package Argument von uic.loadUi verwendet wird, das das Paket mit der Klasse des benutzerdefinierten Widgets importiert.Wie benutzerdefinierte Widget und uic.loadUi verwenden, ohne benutzerdefinierte Widget-Klassenpaket zu importieren?

Allerdings möchte ich die benutzerdefinierte Widget-Klasse in der gleichen Datei wie wo ich rufe uic.loadUi definieren. Ich versuche, dies zu erreichen, etwa so:

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 

Dies ist jedoch die folgenden Fehler zurück:

AttributeError: type object 'MyCustomClass' has no attribute 'MyCustomWidget' 

Gibt es etwas, was ich tun konnte dies tatsächlich funktioniert? Ich vermute, dass MyCustomClass ist nicht in der Art und Weise definiert uic.loadUi erwartet es.

<?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> 

Lösung

ich es Datei wie folgt unter Verwendung der oben .ui gelöst:

In Qt Designer habe ich MyCustomWidget gefördert

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 

Antwort

0

zu zitieren Das dritte Argument von loadUi aus der Dokumentation, die Sie verknüpft haben, lautet:

the optional package that is the base package for any relative imports of custom widgets [emphasis added]

Der tatsächliche Modulname, aus dem die benutzerdefinierte Klasse importiert wird, muss in der Datei ui selbst angegeben werden. In Qt Designer wird dies erreicht, indem die "Header-Datei" auf den entsprechenden Wert gesetzt wird und in den <header> Tags innerhalb der Datei ui gespeichert wird. Beachten Sie, dass dieser Wert der vollständig qualifizierte Paketpfad des Moduls sein kann (z. B. "pkg.mymodule"). In diesem Fall ist es nicht erforderlich, das dritte Argument loadUi zu verwenden. Es sollte niemals sys.module Hacks benötigt werden.

Die loadUi Funktion ist ziemlich einfach. Sie generiert ein Python-Modul genau wie das Befehlszeilentool und lädt es dann mit exec.