1

我想用样式表自定义 QProgressBar 的外观。我想给它那种动画的、“不确定的”外观。所以我制作了一个动画 GIF 来贴在QProgressBar::chunk.

它显示得很好,但图像是静态的,没有动画。有什么建议或解决方法吗?

我在 OS X 10.8 上运行 PyQt 4.9.4。

4

1 回答 1

3

因此,这是您面临的一个稍微复杂的问题。

QProgressBar 依赖于来自循环的信息或某个确定的数量来表示完成百分比。当您通过代码设置值时,Qt 将设置进度条的值,重绘它并显示更新后的值。这实际上需要在您的循环中进行几毫秒的处理。如果你不这样做,那么 Qt 的优化将永远不会重绘。这是同步的。

您想要的“不确定”外观(如 AJAX gif 微调器或条形图)在 Web 上使用,因为该进程实际上已从客户端移出并在服务器上进行处理并等待响应。客户端的进程完全没有被阻塞,所以可以随电影自由更新界面。

您可以通过在 QLabel 中使用 QMovie 来实现您想要的外观:

movie = QMovie()
movie.setFileName('/path/to/ajax_loader.gif')
movie.start()

label = QLabel(parent)
label.setMovie(movie)

这将使您的不确定微调器。但是,它只会在事件循环正在处理事件时播放。一旦你开始你的实际工作进程,它就会阻塞事件循环,这样你的电影就会开始播放。

您实际上需要将事件“泵送”给循环中的播放器以使其更新。您可以通过以下方式做到这一点:

app = QApplication.instance()

# show my label
label.show()

for obj in objs:
    # process stuff on my obj
    app.processEvents()

# hide the label
label.hide()

当然,根据您在循环中执行的每个单独操作需要多长时间,您的微调器/加载器电影将“卡住”,直到再次处理事件。

确实,实现您想要的外观的最佳方法是使用线程应用程序。您可以使用 QThread 执行所有操作,并在处理时向用户显示加载器图像。这更类似于 ajax 的工作方式 - 主 Qt 事件循环将在您的工作线程处理所有内容时继续运行 - 在未知的时间内。这是异步的。

就像是:

class MyThread(QThread):
    def run( self ):
       # perform some actions
       ...

class MyDialog(QDialog):
    def __init__( self, parent ):
        # initialize the dialog
        ...
        self._thread = MyThread(self)
        self._thread.finished.connect(self.refreshResults)

        self.refresh()

    def refresh( self ):
        # show the ajax spinner
        self._ajaxLabel.show()

        # start the thread and wait for the results
        self._thread.start()

    def refreshResults( self ):
        # hide the ajax spinner
        self._ajaxLabel.hide()

        # process the thread results
        ...

我有一个加载器小部件,每当我在我的 GUI 库中执行此类操作时都会使用它。如果您想查看/使用它的代码,请访问http://dev.projexsoftware.com/projects/projexui并且该类是 XLoaderWidget (projexui.widgets.xloaderwidget)

设置与上面相同,但只是:

from projexui.widgets.xloaderwidget import XLoaderWidget

class MyThread(QThread):
    def run( self ):
       # perform some actions
       ...

class MyDialog(QDialog):
    def __init__( self, parent ):
        # initialize the dialog
        ...
        self._thread = MyThread(self)
        self._thread.finished.connect(self.refreshResults)

        self.refresh()

    def refresh( self ):
        # show the ajax spinner
        XLoaderWidget.start(self)

        # start the thread and wait for the results
        self._thread.start()

    def refreshResults( self ):
        # hide the ajax spinner
        XLoaderWidget.stop(self)

        # process the thread results
        ...
于 2012-08-10T20:10:08.660 回答