Подключение сигналов из файла пользовательского интерфейса
После нескольких уроков мне удалось собрать небольшую программу на Python, которая успешно .ui
файл и показывает его на экране:
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QDialog, QMessageBox, QVBoxLayout
from PySide2.QtWidgets import QPushButton, QLineEdit
from PySide2.QtCore import QFile, Slot
from PySide2.QtUiTools import QUiLoader
class Dialog(QDialog):
def __init__(self, parent = None):
super(Dialog, self).__init__(parent)
print('hey')
def alert(self):
print('Alert')
if __name__ == '__main__':
app = QApplication([])
loader = QUiLoader()
loader.registerCustomWidget(Dialog)
ui_file = QFile('alert-quit.ui')
ui_file.open(QFile.ReadOnly)
dialog = loader.load(ui_file)
ui_file.close()
dialog.show()
Диалог показывает правильно, но я получаю ошибку QObject::connect: No such slot QDialog::alert()
и кнопка ничего не делает. (The hey
текст тоже не показывается.)
.ui
файл содержит определение QDialog
с сигналом от кнопки "Оповещение":
Я не уверен в том, что registerCustomWidget()
из другого ответа, казалось, что это то, что нужно сделать. К сожалению, официальная документация терпит неудачу, что, как circle.ui
содержит.
И официальная документация по загрузке .ui
файлы не показывают, как взаимодействовать с элементами, определенными в .ui
сам файл.
Как я могу загрузить полный QDialog
из .ui
файл и получить кнопки для запуска действий в моем коде?
PS: так как я не могу прикрепить .ui
файл, вот его XML:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>344</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="alert_button">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Alert</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="quit_button">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Quit</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>alert_button</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>alert()</slot>
<hints>
<hint type="sourcelabel">
<x>91</x>
<y>30</y>
</hint>
<hint type="destinationlabel">
<x>133</x>
<y>51</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>alert()</slot>
<slot>quit()</slot>
</slots>
</ui>
2 ответа
Как я уже писал в комментариях к моему вопросу, я нашел рабочее решение. Я не уверен на 100%, это правильный (по крайней мере, для части, касающейся ручного редактирования .ui
файл), но я получаю диалоговое окно, чтобы показать и вести себя так, как я ожидал.
Сначала я должен был изменить XML в .ui
файл и использовать два разных имени класса в .py
а также .ui
файлы. Я изменил один в .ui
быть названным AlertDialog
и быть типом Dialog
вместо QDialog
, Я не смог найти способ изменить тип в Qt Designer.
3,4c3,4
< <class>Dialog</class>
< <widget class="QDialog" name="Dialog">
---
> <class>AlertDialog</class>
> <widget class="Dialog" name="AlertDialog">
18c18
< <widget class="QLineEdit" name="lineEdit"/>
---
> <widget class="QLineEdit" name="text_field"/>
66c66
< <receiver>Dialog</receiver>
---
> <receiver>AlertDialog</receiver>
Как вы видите выше, в названии поля ввода также была небольшая опечатка: по этой причине я получил .ui
файл вставлен в вопрос!).
В коде Python я просто должен был правильно оформить свою функцию как Slot
, Вот полный код:
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QDialog, QMessageBox
from PySide2.QtCore import QFile, Slot
from PySide2.QtUiTools import QUiLoader
class Dialog(QDialog):
def __init__(self, parent = None):
super(Dialog, self).__init__(parent)
@Slot()
def alert(self):
alert = QMessageBox()
alert.setText(self.text_field.text())
alert.exec_()
if __name__ == '__main__':
app = QApplication([])
loader = QUiLoader()
loader.registerCustomWidget(Dialog)
ui_file = QFile('alert-quit.ui')
ui_file.open(QFile.ReadOnly)
dialog = loader.load(ui_file)
ui_file.close()
dialog.show()
app.exec_()
Аккуратно, не правда ли? Если кто-нибудь (включая мое будущее я) знает, как избавиться от .ui
доработка или иное улучшение этого решения, ваши комментарии очень приветствуются!
Так как я много боролся с Pyside2, я делюсь здесь, как мне это удалось, я не уверен, что это лучший способ продолжить, но он работает для меня.
Сначала вы должны установить pyqt5
с:
pip3 install pyqt5
И при условии, что ваш файл выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>344</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="alert_button">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Alert</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="quit_button">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Quit</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>alert_button</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>alert()</slot>
<hints>
<hint type="sourcelabel">
<x>91</x>
<y>30</y>
</hint>
<hint type="destinationlabel">
<x>133</x>
<y>51</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>alert()</slot>
<slot>quit()</slot>
</slots>
</ui>
Вы просто набираете команду:
pyuic5 path_to_your_ui_file -o path_to_the_output_python_file # don't forget the extension .py for the output
Обычно есть выход:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(344, 300)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
self.alert_button = QtWidgets.QPushButton(Dialog)
self.alert_button.setMaximumSize(QtCore.QSize(100, 16777215))
self.alert_button.setObjectName("alert_button")
self.verticalLayout.addWidget(self.alert_button)
self.quit_button = QtWidgets.QPushButton(Dialog)
self.quit_button.setMaximumSize(QtCore.QSize(100, 16777215))
self.quit_button.setObjectName("quit_button")
self.verticalLayout.addWidget(self.quit_button)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.retranslateUi(Dialog)
self.alert_button.clicked.connect(Dialog.alert)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.alert_button.setText(_translate("Dialog", "Alert"))
self.quit_button.setText(_translate("Dialog", "Quit"))
Все, что вам нужно сделать, это исправить импорт и загрузить сгенерированный файл:
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import QFile, QObject
import mainwindow # if your generated file name is mainWindow.py
class MainDialog(QDialog, mainwindow.Ui_Dialog):
def __init__(self, parent=None):
super(MainDialog, self).__init__(parent)
self.setupUi(self)
app = QApplication(sys.argv)
form = MainDialog()
form.show()
app.exec_()