Использование собственного виджета PySide2 в Qt Designer

1

Я ищу способ использовать пользовательские виджеты в Qt Designer, написанные с Qt для Python (PySide2) эффективно.

Я узнал, что можно создать графический интерфейс с базовым виджетами, а затем просто поменять класс на свой пользовательский виджет в файле пользовательского интерфейса и сообщить QUiLoader о loader.registerCustomWidget(MyMainWindow) подкласса.registerCustomWidget loader.registerCustomWidget(MyMainWindow), но затем снова открыть его в Qt Designer не работает так хорошо.

Я прочитал в этом подобном вопросе для PyQt, что вам нужно написать плагин для пользовательского виджета. Существует ли такая возможность для PySide2?

Пример кода:

custom_widget.py:

import sys

from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QMainWindow, QAction, QMessageBox, QFileDialog, QTextBrowser
from PySide2.QtCore import QFile


class MyMainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("Demo QtWidget App")

    def closeEvent(self, event):
        msgBox = QMessageBox()
        msgBox.setWindowTitle("Quit?")
        msgBox.setText("Exit application?")
        msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msgBox.setDefaultButton(QMessageBox.No)
        ret = msgBox.exec_()
        if ret == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()


if __name__ == '__main__':
    app = QApplication([])
    file = QFile("custom_widget_original.ui")
    #file = QFile("custom_widget_modified.ui")
    file.open(QFile.ReadOnly)
    loader = QUiLoader()
    loader.registerCustomWidget(MyMainWindow)
    main_window = loader.load(file)
    main_window.show()
    sys.exit(app.exec_())

custom_widget_original.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="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QLabel" name="label_2">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QLabel" name="label">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QLabel" name="label_3">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="actionExit"/>
   </widget>
   <addaction name="menuFile"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>actionExit</sender>
   <signal>triggered()</signal>
   <receiver>MainWindow</receiver>
   <slot>close()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>-1</x>
     <y>-1</y>
    </hint>
    <hint type="destinationlabel">
     <x>399</x>
     <y>299</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

custom_widget_modified.ui

С этой версией вас спрашивают, действительно ли хотите бросить курить.

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="MyMainWindow" 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">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>155</width>
     <height>15</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QLabel" name="label_2">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QLabel" name="label">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QLabel" name="label_3">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="actionExit"/>
   </widget>
   <addaction name="menuFile"/>
  </widget>
  <widget class="QStatusBar" name="statusbar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>3</width>
     <height>18</height>
    </rect>
   </property>
  </widget>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
 </widget>
 <customwidgets>
  <customwidget>
   <class>MyMainWindow</class>
   <extends>QWidget</extends>
   <header>mymainwindow.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections>
  <connection>
   <sender>actionExit</sender>
   <signal>triggered()</signal>
   <receiver>MainWindow</receiver>
   <slot>close()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>-1</x>
     <y>-1</y>
    </hint>
    <hint type="destinationlabel">
     <x>399</x>
     <y>299</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

<customwidgets> добавляется Qt Designer после его повторного открытия.

После модификации Qt Designer не помещает эти три метки правильно.

Теги:
pyside2
qt-designer

1 ответ

1
Лучший ответ

Существует два основных способа использования пользовательского виджета в Qt Designer:

1. Продвижение виджета:

Это самый простой и наименее трудоемкий способ, если это внутренний виджет, который вам нужно просто щелкнуть правой кнопкой мыши на виджете и выбрать "Содействовать...", а затем:

  • Имя базового класса выберите класс, из которого вы наследуете
  • Имя продвинутого класса помещает имя класса a
  • Файл заголовка поместите путь файла, изменяющего расширение.py в.h

Изображение 174551

То, что указано выше, генерирует следующее:

...
    <widget class="RadialBar" name="widget" native="true"/>
...
 <customwidgets>
  <customwidget>
   <class>RadialBar</class>
   <extends>QWidget</extends>
   <header>radialbar.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
...

То есть, измените класс и добавьте поле в customwidget, указывающее на имя класса: <class> NAME_OF_CLASS </class>, имя класса, наследующего <extends>CLASS_EXTENDS</extends> и путь к файлу, изменяющий расширение файла от.py до.h <header>PATH_OF_FILE.h</header>, то есть те же данные, что и вы ввели форму.

В случае корневого виджета это невозможно сделать через Qt Designer, но я вижу, что вы поняли логику, но вы не все правильно изменили, ваша главная ошибка - указать класс, из которого они наследуют

 <customwidgets>
  <customwidget>
   <class>MyMainWindow</class>
   <extends>QMainWindow</extends> <----
   <header>mymainwindow.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>

Итак, правильный файл:

custom_widget_modified.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="MyMainWindow" 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">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>155</width>
     <height>15</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QLabel" name="label_2">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QLabel" name="label">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QLabel" name="label_3">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="actionExit"/>
   </widget>
   <addaction name="menuFile"/>
  </widget>
  <widget class="QStatusBar" name="statusbar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>3</width>
     <height>18</height>
    </rect>
   </property>
  </widget>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
 </widget>
 <customwidgets>
  <customwidget>
   <class>MyMainWindow</class>
   <extends>QMainWindow</extends>
   <header>mymainwindow.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections>
  <connection>
   <sender>actionExit</sender>
   <signal>triggered()</signal>
   <receiver>MainWindow</receiver>
   <slot>close()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>-1</x>
     <y>-1</y>
    </hint>
    <hint type="destinationlabel">
     <x>399</x>
     <y>299</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

mymainwindow.py

import sys

from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QMainWindow, QMessageBox
from PySide2.QtCore import QFile


class MyMainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("Demo QtWidget App")

    def closeEvent(self, event):
        msgBox = QMessageBox()
        msgBox.setWindowTitle("Quit?")
        msgBox.setText("Exit application?")
        msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msgBox.setDefaultButton(QMessageBox.No)
        ret = msgBox.exec_()
        if ret == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()


if __name__ == '__main__':
    app = QApplication([])
    file = QFile("custom_widget_modified.ui")
    file.open(QFile.ReadOnly)
    loader = QUiLoader()
    loader.registerCustomWidget(MyMainWindow)
    main_window = loader.load(file)
    main_window.show()
    sys.exit(app.exec_())

2. Продвижение виджета:

  • 0
    Спасибо! Прямо в этот момент, когда вы это опубликовали, я наткнулся на этот странный механизм, что расширение заголовка c ++ .h преобразуется в .py! И это так, по крайней мере, с 2013 года !!! Безумный!
  • 0
    Только что протестировано, если вы используете registerCustomWidget с точным именем класса и используете точно такое же имя класса в определении XML <widget> , то <customwidgets/> может быть пропущен.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню