无法在不同线程下调用 QMessage.critical 函数 运行
Unable to invoke QMessage.critical function running under different thread
我是 运行 不同线程中的一个单独的 class 方法(由 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())
此外,如果您能告诉我如何将父线程对象传递给子线程,我将不胜感激。
您不得从另一个线程修改或创建 GUI 元素,而必须使用信号发送信息。另一方面,不要从 Ui_Dialog 继承,因为它只是一个用于填充小部件的 class,相反,您必须从适当的小部件继承,因此当您使用 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_())
我是 运行 不同线程中的一个单独的 class 方法(由 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())
此外,如果您能告诉我如何将父线程对象传递给子线程,我将不胜感激。
您不得从另一个线程修改或创建 GUI 元素,而必须使用信号发送信息。另一方面,不要从 Ui_Dialog 继承,因为它只是一个用于填充小部件的 class,相反,您必须从适当的小部件继承,因此当您使用 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_())