任何PyQt循环进度条?

时间:2015-11-06 23:17:04

标签: python pyqt

有人知道如何在PyQt上实现循环进度条吗?

另外,我找到了一个现有的代码: http://sourceforge.net/projects/qroundprogressbar/

但是,它在C ++中的表现如何。如何将它用于PyQt?

更新:使用下面的QRoundProgressBar实现,我创建了一个带有开始按钮的完整演示应用程序来演示QRoundProgressBar。 将QRoundProgressBar保存在circularprogressbar.py中,并在下面代码的同一目录中创建一个新文件。希望它能帮助别人。

from circularprogressbar import QRoundProgressBar
import sys
from PyQt4.QtGui import *
from PyQt4 import QtCore, QtGui, Qt
from time import sleep


class TstWidget(QtGui.QWidget):
    def __init__(self):
        super(type(self), self).__init__()

        self.bar = QRoundProgressBar()
        self.bar.setFixedSize(300, 300)

        self.bar.setDataPenWidth(3)
        self.bar.setOutlinePenWidth(3)
        self.bar.setDecimals(1)
        self.bar.setFormat('%v | %p %')
        # self.bar.resetFormat()
        self.bar.setNullPosition(90)
        self.bar.setBarStyle(QRoundProgressBar.StyleDonut)
        self.bar.setDataColors([(0., QtGui.QColor.fromRgb(255,0,0)), (0.5, QtGui.QColor.fromRgb(255,255,0)), (1., QtGui.QColor.fromRgb(0,255,0))])
        self.bar.setMaximun(100)
        self.bar.setMinimun(0)
        self.bar.setRange(0, 100)
        self.bar.setValue(0)

        button = QtGui.QPushButton("Start", self)

        button.clicked.connect(self.on_start)

        lay = QtGui.QVBoxLayout()
        lay.addWidget(button)
        lay.addWidget(self.bar)
        self.setLayout(lay)

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

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

    def on_progress(self, i):
        self.bar.setValue(i)


class TaskThread(QtCore.QThread):
   notifyProgress = QtCore.pyqtSignal(int)

   def run(self):
       for i in range(101):
           self.notifyProgress.emit(i)
           sleep(0.1)


def main():

    app = QtGui.QApplication(sys.argv)
    ex = TstWidget()
    ex.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

enter image description here

3 个答案:

答案 0 :(得分:4)

我已经在PyQt上移植了QRoundProgressBar(并修复了一些小错误):

from PyQt4 import QtCore, QtGui, Qt

