QUiLoader аварийно завершает работу с пользовательскими виджетами в PySide

Я пытаюсь встроить виджет PySide PyQtGraph в окно GraphicsView, созданное с помощью QT Creator. Однако ошибка сегментации возникает, когда я импортирую файл пользовательского интерфейса и использую функцию «перейти к» в QT Creator.

Эта ошибка наблюдалась ранее, и был предложен обходной путь для переопределения функции createWidget() QUiLoader:

http://www.mail-archive.com/[email protected]/msg00306.html
и
Не удалось вызвать пользовательский класс в файле .ui

Однако, когда я реализую обходной путь, я все равно получаю ошибку сегментации.

Кто-нибудь знает, почему этот обходной путь не работает в моем коде? Или есть другой способ встроить PyQtGraph при динамическом импорте файла пользовательского интерфейса?

Большое спасибо,

Тако

Некоторый пример кода:

#!/usr/bin/python
import os
import sys

from PySide.QtUiTools import QUiLoader


import pyqtgraph as pg

SCRIPT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))

class UiLoader(QUiLoader):
    def __init__(self, baseinstance):
        QUiLoader.__init__(self, baseinstance)
        self.baseinstance = baseinstance

    def createWidget(self, className, parent = None, name = ""):
        if className in QUiLoader.availableWidgets(self):
            widget = QUiLoader.createWidget(self, className, parent, name)
        else:
            if hasattr(self.baseinstance, "customWidgets"):
                if className in self.baseinstance.customWidgets.keys():
                    widget = self.baseinstance.customWidgets[className](parent)
                else:
                    raise KeyError("Unknown widget '%s'" % className)
            else:
                raise AttributeError("Trying to load custom widget '%s', but base instance '%s' does not specify custom widgets." % (className, repr(self.baseinstance)))

        if self.baseinstance is not None:
            setattr(self.baseinstance, name, widget)

        return widget


def loadUi(uifile, baseinstance=None):
    loader = UiLoader(baseinstance)
    loader.registerCustomWidget(pg.PlotWidget)
    widget = loader.load(uifile)
    QMetaObject.connectSlotsByName(widget)
    return widget

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.ui = loadUi(os.path.join(SCRIPT_DIRECTORY, 'example1.ui'), self)
        self.ui.plotBtn.clicked.connect(self.PlotTest)

    def PlotTest(self):
        self.ui.plottest.plot(np.random.normal(size=50), clear=True)

def main():
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()

И файл пользовательского интерфейса: example1.ui

<?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="PlotWidget" name="centralwidget">
   <widget class="QGraphicsView" name="graphicsView">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>30</y>
      <width>761</width>
      <height>471</height>
     </rect>
    </property>
   </widget>
   <widget class="QPushButton" name="plotBtn">
    <property name="geometry">
     <rect>
      <x>670</x>
      <y>510</y>
      <width>114</width>
      <height>32</height>
     </rect>
    </property>
    <property name="text">
     <string>Plot</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>PlotWidget</class>
   <extends>QWidget</extends>
   <header>pyqtgraph</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

person Taco    schedule 24.04.2014    source источник


Ответы (1)


Вы можете обойти проблемы PySides с QtUiLoader, используя pg.Qt.loadUiType('uicfile.ui'). Вот пример, основанный на вашем коде:

from PySide.QtGui import *
import pyqtgraph as pg
import numpy as np

formClass, baseClass = pg.Qt.loadUiType('example1.ui')
class MainWindow(baseClass):
    def __init__(self, parent=None):
        baseClass.__init__(self, parent)
        self.ui = formClass()
        self.ui.setupUi(self)
        self.setCentralWidget(self.ui.centralwidget)
        self.ui.plotBtn.clicked.connect(self.PlotTest)

    def PlotTest(self):
        self.ui.centralwidget.plot(np.random.normal(size=50), clear=True)

def main():
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()

Примечания:

  • Ваш файл .ui, кажется, создан неправильно - вы продвигаете «центральный виджет» как PlotWidget, тогда как я думаю, что вместо этого вы намеревались продвигать GraphicsView.

  • Я столкнулся с некоторыми проблемами юникода с loadUiType, и мне пришлось использовать последнюю версию разработки pyqtgraph. Возможно, вам придется сделать то же самое.

person Luke    schedule 26.04.2014
comment
Спасибо за вашу помощь! Как вы упомянули, мне также пришлось установить версию PyQtGraph для разработки, чтобы решить проблемы с loadUiType. Кроме того, у меня возникла проблема с пакетом PySide, входящим в состав Anaconda для Mac. Похоже, что pyside-uic не включен в этот пакет, но с обычной установкой Python все работает как шарм!! - person Taco; 30.04.2014