3

I've been working some web automation projects. In this exampe, I reduced my code to basically opening some URLs. I want to add some user friendly interface while the main process was continuing. However when I want to show user to loading gif, It just freeze, because of the selenium process. If selenium process done, then the gif rest time of gif continues. For example, my loading gif is set to 20 secs. The selenium process took 5 secs. So for 5 secs, my loading gif freezes, then the selenium process done and closed, the loading gif animation continues for 14 secs.

Also is there a way to do it with overlay. I searched some examples and tried some, but it didnt work

import sys
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class LoadingScreen(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(200,200)
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.CustomizeWindowHint)

        self.label_animation = QLabel(self)
        self.movie = QMovie("loading.gif")
        self.label_animation.setMovie(self.movie)

        timer = QTimer(self)
        self.startAnimation()
        timer.singleShot(20000, self.stopAnimation)

        self.show()

    def startAnimation(self):
        self.movie.start()

    def stopAnimation(self):
        self.movie.stop()
        self.close()

class demo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Loading Overlay with Selenium Problem")
        self.resize(500, 500)
        self.center()
        self.twitter_icon = QtWidgets.QLabel("")
        self.twitter_icon.setAlignment(Qt.AlignCenter)
        self.pixmap = QtGui.QPixmap("twitter.png")
        self.pixmap = self.pixmap.scaled(64, 64, Qt.KeepAspectRatio, Qt.FastTransformation)
        self.twitter_icon.setPixmap(self.pixmap)
        self.twt_btn = QtWidgets.QPushButton("Twitter")

        v_box = QtWidgets.QVBoxLayout()
        v_box.addStretch()
        v_box.addWidget(self.twitter_icon)
        v_box.addWidget(self.twt_btn)
        v_box.addStretch()

        self.setLayout(v_box)

        self.twt_btn.clicked.connect(self.clkdBtn)
        self.show()

    def clkdBtn(self):
        self.hide()
        self.loading = LoadingScreen()
        browser = webdriver.Chrome()
        browser.get("https://twitter.com/login")
        time.sleep(1)
        #do more stuff in project instead i add more url
        browser.get("https://twitter.com/explore")
        time.sleep(1)
        browser.get("https://twitter.com/login")
        time.sleep(1)
        browser.close()
        time.sleep(1)
        self.show()

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

app = QApplication(sys.argv)
dm = demo()
app.exit((app.exec_()))
Fatih Tüz
  • 133
  • 1
  • 12

1 Answers1

3

You should not implement time consuming tasks (selenium and time.sleep()) in the main thread as they block the GUI so you should run that part in another thread and notify the GUI using signals to change its state (show or hide windows)

import sys
import threading
import time

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

from PyQt5 import QtWidgets, QtGui, QtCore


class SeleniumManager(QtCore.QObject):
    started = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()

    def start(self):
        threading.Thread(target=self._execute, daemon=True).start()

    def _execute(self):
        self.started.emit()
        browser = webdriver.Chrome()
        browser.get("https://twitter.com/login")
        time.sleep(1)
        # do more stuff in project instead i add more url
        browser.get("https://twitter.com/explore")
        time.sleep(1)
        browser.get("https://twitter.com/login")
        time.sleep(1)
        browser.close()
        time.sleep(1)
        self.finished.emit()


class LoadingScreen(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(200, 200)
        self.setWindowFlags(
            QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.CustomizeWindowHint
        )

        self.label_animation = QtWidgets.QLabel(self)
        self.movie = QtGui.QMovie("loading.gif")
        self.label_animation.setMovie(self.movie)

    def startAnimation(self):
        self.movie.start()
        self.show()
        QtCore.QTimer.singleShot(2 * 1000, self.stopAnimation)

    def stopAnimation(self):
        self.movie.stop()
        self.hide()


class Demo(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Loading Overlay with Selenium Problem")
        self.resize(500, 500)
        self.center()
        self.twitter_icon = QtWidgets.QLabel("")
        self.twitter_icon.setAlignment(QtCore.Qt.AlignCenter)
        self.pixmap = QtGui.QPixmap("twitter.png")
        self.pixmap = self.pixmap.scaled(
            64, 64, QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation
        )
        self.twitter_icon.setPixmap(self.pixmap)
        self.twt_btn = QtWidgets.QPushButton("Twitter")

        v_box = QtWidgets.QVBoxLayout(self)
        v_box.addStretch()
        v_box.addWidget(self.twitter_icon)
        v_box.addWidget(self.twt_btn)
        v_box.addStretch()

        self.loading = LoadingScreen()
        self._manager = SeleniumManager()

        self._manager.started.connect(self.loading.startAnimation)
        self._manager.finished.connect(self.loading.stopAnimation)
        self.twt_btn.clicked.connect(self._manager.start)
        self._manager.started.connect(self.hide)
        self._manager.finished.connect(self.show)

    def center(self):
        qr = self.frameGeometry()
        cp = QtWidgets.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())


if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    dm = Demo()
    dm.show()
    app.exit((app.exec_()))
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you soooo much! It worked. As far as I understand, the time.sleep() blocks the process of gif. Thats why it didnt worked ? I asked this to be sure. – Fatih Tüz May 07 '20 at 14:12
  • Now it's working properly. I just deleted my last comment by mistake btw, to people who see this topic is not going to see my second question to understand the minor problem. But its ok, because program is working, thanks to you! :) – Fatih Tüz May 07 '20 at 14:45
  • Hello @eyllanesc, i was working with my project today. I have minor another problem, but I couldnt find it and didnt want to open new topic. I have 2 QLineEdit and 1 QTextEdit in my Demo class. I just want to take their text to enter in selenium. ie, Demo.username.text() and it says wrapped C/C++ object of type QLineEdit has been deleted error. I tried to solve with 3 solutions. Every solution didnt work idk why. Can you please help me withthat? – Fatih Tüz May 08 '20 at 10:11