class QRoundProgressBar(QtGui.QWidget):

    StyleDonut = 1
    StylePie = 2
    StyleLine = 3

    PositionLeft = 180
    PositionTop = 90
    PositionRight = 0
    PositionBottom = -90

    UF_VALUE = 1
    UF_PERCENT = 2
    UF_MAX = 4

    def __init__(self):
        super().__init__()
        self.min = 0
        self.max = 100
        self.value = 25

        self.nullPosition = self.PositionTop
        self.barStyle = self.StyleDonut
        self.outlinePenWidth =1
        self.dataPenWidth = 1
        self.rebuildBrush = False
        self.format = "%p%"
        self.decimals = 1
        self.updateFlags = self.UF_PERCENT
        self.gradientData = []
        self.donutThicknessRatio = 0.75

    def setRange(self, min, max):
        self.min = min
        self.max = max

        if self.max < self.min:
            self.max, self.min = self.min, self.max

        if self.value < self.min:
            self.value = self.min
        elif self.value > self.max:
            self.value = self.max

        if not self.gradientData:
            self.rebuildBrush = True
        self.update()

    def setMinimun(self, min):
        self.setRange(min, self.max)

    def setMaximun(self, max):
        self.setRange(self.min, max)

    def setValue(self, val):
        if self.value != val:
            if val < self.min:
                self.value = self.min
            elif val > self.max:
                self.value = self.max
            else:
                self.value = val
            self.update()

    def setNullPosition(self, position):
        if position != self.nullPosition:
            self.nullPosition = position
            if not self.gradientData:
                self.rebuildBrush = True
            self.update()

    def setBarStyle(self, style):
        if style != self.barStyle:
            self.barStyle = style
            self.update()

    def setOutlinePenWidth(self, penWidth):
        if penWidth != self.outlinePenWidth:
            self.outlinePenWidth = penWidth
            self.update()

    def setDataPenWidth(self, penWidth):
        if penWidth != self.dataPenWidth:
            self.dataPenWidth = penWidth
            self.update()

    def setDataColors(self, stopPoints):
        if stopPoints != self.gradientData:
            self.gradientData = stopPoints
            self.rebuildBrush = True
            self.update()

    def setFormat(self, format):
        if format != self.format:
            self.format = format
            self.valueFormatChanged()

    def resetFormat(self):
        self.format = ''
        self.valueFormatChanged()

    def setDecimals(self, count):
        if count >= 0 and count != self.decimals:
            self.decimals = count
            self.valueFormatChanged()

    def setDonutThicknessRatio(self, val):
        self.donutThicknessRatio = max(0., min(val, 1.))
        self.update()

    def paintEvent(self, event):
        outerRadius = min(self.width(), self.height())
        baseRect = QtCore.QRectF(1, 1, outerRadius-2, outerRadius-2)

        buffer = QtGui.QImage(outerRadius, outerRadius, QtGui.QImage.Format_ARGB32)
        buffer.fill(0)

        p = QtGui.QPainter(buffer)
        p.setRenderHint(QtGui.QPainter.Antialiasing)

        # data brush
        self.rebuildDataBrushIfNeeded()

        # background
        self.drawBackground(p, buffer.rect())

        # base circle
        self.drawBase(p, baseRect)

        # data circle
        arcStep = 360.0 / (self.max - self.min) * self.value
        self.drawValue(p, baseRect, self.value, arcStep)

        # center circle
        innerRect, innerRadius = self.calculateInnerRect(baseRect, outerRadius)
        self.drawInnerBackground(p, innerRect)

        # text
        self.drawText(p, innerRect, innerRadius, self.value)

        # finally draw the bar
        p.end()

        painter = QtGui.QPainter(self)
        painter.drawImage(0, 0, buffer)

    def drawBackground(self, p, baseRect):
        p.fillRect(baseRect, self.palette().background())

    def drawBase(self, p, baseRect):
        bs = self.barStyle
        if bs == self.StyleDonut:
            p.setPen(QtGui.QPen(self.palette().shadow().color(), self.outlinePenWidth))
            p.setBrush(self.palette().base())
            p.drawEllipse(baseRect)
        elif bs == self.StylePie:
            p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth))
            p.setBrush(self.palette().base())
            p.drawEllipse(baseRect)
        elif bs == self.StyleLine:
            p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth))
            p.setBrush(Qt.Qt.NoBrush)
            p.drawEllipse(baseRect.adjusted(self.outlinePenWidth/2, self.outlinePenWidth/2, -self.outlinePenWidth/2, -self.outlinePenWidth/2))

    def drawValue(self, p, baseRect, value, arcLength):
        # nothing to draw
        if value == self.min:
            return

        # for Line style
        if self.barStyle == self.StyleLine:
            p.setPen(QtGui.QPen(self.palette().highlight().color(), self.dataPenWidth))
            p.setBrush(Qt.Qt.NoBrush)
            p.drawArc(baseRect.adjusted(self.outlinePenWidth/2, self.outlinePenWidth/2, -self.outlinePenWidth/2, -self.outlinePenWidth/2),
                      self.nullPosition * 16,
                      -arcLength * 16)
            return

        # for Pie and Donut styles
        dataPath = QtGui.QPainterPath()
        dataPath.setFillRule(Qt.Qt.WindingFill)

        # pie segment outer
        dataPath.moveTo(baseRect.center())
        dataPath.arcTo(baseRect, self.nullPosition, -arcLength)
        dataPath.lineTo(baseRect.center())

        p.setBrush(self.palette().highlight())
        p.setPen(QtGui.QPen(self.palette().shadow().color(), self.dataPenWidth))
        p.drawPath(dataPath)

    def calculateInnerRect(self, baseRect, outerRadius):
        # for Line style
        if self.barStyle == self.StyleLine:
            innerRadius = outerRadius - self.outlinePenWidth
        else:    # for Pie and Donut styles
            innerRadius = outerRadius * self.donutThicknessRatio

        delta = (outerRadius - innerRadius) / 2.
        innerRect = QtCore.QRectF(delta, delta, innerRadius, innerRadius)
        return innerRect, innerRadius

    def drawInnerBackground(self, p, innerRect):
        if self.barStyle == self.StyleDonut:
            p.setBrush(self.palette().alternateBase())

            cmod = p.compositionMode()
            p.setCompositionMode(QtGui.QPainter.CompositionMode_Source)

            p.drawEllipse(innerRect)

            p.setCompositionMode(cmod)

    def drawText(self, p, innerRect, innerRadius, value):
        if not self.format:
            return

        text = self.valueToText(value)

        # !!! to revise
        f = self.font()
        # f.setPixelSize(innerRadius * max(0.05, (0.35 - self.decimals * 0.08)))
        f.setPixelSize(innerRadius * 1.8 / len(text))
        p.setFont(f)

        textRect = innerRect
        p.setPen(self.palette().text().color())
        p.drawText(textRect, Qt.Qt.AlignCenter, text)

    def valueToText(self, value):
        textToDraw = self.format

        format_string = '{' + ':.{}f'.format(self.decimals) + '}'

        if self.updateFlags & self.UF_VALUE:
            textToDraw = textToDraw.replace("%v", format_string.format(value))

        if self.updateFlags & self.UF_PERCENT:
            percent = (value - self.min) / (self.max - self.min) * 100.0
            textToDraw = textToDraw.replace("%p", format_string.format(percent))

        if self.updateFlags & self.UF_MAX:
            m = self.max - self.min + 1
            textToDraw = textToDraw.replace("%m", format_string.format(m))

        return textToDraw

    def valueFormatChanged(self):
        self.updateFlags = 0;

        if "%v" in self.format:
            self.updateFlags |= self.UF_VALUE

        if "%p" in self.format:
            self.updateFlags |= self.UF_PERCENT

        if "%m" in self.format:
            self.updateFlags |= self.UF_MAX

        self.update()

    def rebuildDataBrushIfNeeded(self):
        if self.rebuildBrush:
            self.rebuildBrush = False

            dataBrush = QtGui.QConicalGradient()
            dataBrush.setCenter(0.5,0.5)
            dataBrush.setCoordinateMode(QtGui.QGradient.StretchToDeviceMode)

            for pos, color in self.gradientData:
                dataBrush.setColorAt(1.0 - pos, color)

            # angle
            dataBrush.setAngle(self.nullPosition)

            p = self.palette()
            p.setBrush(QtGui.QPalette.Highlight, dataBrush)
            self.setPalette(p)

