python - PyQt检测worker何时完成并在主线程中执行某些操作

时间:2016-05-27 16:48:17

标签: python selenium-webdriver pyqt

我有一个问题,我是PyQt的新手,我无法弄清楚如何使用主线程(UI线程)检测我的工作者(线程完成)的时间.. 基本上我想说的是: 我有一个创建UI和一组小部件的类,当我点击一个按钮时,我的 Qthread 成功运行问题,我无法检测到我的线程何时完成...因为我想在线程完成时启动一个新的UI ..当我从线程内部执行此操作时出现错误:

QPixmap: It is not safe to use pixmaps outside the GUI thread

所以,如果有人知道如何使用作为UI线程的主线程检测我的线程的完成SIGNAL

无论如何这里是我的代码..我到目前为止尝试了

from  PyQt4 import QtGui, QtCore
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from PyQt4 import QtCore


class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.setGeometry(50, 50, 400, 300)
        self.setWindowTitle("Log In to your facebook account")
        self.setWindowIcon(QtGui.QIcon("../data/facebook.ico"))
        self.setStyleSheet("background-color: #3b5998;")

        self.initUI()


    def initUI(self):
        """Create facebook login ui"""
        LineEditStyle = "background-color: white;padding: 10px 10px 10px 20px; font-size: 14px; font-family: consolas;" \
                        "border: 2px solid #3BBCE3; border-radius: 4px;"

        logo = QtGui.QLabel("Facebook")
        logo.setStyleSheet("font-size: 50px; font-weight:bold;color:white;")
        logo.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)

        trustus = QtGui.QLabel("This Feature requires you to sign in to your facebook account.\n"
                               "Please enter your facebook email and password, trust us, we won't steal your \n"
                               "login info, you're in control + you can always go back if you want.")

        email = QtGui.QLineEdit()
        email.setPlaceholderText("Your facebook email address")
        email.setStyleSheet(LineEditStyle)

        password = QtGui.QLineEdit()
        password.setEchoMode(QtGui.QLineEdit.Password)
        password.setPlaceholderText("Your facebook password")
        password.setStyleSheet(LineEditStyle)

        login = QtGui.QPushButton("Log In")
        login.clicked.connect(lambda: self.login(email.text(), password.text()))
        login.setStyleSheet("background: #2A49A5;border: 1px solid #082783;color: white;padding: 10px;"
                            "text-decoration: none;font: 12px Verdana, sans-serif;")

        keepLogin = QtGui.QCheckBox()
        keepLogin.setEnabled(True)

        layout = QtGui.QVBoxLayout()

        self.setLayout(layout)
        layout.addWidget(logo)
        layout.addWidget(trustus)
        layout.addStretch()
        layout.addWidget(email)
        layout.addWidget(password)
        layout.addStretch()
        layout.addWidget(login)

    def look(self):
        print("oh you made it, this method got run from insid the main thread insteed the ")

    def login(self, email, password):
        if not email.strip() or not email.find("@") or not password.strip():
            print("please insert a valid entry")
        else:
            self.thread = LoginWorker(email, password)
            self.connect(self.thread, QtCore.SIGNAL("finished()"), self.look)
            self.thread.start()


class LoginWorker(QtCore.QThread):
    def __init__(self, facebook_email, facebook_password, parent=None):
        super(LoginWorker, self).__init__(parent)
        self.email = facebook_email
        self.password = facebook_password
        self.driver = None

        self.signal = QtCore.SIGNAL("signal")

    def run(self):

        if self.driver is None:
            self.driver = webdriver.Firefox()
        else:
            self.driver.quit()
            self.driver = webdriver.Firefox()
        self.emit(self.signal, "hi from thread")

        self.driver.get("https://wwww.facebook.com/")
        self.test_login()

    def test_login(self):
        emailFieldID = "email"
        passFieldID = "pass"
        loginButtonXpath = "//input[@value='Log In']"

        emailFieldElement = WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element_by_id(emailFieldID))
        passFieldElement = WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element_by_id(passFieldID))
        loginButtonElement = WebDriverWait(self.driver, 10).until(
            lambda driver: driver.find_element_by_xpath(loginButtonXpath))

        emailFieldElement.clear()
        emailFieldElement.send_keys(self.email)

        passFieldElement.clear()
        passFieldElement.send_keys(self.password)

        loginButtonElement.click()

        self.checkLogin()

    def checkLogin(self):
        try:
            self.driver.find_element_by_id("loginbutton")
            print("You're not logged in..")
        except:
            """after the execution of this line right here it will be great if i could run the method done() using the Main Thread instead of  the worker.. i hope you got what I am trying to see"""
            print("You're Logged in")
            self.driver.quit()


def done():
    print("this method (done) needs to be run from the Main Thread :(, i will be happy if you could make it runs from the Main thread.. :) because later on this print will be replaced by the code that could run my new Window..:)")

请注意我使用的是PyQt4

2 个答案:

答案 0 :(得分:1)

您无法在实例上动态定义信号,必须将它们声明为类属性。此外,SIGNAL仅用于旧式语法,无人使用,因为新式信号/插槽语法使用pyqtSignalpyqtSlot。此外,pyqtSignal的参数应该是通过信号emit'的对象的类类型。所以你不能这样做

self.signal = QtCore.SIGNAL("signal")

你会这样做

class MyThread(QtCore.QThread):
    signal = QtCore.pyqtSignal(str)

    def run(self):
        self.signal.emit('The string sent through the signal')

另一方面,你应该宣布你的老虎机

class Window(...):

    @QtCore.pyqtSlot(str)
    def look(self, msg):
        print msg

    def ...
        thread = MyThread()
        thread.signal.connect(self.look)

如果您不关心从线程传回数据而关心它何时完成

    @QtCore.pyqtSlot()
    def look(self):
        print 'Thread finished'

    def ...
        thread = MyThread()
        thread.finished.connect(self.look)

答案 1 :(得分:0)

感谢Brendan Abel的回答,当我在简单的用户界面中运行您的代码时,它确实有效。

from  PyQt4 import QtGui, QtCore
import time, sys

class Worker(QtCore.QThread):
    signal = QtCore.pyqtSignal(str)

    def run(self):
        self.signal.emit(':) Oh I did it the string is final sent over the SIGNAL')

        x = 1
        while x < 10:
            time.sleep(1)
            x += 1


class Window(QtGui.QWidget):

    @QtCore.pyqtSlot(str)
    def look(self, msg):
        print(msg)
        print(self.thread.isFinished())

    def __init__(self):
        super(Window, self).__init__()
        self.setGeometry(50, 50, 400, 300)
        self.setWindowTitle("Log In to your facebook account")

        self.initUI()

    def initUI(self):
        button = QtGui.QPushButton("Start Thread", self)
        button.clicked.connect(self.handelClick)

    def handelClick(self):
        self.thread = Worker()
        self.thread.signal.connect(self.look)
        self.thread.start()



if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    ui  = Window()
    ui.show()
    sys.exit(app.exec_())

我将尝试在上面的“我的代码”中执行相同操作..再次感谢