【问题标题】:Is there a way to create a custom animated / gif QCursor?有没有办法创建自定义动画/gif QCursor?
【发布时间】:2019-08-22 15:56:41
【问题描述】:

我正在尝试创建一个自定义动画光标,用于在发生类似于herehere 的冗长过程时替换常规光标,但是,我希望我的动画光标,例如使用 gif,就像标准 Qt.WaitCursor 的情况一样。我怎样才能做到这一点?我找到了关于动画系统托盘图标的this 解决方案,但是,我没有设法对其进行调整以使其与光标图标一起使用。

附带说明:当我尝试按照第一个链接中所述执行 pm.setAlphaChannel(bm) 时,它对我不起作用,并且出现以下错误:

'AttributeError: QPixmap' object has no attribute 'setAlphaChannel'

这很奇怪,因为根据documentation,QPixmap 确实有一个setAlphaChannel 方法。

【问题讨论】:

  • 你指的是什么动画?
  • 感谢您的提问!我添加了信息。 pyqt5 和动画我的意思是像 gif 之类的东西。例如,在 Windows 10 中,您有这个旋转的蓝色环。我想替换它。

标签: python pyqt pyqt5 qcursor


【解决方案1】:

一种可能的解决方案是创建一个类来处理给定小部件的光标更新。在下面的例子中,当按下开始按钮时光标被设置,当按下停止按钮时光标被恢复:

from PyQt5 import QtCore, QtGui, QtWidgets

class ManagerCursor(QtCore.QObject):
    def __init__(self, parent=None):
        super(ManagerCursor, self).__init__(parent)
        self._movie = None
        self._widget = None
        self._last_cursor = None

    def setMovie(self, movie):
        if isinstance(self._movie, QtGui.QMovie):
            if not self._movie != QtGui.QMovie.NotRunning:
                self._movie.stop()
            del self._movie
        self._movie = movie
        self._movie.frameChanged.connect(self.on_frameChanged)
        self._movie.started.connect(self.on_started)
        self._movie.finished.connect(self.restore_cursor)

    def setWidget(self, widget):
        self._widget = widget

    @QtCore.pyqtSlot()
    def on_started(self):
        if self._widget is not None:
            self._last_cursor = self._widget.cursor()

    @QtCore.pyqtSlot()
    def restore_cursor(self):
        if self._widget is not None:
            if self._last_cursor is not None:
                self._widget.setCursor(self._last_cursor)
        self._last_cursor = None

    @QtCore.pyqtSlot()
    def start(self):
        if self._movie is not None:
            self._movie.start()

    @QtCore.pyqtSlot()
    def stop(self):
        if self._movie is not None:
            self._movie.stop()
            self.restore_cursor()

    @QtCore.pyqtSlot()
    def on_frameChanged(self):
        pixmap = self._movie.currentPixmap()
        cursor = QtGui.QCursor(pixmap)
        if self._widget is not None:
            if self._last_cursor is None:
                self._last_cursor = self._widget.cursor()
            self._widget.setCursor(cursor)


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        start_btn = QtWidgets.QPushButton("start", clicked=self.on_start)
        stop_btn = QtWidgets.QPushButton("stop", clicked=self.on_stop)

        self._manager = ManagerCursor(self)
        movie = QtGui.QMovie("loading-icon.gif")
        self._manager.setMovie(movie)
        self._manager.setWidget(self)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(start_btn)
        lay.addWidget(stop_btn)
        lay.addStretch()

    @QtCore.pyqtSlot()
    def on_start(self):
        self._manager.start()

    @QtCore.pyqtSlot()
    def on_stop(self):
        self._manager.stop()

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

【讨论】:

  • 好的,如果您阅读了我之前的评论,请不要介意!我在我的 gif 文件的路径中犯了一个错误,所以它永远无法加载。不过,在这种情况下,我预计会出现错误消息,这就是为什么我花了这么长时间才找到它的原因。有趣的是 QMovie 只是忽略了不正确的文件路径。
  • @mapf Qt 出于效率原因不使用异常,在这种情况下假设您创建了一个空 QMovie,如果您想验证是否已加载 gif,您应该使用 isValid( ) 方法:print(movie.isValid())
  • 很高兴知道!谢谢!
  • 对不起,如果这很挑剔,但我有一个后续问题:当我使用here 描述的方法时,即QApplication.setOverrideCursor(Qt.WaitCursor),光标保持不变(因为一直在旋转cicle) 并且无论您将鼠标悬停在哪里都会不断更新。但是,使用您的方法,情况并非如此。例如。如果您将鼠标悬停在窗口的框架或文本字段上,则光标会发生变化,并且由于某种原因,当我使用 pickle(第二个线程)加载数据时,光标不会更新。
  • @mapf 如果您还有其他问题(可能与我回答的问题相似),那么您必须创建一个新出版物。
猜你喜欢
  • 2012-08-22
  • 2010-12-04
  • 2020-05-19
  • 2016-08-25
  • 2014-12-15
  • 2021-04-18
  • 1970-01-01
  • 2010-10-23
  • 1970-01-01
相关资源
最近更新 更多