Как я могу изменить форму курсора с помощью 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