Pyqt5 等到小部件可见
Pyqt5 Wait until widget is visible
我正在寻找一种方法来等待 QWidget 完全显示后再调用函数。我有两个 windows:一个 parent 和一个 child.
parent 表单是一个 window,带有一个调用 openChild
的按钮,隐藏 parent,显示 child,然后执行 child的主要功能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_())
child 表单只有一个标签和一个包含文本编辑的滚动区域。
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
完成。
如何让child像这样完全加载然后执行busyFunc
?
一种解决方案是在一段时间后通过计时器启动 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 的当前代码不与 GUI 交互,即不更新 GUI 的任何值,所以不会有问题,但是如果这个代码必须更新 GUI 的某些数据,则必须通过信号,不是直接的:
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()
我正在寻找一种方法来等待 QWidget 完全显示后再调用函数。我有两个 windows:一个 parent 和一个 child.
parent 表单是一个 window,带有一个调用 openChild
的按钮,隐藏 parent,显示 child,然后执行 child的主要功能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_())
child 表单只有一个标签和一个包含文本编辑的滚动区域。
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
完成。
如何让child像这样完全加载然后执行busyFunc
?
一种解决方案是在一段时间后通过计时器启动 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 的当前代码不与 GUI 交互,即不更新 GUI 的任何值,所以不会有问题,但是如果这个代码必须更新 GUI 的某些数据,则必须通过信号,不是直接的:
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()