在 Qt Designer 中使用自定义 PySide2 小部件 [英] Using a custom PySide2 widget in Qt Designer

查看:84
本文介绍了在 Qt Designer 中使用自定义 PySide2 小部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种在 Qt Designer 中有效地使用使用 Qt for Python (PySide2) 编写的自定义小部件的方法.

我发现,可以使用基本小部件设计 GUI,然后只需将类交换到 UI 文件中的自定义小部件,并通知 QUiLoader 关于子类 loader.registerCustomWidget(MyMainWindow),但是在 Qt Designer 中再次打开它并不能很好地工作.

我在

上面所做的是生成以下内容:

<代码>...<widget class="RadialBar" name="widget" native="true"/>...<自定义小部件><自定义小部件><class>RadialBar</class><extends>QWidget</extends><header>radialbar.h</header><容器>1</容器></customwidget></customwidgets>...

即改类,在customwidget中增加一个字段,指向类名:NAME_OF_CLASS </class>,他们继承的类的名称 和文件路径将文件扩展名从 .py 更改为 .h <;header>PATH_OF_FILE.h</header>,即与您在表单中输入的数据相同.

在root widget的情况下,不能通过Qt Designer来完成,但我看到你已经理解了逻辑但你没有正确修改所有内容,你的主要错误是指出它们继承的类

 <自定义小部件><class>MyMainWindow</class><extends>QMainWindow</extends><----<header>mymainwindow.h</header><容器>1</容器></customwidget></customwidgets>

所以正确的文件是:

custom_widget_modified.ui

<string>TextLabel</string></属性></小部件></项目><item row="0" column="2"><widget class="QLabel" name="label"><属性名称=文本"><string>TextLabel</string></属性></小部件></项目><item row="0" column="1"><widget class="QLabel" name="label_3"><属性名称=文本"><string>TextLabel</string></属性></小部件></项目></布局></小部件><widget class="QMenuBar" name="menubar"><属性名称=几何"><rect><x>0</x><y>0</y><宽度>800</宽度><高度>21</高度></rect></属性><widget class="QMenu" name="menuFile"><属性名称=标题"><string>文件</string></属性><addaction name="actionExit"/></小部件><addaction name="menuFile"/></小部件><widget class="QStatusBar" name="statusbar"><属性名称=几何"><rect><x>0</x><y>0</y><宽度>3</宽度><高度>18</高度></rect></属性></小部件><action name="actionExit"><属性名称=文本"><string>退出</string></属性></动作></小部件><自定义小部件><自定义小部件><class>MyMainWindow</class><extends>QMainWindow</extends><header>mymainwindow.h</header><容器>1</容器></customwidget></customwidgets><资源/><连接><连接><sender>actionExit</sender><信号>触发()</信号><receiver>MainWindow</receiver><slot>close()</slot><提示><提示类型=源标签"><x>-1</x><y>-1</y><提示类型=目的地标签"><x>399</x><y>299</y></提示></连接></连接></ui>

mymainwindow.py

导入系统从 PySide2.QtUiTools 导入 QUiLoader从 PySide2.QtWidgets 导入 QApplication、QMainWindow、QMessageBox从 PySide2.QtCore 导入 QFile类 MyMainWindow(QMainWindow):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.setWindowTitle("演示 QtWidget 应用程序")def closeEvent(self, event):msgBox = QMessageBox()msgBox.setWindowTitle("退出?")msgBox.setText("退出应用程序?")msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)msgBox.setDefaultButton(QMessageBox.No)ret = msgBox.exec_()如果 ret == QMessageBox.Yes:事件.接受()别的:事件.忽略()如果 __name__ == '__main__':app = QApplication([])file = QFile("custom_widget_modified.ui")file.open(QFile.ReadOnly)加载器 = QUiLoader()loader.registerCustomWidget(MyMainWindow)main_window = loader.load(file)main_window.show()sys.exit(app.exec_())

2.推广小部件:

I'm searching for a way to use custom widgets in Qt Designer written with Qt for Python (PySide2) effectively.

I found out, that it is possible to design the GUI with the base widget, then just swap out the class to my custom widget in the UI File and informing the QUiLoader about the subclass loader.registerCustomWidget(MyMainWindow), but then opening it again in Qt Designer doesn't work that well.

I read in this similar question for PyQt that you have to write a Plugin for the custom widget. Does this possibility also exist for PySide2?

Some example code:

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

With this version the application is closed without question.

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

With this version you are asked if you really want to quit.

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

The <customwidgets> segment is added by Qt Designer after opening it again.

After modification Qt Designer doesn't place the three labels correctly.

解决方案

There are 2 main ways to use a custom widget in Qt Designer:

1. Promoting the widget:

This is the simplest and least laborious way, if it's an internal widget you just have to right click on the widget and select Promote To ..., then in:

  • Base Class Name choose the class from which you inherit
  • Promoted Class Name place the name of the class a
  • Header File place the path of the file changing the extension .py to .h

What the above does is generate the following:

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

That is, change class, and add a field in customwidget pointing to the name of the class: <class> NAME_OF_CLASS </class>, name of the class they inherit <extends>CLASS_EXTENDS</extends> and file path changing the file extension from .py to .h <header>PATH_OF_FILE.h</header>, that is, the same data as You entered the form.

In the case of the root widget it can not be done through Qt Designer, but I see that you have understood the logic but you have not modified everything correctly, your main mistake is to point out the class from which they inherit

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

So the correct file is:

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. Promoting the widget:

这篇关于在 Qt Designer 中使用自定义 PySide2 小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