Как я могу изменить форму курсора с помощью PyQt?

У меня есть простое приложение, которое запускает процесс, который может длиться несколько минут до завершения. Поэтому я пытаюсь предоставить пользователю индикатор того, что он обрабатывает запрос, например, изменить курсор на песочные часы.

Но я не могу заставить его работать правильно. Все мои попытки привели к ошибке или не дали результата. И я, кажется, неправильно называю формы курсора PyQt4.Qt.WaitCursor возвращает ошибку, что модуль не содержит его.

Как правильно указать пользователю, что процесс запущен?

8 ответов

Решение

Я думаю, что QApplication.setOverrideCursor это то, что вы ищете:

from PyQt4.QtCore import Qt
from PyQt4.QtGui import QApplication
...
QApplication.setOverrideCursor(Qt.WaitCursor)
# do lengthy process
QApplication.restoreOverrideCursor()

Хотя ответы Кэмерона и Дэвида отлично подходят для установки курсора ожидания на всю функцию, я считаю, что контекстный менеджер лучше всего подходит для установки курсора ожидания для фрагментов кода:

from contextlib import contextmanager
from PyQt4 import QtCore
from PyQt4.QtGui import QApplication, QCursor

@contextmanager
def wait_cursor():
    try:
        QApplication.setOverrideCursor(QCursor(QtCore.Qt.WaitCursor))
        yield
    finally:
        QApplication.restoreOverrideCursor()

Затем поместите длинный код процесса в блок с:

with wait_cursor():
    # do lengthy process
    pass

Решение Эхуморо правильное. Это решение является модификацией ради стиля. Я использовал то, что сделал Эхумор, но использовал декоратор python.

from PyQt4.QtCore import Qt
from PyQt4.QtGui import QApplication, QCursor, QMainWidget

def waiting_effects(function):
    def new_function(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        try:
            function(self)
        except Exception as e:
            raise e
            print("Error {}".format(e.args[0]))
        finally:
            QApplication.restoreOverrideCursor()
    return new_function

Я могу просто установить декоратор на любой метод, который мне нужен, чтобы спиннер был активным.

class MyWigdet(QMainWidget):

    # ...

    @waiting_effects
    def doLengthyProcess(self):
        # do lengthy process
        pass
      from qtpy import QtCore, QtGui, QtWidgets

def waiting_effect(function):
    def waiting(*args, **kwargs):
        QtWidgets.QApplication.setOverrideCursor(
             QtCore.Qt.CursorShape(QtCore.Qt.CursorShape.WaitCursor)
        )
        try:
            function(*args, **kwargs)     
        finally:
            QtWidgets.QApplication.restoreOverrideCursor()

Если вы используете PyQt5/PySide2, это может быть полезно, прекрасно работает с декорирующими функциями, имеющими несколько аргументов.

Вы можете использовать класс QgsTemporaryCursorOverride https://qgis.org/api/classQgsTemporaryCursorOverride.html

Но в Python вы должны использовать диспетчер контекста Python, который теперь включен в PyQGIS:

      from qgis.PyQt.QtCore import Qt
from qgis.utils import OverrideCursor

with OverrideCursor(Qt.WaitCursor):
    do_a_slow(operation)

Лучше так:

def waiting_effects(function):
    def new_function(*args, **kwargs):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        try:
            return function(*args, **kwargs)
        except Exception as e:
            raise e
            print("Error {}".format(e.args[0]))
        finally:
            QApplication.restoreOverrideCursor()
    return new_function

Я считаю, что мне часто нужно делать:

QApplication.setOverrideCursor(Qt.WaitCursor)
QApplication.ProcessEvents()
...
QApplication.restoreOverrideCursor()

Однако! Во время инициализации графического интерфейса я обнаружил, что по какой-то причине необходимо внести изменения:

self.ui.show()  # Or your equivalent code to show the widget
QApplication.processEvents()
QApplication.setOverrideCursor(Qt.WaitCursor)
app.processEvents()
...
QApplication.restoreOverrideCursor()

В противном случае курсор не будет "восстанавливаться" до тех пор, пока мышь не пройдет над виджетом, который его изменяет (например, QLineEdit), аналогично тому, что упоминал @Guimoute

На мой взгляд, лучший способ добавить курсор - это использовать декораторы. Таким образом, вы можете запустить любую функцию, просто добавив курсор к этой функции в качестве декоратора.

import decorator
@decorator.decorator
def showWaitCursor(func, *args, **kwargs):
    QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
    try:
        return func(*args, **kwargs)
    finally:
        QtWidgets.QApplication.restoreOverrideCursor()

@showWaitCursor
def youFunc():
    # Long process
Другие вопросы по тегам