#python #user-interface #pyqt
#python #пользовательский интерфейс #pyqt
Вопрос:
Предположим, у нас есть два окна, одно с кнопкой, родительское, и одно пустое, дочернее. Коды для родительского и дочернего элементов:
test_parent.py:
from PyQt5 import QtCore, QtGui, QtWidgets
from test_child import Ui_child
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(270, 208)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(90, 90, 89, 25))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton.clicked.connect(self.open_child)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
def open_child(self):
self.child = QtWidgets.QMainWindow()
self.ui = Ui_child()
self.ui.setupUi(self.child)
self.child.show()
MainWindow.hide()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
и test_child.py:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_child(object):
def setupUi(self, child):
child.setObjectName("child")
child.resize(275, 176)
self.centralwidget = QtWidgets.QWidget(child)
self.centralwidget.setObjectName("centralwidget")
child.setCentralWidget(self.centralwidget)
self.retranslateUi(child)
QtCore.QMetaObject.connectSlotsByName(child)
def retranslateUi(self, child):
_translate = QtCore.QCoreApplication.translate
child.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_child()
ui.setupUi(child)
child.show()
sys.exit(app.exec_())
С помощью этого кода, когда пользователь нажимает на кнопку, родительский элемент скрывается, а дочерний отображается. Теперь я хочу снова показать родительский элемент, когда пользователи закрывают дочерний элемент. Как я могу это сделать?
Ответ №1:
Хорошим решением является создание пользовательского сигнала для дочернего элемента и выдача его при закрытии окна.
Обратите внимание, что для этого вы должны правильно использовать файлы, созданные pyuic, что вы не делаете: эти файлы никогда не должны изменяться вручную, поскольку они предназначены только для импорта и не предназначены для дальнейшей реализации: есть много причин не делать этого,и один из них заключается в том, что их структура может привести к путанице в структуре объекта. Вы можете прочитать больше о правильном использовании этих файлов в официальных рекомендациях PyQt по использованию конструктора.
Самое главное, поскольку это простые object
классы python (а не классы виджетов Qt), они не допускают переопределения методов, что очень важно, особенно в подобных случаях.
Итак, прежде чем продолжить пример, перестройте эти файлы с pyuic
помощью и создайте новый скрипт для своей программы.
Концепция заключается в том, что дочерний класс будет иметь closed
сигнал, и сигнал будет передаваться внутри closeEvent
(который вызывается каждый раз, когда окно закрывается пользователем или программно с close()
помощью ); затем главное окно создает дочерний элемент (но не показывает его) прямо в __init__
, и соединяет его пользовательский сигнал сэто окно show
.
from PyQt5 import QtCore, QtGui, QtWidgets
from test_parent import Ui_MainWindow
from test_child import Ui_child
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.openChild)
# create an instance of the child
self.child = Child()
# connect its closed signal to show() of this window
self.child.closed.connect(self.show)
def openChild(self):
self.child.show()
self.hide()
class Child(QtWidgets.QMainWindow, Ui_child):
closed = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
self.setupUi(self)
def closeEvent(self, event):
self.closed.emit()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
Комментарии:
1. Я думаю, что я должен делать все в qt designer, но я просто видел в сети, что все делают pyuic, а затем модифицируют материал, который я не считаю уместным. Тем не менее, мне непонятно, что вы подразумеваете под «перестроить эти файлы с помощью pyuic». Вы имеете в виду вызов pyuic для каждого из них, создание файла py из пользовательского интерфейса (как я делал), а затем копирование того, что мне нужно для создания скрипта, который вы мне показали? Разве это не противоположно тому, что мы говорим, чтобы делать что-то в qt designer?
2. «все делали pyuic, а затем изменяли материал» к счастью, не все, и тот, кто это делает, почти всегда ошибается в этом (что еще хуже, предлагать это): это считается плохой практикой по множеству причин, и существует лишь очень мало случаев, для которых (очень ограниченных) модификаций требуетсяна самом деле требуется. Я имел в виду: избавьтесь от этих 2 файлов, перестроив их с помощью pyuic, используя ваши исходные файлы пользовательского интерфейса (в моем примере предполагается, что они будут называться
test_parent.py
иtest_child.py
), затем создайте новый файл с приведенным выше кодом таким, какой он есть, это будет ваш фактический программный скрипт.3. @musicamante в вашем примере, что возвращает self.child.parentWidget() ?
4. @pippo1980 он вернется
None
, поскольку дочерний элемент был создан без какого-либо родительского элемента (__init__
у него нет аргумента) и неsetParent()
вызывался для него.5. круто, вернуться к PyQt5, бороться с родительским / дочерним элементом! Это то же самое, что модальный / немодальный fromQt Designer или что-то еще?
Ответ №2:
from PyQt5 import QtCore, QtGui, QtWidgets
from test_parent import Ui_MainWindow
class Ui_child(object):
def setupUi(self, child):
child.setObjectName("child")
child.resize(275, 176)
self.centralwidget = QtWidgets.QWidget(child)
self.centralwidget.setObjectName("centralwidget")
child.setCentralWidget(self.centralwidget)
self.retranslateUi(child)
QtCore.QMetaObject.connectSlotsByName(child)
def retranslateUi(self, child):
_translate = QtCore.QCoreApplication.translate
child.setWindowTitle(_translate("MainWindow", "MainWindow"))
def closeEvent(self, event):
self.parent = Ui_MainWindow()
self.parent.setupUi(QtWidgets.QMainWindow())
self.parent.show()
self.hide()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_child()
ui.setupUi(child)
child.show()
sys.exit(app.exec_())
Комментарии:
1. Я не могу запустить родительский файл. В нем говорится: «из test_child import Ui_child ImportError: невозможно импортировать имя ‘Ui_child'»
2. Это неверный ответ: не только
from test_parent import Ui_MainWindow
строка создает циклический импорт (отсюда и ошибка импорта, отмеченная @Learningfrommasters), но он также не будет работать в любом случае:closeEvent()
никогда не будет вызван, поскольку класс не наследуется от QWidget. Пожалуйста, всегда проверяйте свой код перед отправкой ответа.