PyQt 进度条忙指示 [英] Busy indication with PyQt progress bar

查看:60
本文介绍了PyQt 进度条忙指示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个脚本来显示忙碌指示在执行任务时.当任务结束时,进度条将填充到最后显示 100% 任务已完成.我只是想让进度条显示正在执行的任务.但是当我开始时任务,忙指示停止.在我看来,指示和任务不能一起继续.请帮我.这是我的代码:

I'm trying to write a script which will display a busy indication while performing the task. And when the task is over, the progress bar will fill to the end showing that 100% task has been completed. I just want the progress bar to show a task is going on.But when I start the task, busy indication stops.It seems to me that the indication and the task can not continue together. Please help me. Here's mycode:

from PyQt4 import QtCore, QtGui
from time import sleep
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(344, 159)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.pb = QtGui.QProgressBar(self.centralwidget)
        self.pb.setGeometry(QtCore.QRect(20, 20, 301, 31))
        self.pb.setProperty("value", 0)
        self.pb.setObjectName(_fromUtf8("pb"))
        self.btn = QtGui.QPushButton(self.centralwidget)
        self.btn.setGeometry(QtCore.QRect(20, 70, 98, 27))
        self.btn.setObjectName(_fromUtf8("btn"))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 344, 25))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QObject.connect(self.btn, QtCore.SIGNAL(_fromUtf8("clicked()")), self.action)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)            

    def action(self):
        self.pb.setRange(0, 0)
        sleep(3) # Here I want to run a command.For example: os.system('copy something')
        self.pb.setRange(0, 100)
        self.pb.setValue(100)
        QtGui.qApp.processEvents()

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.btn.setText(_translate("MainWindow", "Start", None))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

推荐答案

首先,直接编辑用 QtDesigner 创建的代码是个坏主意.您可能已经看到 # WARNING!在此文件中所做的所有更改都将丢失! 位于文档顶部.对于这样一个简单的小部件,最好使用手动编码.

First, it's a bad idea to directly edit the code created with QtDesigner. You may have seen the line # WARNING! All changes made in this file will be lost! at the top of the document. For such a simple widget, you're better off with manual coding.

其次,仔细看看 action 槽的实际作用.

Secondly, take a closer look at what the action slot actually does.

def action(self):
    self.pb.setRange(0, 0) # Un
    sleep(3) # <-- Your slot blocks HERE
    self.pb.setRange(0, 100)
    self.pb.setValue(100)
    QtGui.qApp.processEvents()

当您的插槽在 sleep 中被阻塞时,progressBar 没有理由更新其值.当 action 被调用时,槽线程会休眠 3 秒,然后将进度条设置为完整的 100.

There is no reason for your progressBar to update its value while your slot is blocked in sleep. When action is called, the slot thread sleeps for 3 sec then sets the progress bar to a full 100.

您不能指望progressBar 在您的任务运行时神奇地自我更新.如果您不知道需要多长时间并且无法按步骤细分它,您应该考虑使用 pulsed ProgressBar 代替(参见下面的示例 1).如果您可以轻松获取任务的进度(例如复制 n 个文件),则应相应地更新 progressBar 的值.

You can't expect the progressBar to magically update itself while your task is running. If you have no idea how long it will take and you can't subdivise it in steps, you should consider using a pulsed ProgressBar instead (see example 1 below). If you can easily get the progression of your task (say copying n files), you should update the value of your progressBar accordingly.

无论哪种方式,您都应该使用 QThread 来获得非阻塞行为,并使用 signals 在您的线程和主应用程序之间进行通信.

Either way, you should use QThread to get a non-blocking behaviour, and signals to communicate between your thread(s) and your main application.

  • 主应用程序启动执行长时间运行任务的 QThread.
  • QThread 通知主应用程序的任务进展(如果可用)或完成

示例 1 - Pulse ProgressBar:

如果最小值和最大值都设置为 0,进度条将显示忙指示符而不是步数百分比.

If minimum and maximum are both set to 0, the progress bar will show a busy indicator instead of a percentage of steps.

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)

        # Create a progress bar and a button and add them to the main layout
        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,1)
        layout.addWidget(self.progressBar)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(button)      

        button.clicked.connect(self.onStart)

        self.myLongTask = TaskThread()
        self.myLongTask.taskFinished.connect(self.onFinished)

    def onStart(self): 
        self.progressBar.setRange(0,0)
        self.myLongTask.start()

    def onFinished(self):
        # Stop the pulsation
        self.progressBar.setRange(0,1)


class TaskThread(QtCore.QThread):
    taskFinished = QtCore.pyqtSignal()
    def run(self):
        time.sleep(3)
        self.taskFinished.emit()  

示例 2 - 经典进度条:

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)       

        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,100)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(self.progressBar)
        layout.addWidget(button)

        button.clicked.connect(self.onStart)

        self.myLongTask = TaskThread()
        self.myLongTask.notifyProgress.connect(self.onProgress)


    def onStart(self):
        self.myLongTask.start()

    def onProgress(self, i):
        self.progressBar.setValue(i)


class TaskThread(QtCore.QThread):
    notifyProgress = QtCore.pyqtSignal(int)
    def run(self):
        for i in range(101):
            self.notifyProgress.emit(i)
            time.sleep(0.1)

这篇关于PyQt 进度条忙指示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