Pyqt5 Подождите, пока виджет не станет видимым

Я ищу способ дождаться полного отображения QWidget перед вызовом функции. У меня есть два окна: родительское и дочернее.

Родительская форма представляет собой окно с кнопкой, которая вызывает openChild, которая скрывает родительский элемент, показывает дочерний элемент, а затем выполняет основную функцию дочернего элемента busyFunc:

from PyQt5 import QtCore, QtGui, QtWidgets
from Child import Child_Form
import sys

class Parent_Form(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.setupUi(self)
        self.Child = Child_Form(self)

    def setupUi(self, Parent):
        Parent.setObjectName("Parent")
        Parent.resize(400, 300)
        self.nextWindow = QtWidgets.QPushButton(Parent)
        self.nextWindow.setGeometry(QtCore.QRect(150, 120, 91, 31))
        self.nextWindow.setObjectName("nextWindow")

        self.retranslateUi(Parent)
        QtCore.QMetaObject.connectSlotsByName(Parent)

    def retranslateUi(self, Parent):
        _translate = QtCore.QCoreApplication.translate
        Parent.setWindowTitle(_translate("Parent", "Parent Window"))
        self.nextWindow.setText(_translate("Parent", "Next Window"))

        self.nextWindow.clicked.connect(self.openChild)

    def openChild(self):
        self.hide()
        self.Child.show()
        self.Child.busyFunc()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = Parent_Form()
    ex.show()
    sys.exit(app.exec_())

Дочерняя форма имеет только метку и область прокрутки, в которой есть текстовое редактирование.

from PyQt5 import QtCore, QtGui, QtWidgets

class Child_Form(QtWidgets.QWidget):
    def __init__(self, Parent_Form):
        QtWidgets.QWidget.__init__(self)
        self.setupUi(self)
        self.parent = Parent_Form

    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(20, 10, 61, 16))
        self.label.setObjectName("label")
        self.scrollArea = QtWidgets.QScrollArea(Form)
        self.scrollArea.setGeometry(QtCore.QRect(20, 40, 361, 241))
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 359, 239))
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.textEdit = QtWidgets.QTextEdit(self.scrollAreaWidgetContents)
        self.textEdit.setGeometry(QtCore.QRect(0, 0, 361, 241))
        self.textEdit.setObjectName("textEdit")
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Child Window"))
        self.label.setText(_translate("Form", "Status:"))

    def busyFunc(self):
        for i in range(0, 1000000000):
            pass

Проблема заключается в том, что когда вызывается busyFunc (фактическая функция представляет собой огромную программу, поэтому я опустил ее для ясности. Я моделирую проблему с помощью цикла).

Parent скрыт, но Child выглядит так, пока не будет выполнено busyFunc.

Как я могу полностью загрузить дочерний элемент, а затем выполнить busyFunc?


person Jaitnium    schedule 16.06.2017    source источник
comment
Если есть какой-то способ, чтобы я мог прояснить свой вопрос, пожалуйста, скажите об этом!   -  person Jaitnium    schedule 16.06.2017
comment
посмотри мое решение   -  person eyllanesc    schedule 16.06.2017


Ответы (1)


Одним из решений является запуск функции busyFunc через некоторое время через таймер.

def openChild(self):
    self.hide()
    self.Child.show()
    QtCore.QTimer.singleShot(100, self.Child.busyFunc)

Проблема будет заключаться в том, что интерфейс заблокирован во время выполнения этой функции, для решения этой проблемы рекомендуется запустить эту задачу в потоке.

class Thread(QtCore.QThread):
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)

    def run(self):
        for i in range(0, 1000000000):
            pass

class Child_Form(QtWidgets.QWidget):
    def __init__(self, Parent_Form):
        [...]
    def busyFunc(self):
        self.thread = Thread(self)
        self.thread.start() 

Очевидно, что текущий код busyFunc не взаимодействует с графическим интерфейсом, т. е. не обновляет никаких значений графического интерфейса, поэтому проблем не возникнет, но если этот код должен обновить некоторые данные графического интерфейса, он должен делать это через сигналы, а не напрямую:

class Thread(QtCore.QThread):
    signal = QtCore.pyqtSignal(str)
    signal2 = QtCore.pyqtSignal(list)
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)

    def run(self):
        self.signal.emit("start")
        for i in range(0, 1000000000):
            pass
        self.signal.emit("finish")
        self.signal2.emit([1, 2, 3, 4])

class Child_Form(QtWidgets.QWidget):
    def __init__(self, Parent_Form):
        [...]
    def busyFunc(self):
        self.thread = Thread(self)
        self.thread.signal.connect(lambda text: self.textEdit.append(text))
        self.thread.signal2.connect(lambda l: print(l))
        self.thread.start() 

class Parent_Form(QtWidgets.QWidget):
    def __init__(self):
        [...]
    def openChild(self):
        self.hide()
        self.Child.show()
        self.Child.busyFunc()
person eyllanesc    schedule 16.06.2017
comment
Спасибо за подробное решение! Я дам вам знать, как это получается. - person Jaitnium; 16.06.2017
comment
Я попробовал ваше решение и почти решил свою проблему. Есть ли способ выдать список из потока? - person Jaitnium; 16.06.2017
comment
Если вы можете, я обновил код, показывающий, как это сделать. - person eyllanesc; 16.06.2017
comment
А, это имеет смысл. Поточное решение отлично работало для загрузки дочернего окна во время работы busyFunc. Спасибо еще раз! - person Jaitnium; 16.06.2017