【问题标题】:Using a custom PySide2 widget in Qt Designer在 Qt Designer 中使用自定义 PySide2 小部件
【发布时间】:2019-02-07 05:42:47
【问题描述】:

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

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

我在this similar question for 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>

&lt;customwidgets&gt; 段是 Qt Designer 再次打开后添加的。

修改后Qt Designer没有正确放置三个标签。

【问题讨论】:

    标签: python qt-designer pyside2


    【解决方案1】:

    在 Qt Designer 中使用自定义小部件有两种主要方法:

    1。推广小部件:

    这是最简单、最省力的方法,如果是内部小部件,您只需右键单击小部件并选择Promote To ...,然后在:

    • 基类名称选择你继承的类
    • Promoted Class Name 放置类a的名称
    • 头文件放置文件的路径,将扩展名.py更改为.h

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

    ...
        <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中添加一个指向类名的字段:&lt;class&gt; NAME_OF_CLASS &lt;/class&gt;,它们继承的类名&lt;extends&gt;CLASS_EXTENDS&lt;/extends&gt;和文件路径更改文件扩展名从.py到.h&lt;header&gt;PATH_OF_FILE.h&lt;/header&gt;,也就是和你输入表格一样的数据。

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

     <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。推广小部件:

    【讨论】:

    • 谢谢!就在您发布此内容的这一刻,我偶然发现了这种奇怪的机制,即 c++ 标头 .h 扩展名转换为 .py!至少从 2013 年开始就是这样!!!疯了!
    • 刚刚测试过,如果您使用registerCustomWidget 与确切的类名,并且您在XML &lt;widget&gt; 定义中使用完全相同的类名,则可以省略&lt;customwidgets/&gt; 部分。
    猜你喜欢
    • 2015-04-13
    • 1970-01-01
    • 2022-07-02
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多