#python #pyqt5
Вопрос:
Я использую QtWaitingSpinner, найденный здесь: https://github.com/snowwlex/QtWaitingSpinner. Вы можете создать и запустить спиннер следующим образом: spinner = QtWaitingSpinner(self); spinner.start()
. К сожалению, когда я пытаюсь сделать запрос на публикацию из своего графического интерфейса, счетчик останавливается до тех пор, пока не будет возвращен ответ. Следовательно, я вообще не вижу прядильщика, или если я преждевременно запускаю прядильщик, он перестает вращаться, ожидая ответа. Я думаю, что мне придется использовать какой-то асинхронный метод, такой как QThread или asyncio, но неясно, как лучше всего это обойти. Если кто-нибудь может показать мне лучший способ справиться с этим, я был бы благодарен. Вот упрощенная версия того, что я делаю:
class Obj(QDialog):
# some button calls this function when pressed
def submit(self):
#start spinner
spinner = QtWaitingSpinner(self)
spinner.start()
# post some data to some url, spinner should spin
r = requests.post('some_url.com', json=some_data)
# stop spinner
spinner.stop()
Ответ №1:
Проблема в том, что вы requests
блокируете цикл Qt, поэтому такие элементы, как QTimer
не работают. Одним из решений является выполнение этой задачи в другом потоке, простой способ сделать это-использовать QRunnable
и QThreadPool
.
class RequestRunnable(QRunnable):
def __init__(self, url, json, dialog):
QRunnable.__init__(self)
self.mUrl = url
self.mJson = json
self.w = dialog
def run(self):
r = requests.post(self.mUrl, json=self.mJson)
QMetaObject.invokeMethod(self.w, "setData",
Qt.QueuedConnection,
Q_ARG(str, r.text))
class Dialog(QDialog):
def __init__(self, *args, **kwargs):
QDialog.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
btn = QPushButton("Submit", self)
btn.clicked.connect(self.submit)
self.spinner = QtWaitingSpinner(self)
self.layout().addWidget(btn)
self.layout().addWidget(self.spinner)
def submit(self):
self.spinner.start()
runnable = RequestRunnable("https://api.github.com/some/endpoint",
{'some': 'data'},
self)
QThreadPool.globalInstance().start(runnable)
@pyqtSlot(str)
def setData(self, data):
print(data)
self.spinner.stop()
self.adjustSize()
Полный пример можно найти по следующей ссылке