我决定在我的一个脚本中添加一个GUI。脚本是一个简单的web刮刀。我决定使用一个工作线程来下载和解析数据可能需要一段时间。我决定使用PySide,但我对Qt的总体了解非常有限。
由于脚本应该在遇到验证码时等待用户输入,所以我决定应该等到QLineEdit
触发returnPressed
,然后将其内容发送到工作线程,以便它可以发送验证。这应该比忙着等待按下返回键要好。
似乎等待信号并不像我想象的那么直接,经过一段时间的搜索,我发现了几个类似于this的解决方案。不过,跨线程的信令和工作线程中的本地事件循环使我的解决方案更加复杂。
修了几个小时后还是不行。
会发生什么:
self.loop.exec_()
启动QEventLoop
main_window
类中的self.line_edit.returnPressed.connect(self.worker.stop_waiting)
连接的工作线程槽中的QEventLoop
退出loop.quit()
会发生什么:
……见上图。。。
退出QEventLoop
不起作用。self.loop.isRunning()
调用其exit()
后返回False
。self.isRunning
返回True
,因此线程似乎没有在奇怪的情况下死亡。但线程仍然停留在self.loop.exec_()
行。因此,即使事件循环告诉我它不再运行,线程仍然无法执行事件循环。
GUI的响应与worker线程类的插槽一样。我可以看到发送给工作线程的文本、事件循环的状态和线程本身,但在执行上述行之后什么也看不到。
代码有点复杂,因此我添加了一点伪代码python mix,省去了不重要的:
class MainWindow(...):
# couldn't find a way to send the text with the returnPressed signal, so I
# added a helper signal, seems to work though. Doesn't work in the
# constructor, might be a PySide bug?
helper_signal = PySide.QtCore.Signal(str)
def __init__(self):
# ...setup...
self.worker = WorkerThread()
self.line_edit.returnPressed.connect(self.helper_slot)
self.helper_signal.connect(self.worker.stop_waiting)
@PySide.QtCore.Slot()
def helper_slot(self):
self.helper_signal.emit(self.line_edit.text())
class WorkerThread(PySide.QtCore.QThread):
wait_for_input = PySide.QtCore.QEventLoop()
def run(self):
# ...download stuff...
for url in list_of_stuff:
self.results.append(get(url))
@PySide.QtCore.Slot(str)
def stop_waiting(self, text):
self.solution = text
# this definitely gets executed upon pressing return
self.wait_for_input.exit()
# a wrapper for requests.get to handle captcha
def get(self, *args, **kwargs):
result = requests.get(*args, **kwargs)
while result.history: # redirect means captcha
# ...parse and extract captcha...
# ...display captcha to user via not shown signals to main thread...
# wait until stop_waiting stops this event loop and as such the user
# has entered something as a solution
self.wait_for_input.exec_()
# ...this part never get's executed, unless I remove the event
# loop...
post = { # ...whatever data necessary plus solution... }
# send the solution
result = requests.post('http://foo.foo/captcha_url'), data=post)
# no captcha was there, return result
return result
frame = MainWindow()
frame.show()
frame.worker.start()
app.exec_()
插槽在创建
QThread
的线程中执行,而不是在QThread
控制的线程中执行。您需要将
QObject
移动到线程并将其插槽连接到信号,该插槽将在线程内部执行:你所描述的看起来很适合^{} 。
简单示例:
相关问题 更多 >
编程相关推荐