I am running a separate class method in a different thread (created by threading.Thread
). I want to check if the user is logged in successfully or not.
If the user is not logged in, I want to prompt a message box
QtWidgets.QMessageBox.critical(
None,
"Wrong Credentials",
"The login credentials provided in settings are wrong. Kindly edit them and restart the application"
)
Error
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)
Code
"""
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())
Also, I would be thankful if you could tell me how to pass parent thread objects to the child thread.
You must not modify or create GUI elements from another thread, instead you must use the signals to send the information. On the other hand, do not inherit from Ui_Dialog since it is only a class that is used to fill in a widget, instead you must inherit from the appropriate widget so when you use the pyqtSlot decorator it ensures that the method will be invoked in the GUI thread.
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_())