PyQt5 загрузка спиннера останавливается по запросу после отправки

#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()
 

Полный пример можно найти по следующей ссылке