【问题标题】:How can I change the cursor shape with PyQt?如何使用 PyQt 更改光标形状?
【发布时间】:2012-01-03 08:53:18
【问题描述】:

我有一个简单的应用程序,它运行的进程可能会持续几分钟才能完成。我正在尝试向用户提供它正在处理请求的指示 - 例如将光标更改为沙漏。

但我不能让它正常工作。我所有的尝试都导致错误或无效。而且我似乎错误地调用了光标形状,因为PyQt4.Qt.WaitCursor 返回了一个模块不包含它的错误。

向用户指示进程正在运行的正确方法是什么?

【问题讨论】:

    标签: python pyqt pyqt5 pyqt4 mouse-cursor


    【解决方案1】:

    你可以使用类 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)
    

    【讨论】:

      【解决方案2】:

      我发现我经常需要做的事情:

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

      但是!在 GUI 的初始化过程中,我发现由于某种原因需要进行修改:

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

      否则光标不会“恢复”,直到鼠标经过修改它的小部件(如 QLineEdit),类似于 @Guimute 提到的内容

      【讨论】:

        【解决方案3】:

        在我看来,添加光标的最佳方法是使用装饰器。通过这种方式,您只需将光标添加到该函数作为装饰器即可运行任何函数

        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
        

        【讨论】:

          【解决方案4】:

          我认为QApplication.setOverrideCursor 是您正在寻找的:

          PyQt5

          from PyQt5.QtCore import Qt
          from PyQt5.QtWidgets import QApplication
          ...
          QApplication.setOverrideCursor(Qt.WaitCursor)
          # do lengthy process
          QApplication.restoreOverrideCursor()
          

          PyQt4

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

          【讨论】:

          • 注意:这适用于 PyQt4。但是 Linux(Ubuntu 16.10)下的 PySide 1.2.2 说“X 错误:BadCursor(无效的光标参数)6”“主要操作码:2(X_ChangeWindowAttributes)”“资源 id:0xa”。提供 PySide 的 setOverrideCursor(Qt.WaitCursor) 而不是 setOverrideCursor(QCursor(Qt.WaitCursor)) 有效——尽管文档说需要 QCursor()。在某些情况下,还原会出现类似的错误。这似乎是一个已知的 PySide 错误。
          • @Ubuntourist。谢谢 - 我可以确认 PySide 中的错误。 QCursor 类有一个复制构造函数,它接受 Qt.CursorShape 枚举值,因此实际上没有必要使用 QCursor 本身。我想在 Qt 端创建 QCursor 可以解决 PySide 问题。
          • 出于某种原因,这个解决方案在 PyQt5 中适用于我,但它需要失去焦点才能恢复常规光标(alt+tab,或在其他小部件周围移动,这些小部件也会像任何输入小部件一样改变光标) .如果我不动,QApplication.restoreOverrideCursor() 一个人不会做任何事情。
          • @Guimute 你应该发布一个关于这个的新问题并提供minimal reproducible example
          【解决方案5】:

          虽然 Cameron 和 David 的回答非常适合在整个函数上设置等待光标,但我发现上下文管理器最适合为代码的 sn-ps 设置等待光标:

          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块中:

          with wait_cursor():
              # do lengthy process
              pass
          

          【讨论】:

          • 这是最简单、最优雅、最通用的
          【解决方案6】:

          这样更好:

          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
          

          【讨论】:

            【解决方案7】:

            ekhumoro 的解决方案是正确的。此解决方案是为了风格而进行的修改。我使用了 ekhumor 所做的,但使用了 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
            

            【讨论】:

            • 装饰器是个好主意,谢谢。我建议调用function(*args, **kwargs),返回function 的返回值,并将其调用包装在try...finally 块中以获得更多好处。我似乎无法将其放在此评论中,因此接下来我将尝试编辑您的解决方案。
            • 将 try 块更改为 return function(*args, **kwargs) 也可能有用,或者至少在我的情况下是这样。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-12-08
            • 1970-01-01
            相关资源
            最近更新 更多