无法调用在不同线程下运行的QMessage.critical函数

问题描述 投票:2回答:1

我正在不同的线程(由threading.Thread创建)中运行单独的类方法。我想检查用户是否成功登录。

如果用户未登录,我想提示一个消息框

QtWidgets.QMessageBox.critical(
None,
"Wrong Credentials",
"The login credentials provided in settings are wrong. Kindly edit them and restart the application"
)

错误

QObject::setParent: Cannot set parent, new parent is in a different thread
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Segmentation fault (core dumped)

代码

"""
include all related imports
"""

# Code for Ui_Dialog is not important

class Application(Ui_Dialog):
    def __init__(self, Dialog):

        self.completer = QtWidgets.QCompleter(["days", "weeks", "months"],
                                              Dialog)
        self.recent_profiles: List[Dict[str, Union[str, WebElement]]] = []
        self.parent = Dialog
        Dialog.setWindowFlags(QtCore.Qt.WindowCloseButtonHint
                              | QtCore.Qt.WindowMinimizeButtonHint)
        qtRectangle = Dialog.frameGeometry()
        centerPoint = QtWidgets.QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        Dialog.move(qtRectangle.topLeft())

        self.setupUi(Dialog)
        self.retranslateUi(Dialog)

        self.db = self.__load_db()

        Thread(
            target=self.__run_auto,
            args=(
                self.db["auto"],
                self.db["email"],
                self.db["password"],
            )
        ).start()

    def __run_auto(self, auto, email, password):
        if not auto["predicate"] or not auto["lim"] or not auto["template"]:
            QtWidgets.QMessageBox.critical("Error", "Auto recent sender is not configured") # the  problem occurs here
        else:
            options = Options()
            options.headless = False
            driver: WebDriver = WebDriver()
            driver.get("https://example.com/user/login")

            user: WebElement = driver.find_element_by_xpath('//*[@id="username"]')
            pasw: WebElement = driver.find_element_by_xpath('//*[@id="password"]')
            login: WebElement = driver.find_element_by_xpath(
                '/html/body/div[1]/main/div/form/div[3]/button')

            user.send_keys(email)
            pasw.send_keys(password)
            login.click()
            SUCCESS = False

            try:
                WebDriverWait(driver, 2).until(
                EC.presence_of_element_located(
                        (By.XPATH,
                            "/html/body/div[1]/main/div/form/div[2]/div/a")))
            except (NoSuchElementException, TimeoutException):
                SUCCESS = True
                pass
            if not SUCCESS:
                # the problem occurs here
                QtWidgets.QMessageBox.critical(
                    None,
                    "Wrong Credentials",
                    "The login credentials provided in settings are wrong. Kindly edit them and restart the application"
                )

            driver.quit()
        pass

    def __load_db(self):
        with open("/home/jarvis/config.json") as file:
            return json.loads(file.read())

此外,如果您能告诉我如何将父线程对象传递给子线程,我将不胜感激。

python pyqt5 python-multithreading
1个回答
1
投票

您不得从另一个线程修改或创建GUI元素,而必须使用信号发送信息。另一方面,请勿从Ui_Dialog继承,因为它只是用于填充窗口小部件的类,而是必须从适当的窗口小部件继承,因此当您使用pyqtSlot装饰器时,可以确保在pyqtSlot装饰器中调用该方法。 GUI线程。

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        # ...

    def retranslateUi(self, Dialog):
        # ...


class DriverWorker(QtCore.QObject):
    messageChanged = QtCore.pyqtSignal(str, str)

    def start(self, *args, **kwargs):
        threading.Thread(
            target=self.__run_auto, args=args, kwargs=kwargs, daemon=True
        ).start()

    def __run_auto(self, auto, email, password):
        if not auto["predicate"] or not auto["lim"] or not auto["template"]:
            self.messageChanged.emit(
                "Error", "Auto recent sender is not configured"
            )  # the  problem occurs here
        else:
            options = Options()
            options.headless = False
            driver: WebDriver = WebDriver()
            driver.get("https://example.com/user/login")

            user: WebElement = driver.find_element_by_xpath('//*[@id="username"]')
            pasw: WebElement = driver.find_element_by_xpath('//*[@id="password"]')
            login: WebElement = driver.find_element_by_xpath(
                "/html/body/div[1]/main/div/form/div[3]/button"
            )

            user.send_keys(email)
            pasw.send_keys(password)
            login.click()
            SUCCESS = False

            try:
                WebDriverWait(driver, 2).until(
                    EC.presence_of_element_located(
                        (By.XPATH, "/html/body/div[1]/main/div/form/div[2]/div/a")
                    )
                )
            except (NoSuchElementException, TimeoutException):
                SUCCESS = True
                pass
            if not SUCCESS:
                # the problem occurs here
                self.messageChanged.emit(
                    "Wrong Credentials",
                    "The login credentials provided in settings are wrong. Kindly edit them and restart the application",
                )

            driver.quit()


class Dialog(QtWidgets.QDialog, Ui_Dialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        self.setupUi(self)

        self.setWindowFlags(
            QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint
        )

        qtRectangle = self.frameGeometry()
        centerPoint = QtWidgets.QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())

        self.db = self.__load_db()

        self.worker = DriverWorker()
        self.worker.start(self.db["auto"], self.db["email"], self.db["password"])
        self.worker.messageChanged.connect(self.on_message_changed)

    @QtCore.pyqtSlot(str, str)
    def on_message_changed(self, title, description):
        QtWidgets.QMessageBox.critical(None, title, description)

    def __load_db(self):
        with open("/home/jarvis/config.json") as file:
            return json.loads(file.read())


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Dialog()
    w.show()
    sys.exit(app.exec_())
© www.soinside.com 2019 - 2024. All rights reserved.