用法示例:

class TstWidget(QtGui.QWidget):
    def __init__(self):
        super(type(self), self).__init__()

        self.bar = QRoundProgressBar()
        self.bar.setFixedSize(300, 300)

        self.bar.setDataPenWidth(3)
        self.bar.setOutlinePenWidth(3)
        self.bar.setDonutThicknessRatio(0.85)
        self.bar.setDecimals(1)
        self.bar.setFormat('%v | %p %')
        # self.bar.resetFormat()
        self.bar.setNullPosition(90)
        self.bar.setBarStyle(QRoundProgressBar.StyleDonut)
        self.bar.setDataColors([(0., QtGui.QColor.fromRgb(255,0,0)), (0.5, QtGui.QColor.fromRgb(255,255,0)), (1., QtGui.QColor.fromRgb(0,255,0))])

        self.bar.setRange(0, 300)
        self.bar.setValue(260)

        lay = QtGui.QVBoxLayout()
        lay.addWidget(self.bar)
        self.setLayout(lay)

答案 1 :(得分:0)

@Alexandro,谢谢您的代码。效果很好。

我发现最好将最小值和最大值设置为float而不是int

self.min = 0.
self.max = 100.
self.value = 25.

否则,由于整数除法,如果valueToText()的输入值也是整数,则在python3中值将无法正确更新

答案 2 :(得分:-2)

我写了这个

class RoundProgress(QProgressBar):
def __init__(self,parent):
    QProgressBar.__init__(self)
    self.values = self.value()
    self.values = (self.values*360)/100
    self.parent = parent
    self.setParent(parent)
    self.n = self.value()
    self.label = QLabel("<center>100%<center>")
    self.label.setStyleSheet("color:red;")
    self.label.setFont(QFont("courrier",math.sqrt(self.width())))
    self.v = QVBoxLayout(self)
    self.setLayout(self.v)
    self.v.addWidget(self.label)
def setValue(self,n):
    self.n = n
    self.values = ((n*5650)/100)*(-1)
    self.label.setText("<center>"+str(self.n)+"</center>")
def setNvalue(self,n):
    self.n = n
    self.values = ((n*5650)/100)*(-1)
    self.label.setText("<center>"+str(self.n)+"</center>")
def paintEvent(self,event):
    painter = QPainter(self)
    painter.setRenderHint(QPainter.Antialiasing)
    pen = QPen()
    pen.setWidth(2)
    pen.setColor(QColor("darkblue"))
    painter.setPen(pen)
    pen = QPen()
    pen.setWidth(9)
    pen.setColor(QColor("lightgrey"))
    painter.setPen(pen)
    painter.drawArc(5.1,5.1,self.width()-10,self.height()-10,1450,-5650)
    #painter.drawEllipse(0,0,100,100)
    painter.setBrush(QColor("lightblue"))
    pen = QPen()
    pen.setWidth(10)
    pen.setColor(QColor("red"))
    painter.setPen(pen)
    painter.drawArc(5.1,5.1,self.width()-10,self.height()-10,1450,self.values)
    self.update()