Tôi quyết định thêm GUI vào một trong các tập lệnh của mình. Kịch bản là một trình duyệt web đơn giản. Tôi quyết định sử dụng một chuỗi công nhân khi tải xuống và phân tích cú pháp dữ liệu có thể mất một lúc. Tôi quyết định sử dụng PySide, nhưng kiến thức của tôi về Qt nói chung là khá hạn chế.PySide chờ tín hiệu từ chủ đề chính trong luồng công nhân
Vì kịch bản được yêu cầu phải chờ người dùng nhập khi gặp một hình ảnh xác thực, tôi phải đợi cho đến khi QLineEdit
kích hoạt returnPressed
và gửi nội dung đó đến chuỗi công nhân để nó có thể gửi nó để xác thực. Điều đó nên được tốt hơn so với bận rộn chờ đợi cho các phím trở lại được ép.
Dường như chờ tín hiệu không thẳng như tôi nghĩ và sau khi tìm kiếm một lúc, tôi đã xem một số giải pháp tương tự như this. Việc báo hiệu qua các luồng và một vòng lặp sự kiện cục bộ trong luồng công nhân làm cho giải pháp của tôi phức tạp hơn một chút.
Sau khi mày mò với nó trong vài giờ nó vẫn không hoạt động.
gì là vụ xảy ra:
- Tải dữ liệu cho đến khi giới thiệu đến hình ảnh xác thực và nhập một vòng lặp
- Tải hình ảnh xác thực và hiển thị nó cho người dùng, bắt đầu
QEventLoop
bằng cách gọiself.loop.exec_()
- Thoát
QEventLoop
bằng cách gọiloop.quit()
trong khe chủ đề công nhân được kết nối quaself.line_edit.returnPressed.connect(self.worker.stop_waiting)
trong các lớpmain_window
- Xác thực captcha và vòng lặp nếu validati trên thất bại, nếu không thử lại url cuối cùng mà nên tải về bây giờ, sau đó di chuyển về với url tới
gì xảy ra:
... xem ở trên ...
Thoát khỏi
QEventLoop
không hoạt động.self.loop.isRunning()
trả lạiFalse
sau khi gọi sốexit()
.self.isRunning
trả vềTrue
, vì vậy chủ đề dường như không chết trong những trường hợp kỳ lạ. Chuỗi vẫn dừng ở đường dâyself.loop.exec_()
. Vì vậy, thread bị mắc kẹt khi thực thi vòng lặp sự kiện mặc dù vòng lặp sự kiện cho tôi biết nó không còn chạy nữa.GUI phản hồi như các vị trí của lớp chuỗi công nhân. Tôi có thể thấy các văn bản beeing gửi đến thread công nhân, tình trạng của vòng lặp sự kiện và các chủ đề chính nó, nhưng không có gì sau khi dòng đề cập ở trên được thực hiện.
Mã này là một chút phức tạp, như vậy tôi thêm một chút pseudo-code-python-mix rời ra không quan trọng:
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_()
Thật vậy, mà giải quyết vấn đề của tôi. Cảm ơn. –