从主窗口中的 UI 文件加载带有信号槽定义的小部件

Posted

技术标签:

【中文标题】从主窗口中的 UI 文件加载带有信号槽定义的小部件【英文标题】:Load widget with signal-slot defintions from UI file in main window 【发布时间】:2019-12-05 16:54:04 【问题描述】:

我无法将 Qt Designer 生成的小部件加载到我的主窗口中。当我还在 UI 文件中定义了信号和插槽时,它会失败。

# -*- coding: utf-8 -*-
import sys

from PyQt5 import QtWidgets
from PyQt5 import uic as pyuic

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args):
        super().__init__(*args)
        self.uifile = 'serialTandemGUI.ui'
        self.form_widget = pyuic.loadUi(self.uifile)
        _widget = QtWidgets.QWidget()
        _layout = QtWidgets.QVBoxLayout(_widget)
        _layout.addWidget(self.form_widget)
        self.setCentralWidget(_widget)

if __name__ == '__main__':
    app = QtWidgets.QApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)

    w = MainWindow()
    w.show()

    app.exec_()

我得到的错误是: AttributeError: 'QWidget' object has no attribute 'init'

是否有可能以这种方式继承小部件?蒂亚!

编辑: 这是一个带有 clicked() 信号的简单 UI 文件进行演示。只要没有进行信号定义,它就可以工作(即实际上只是 UI,但这只是工作的一半,甚至更少)。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QGroupBox" name="groupBox">
     <property name="title">
      <string>GroupBox</string>
     </property>
     <layout class="QGridLayout" name="gridLayout_2">
      <item row="0" column="0">
       <widget class="QPushButton" name="pushButton">
        <property name="text">
         <string>PushButton</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>pushButton</sender>
   <signal>clicked()</signal>
   <receiver>Form</receiver>
   <slot>init()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>203</x>
     <y>162</y>
    </hint>
    <hint type="destinationlabel">
     <x>396</x>
     <y>201</y>
    </hint>
   </hints>
  </connection>
 </connections>
 <slots>
  <slot>init()</slot>
 </slots>
</ui>

【问题讨论】:

分享.ui .......... 任何带有信号槽定义的 ui 文件都可以。不工作。 【参考方案1】:

说明:

当您创建 .ui 时,您只指出 clicked 信号和小部件的 init 方法之间存在连接,但是当您使用 loadUi() 加载它时,不要将其作为第二个参数 QWidget 将使用设计的基类,在您的情况下为 QWidget,它显然没有“init”方法抛出该错误。

解决方案:

你必须创建一个继承自QWidget并具有init方法的类,然后使用loadUi()来填写。

# -*- coding: utf-8 -*-
import os
import sys

from PyQt5 import QtCore, QtWidgets, uic as pyuic


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        current_dir = os.path.dirname(os.path.realpath(__file__))
        uifile = os.path.join(current_dir, "serialTandemGUI.ui")
        pyuic.loadUi(uifile, self)

    @QtCore.pyqtSlot()
    def init(self):
        print("init")


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.form_widget = Widget()
        _widget = QtWidgets.QWidget()
        _layout = QtWidgets.QVBoxLayout(_widget)
        _layout.addWidget(self.form_widget)
        self.setCentralWidget(_widget)


if __name__ == "__main__":
    app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)

    w = MainWindow()
    w.show()

    sys.exit(app.exec_())

【讨论】:

完全回答了,非常感谢!我已经尝试在主窗口中有相关的插槽方法,但是在相应的小部件类中使用它也使一切变得更加清晰。 您能否解释一下为什么使用 @QtCore.pyqtSlot() 装饰器是有利的?它也可以不使用。 @damada 阅读riverbankcomputing.com/static/Docs/PyQt5/…

以上是关于从主窗口中的 UI 文件加载带有信号槽定义的小部件的主要内容,如果未能解决你的问题,请参考以下文章

qt中的信号和槽机制

SwiftUI 中的小部件 UI 预览

PyQt5 不能在单独的 ui 文件中使用预定义的小部件

如何从另一个窗口访问一个窗口的小部件?

Qt将信号连接到插槽

如何将 QGraphicsView 提升为 .ui 文件中的自定义小部件?