我有一个问题,我是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
答案 0 :(得分:1)
您无法在实例上动态定义信号,必须将它们声明为类属性。此外,SIGNAL
仅用于旧式语法,无人使用,因为新式信号/插槽语法使用pyqtSignal
和pyqtSlot
。此外,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_())
我将尝试在上面的“我的代码”中执行相同操作..再次感谢