本文介绍了任何 PyQt 圆形进度条?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
有人知道如何在 PyQt 上实现循环进度条吗?
另外,我发现了一个现有的代码:
解决方案
我已经在 PyQt 上移植了 QRoundProgressBar(并修复了一些小错误):
from PyQt4 import QtCore, QtGui, Qt类 QroundProgressBar(QtGui.QWidget):样式甜甜圈 = 1样式饼 = 2样式线 = 3位置左 = 180位置顶部 = 90位置右 = 0位置底部 = -90UF_VALUE = 1UF_PERCENT = 2UF_MAX = 4def __init__(self):super().__init__()self.min = 0self.max = 100自我价值 = 25self.nullPosition = self.PositionTopself.barStyle = self.StyleDonutself.outlinePenWidth =1self.dataPenWidth = 1self.rebuildBrush = Falseself.format = "%p%"self.decimals = 1self.updateFlags = self.UF_PERCENTself.gradientData = []self.donutThicknessRatio = 0.75def setRange(self, min, max):self.min = minself.max = 最大值如果 self.max self.max:self.value = self.max别的:self.value = val自我更新()def setNullPosition(self, position):如果位置 != self.nullPosition:self.nullPosition = 位置如果不是 self.gradientData:self.rebuildBrush = True自我更新()def setBarStyle(self, style):如果样式 != self.barStyle:self.barStyle = 样式自我更新()def setOutlinePenWidth(self, penWidth):如果 penWidth != self.outlinePenWidth:self.outlinePenWidth = penWidth自我更新()def setDataPenWidth(self, penWidth):如果 penWidth != self.dataPenWidth:self.dataPenWidth = penWidth自我更新()def setDataColors(self, stopPoints):如果 stopPoints != self.gradientData:self.gradientData = stopPointsself.rebuildBrush = True自我更新()def setFormat(self, format):如果格式 != self.format:self.format = 格式self.valueFormatChanged()def resetFormat(self):self.format = ''self.valueFormatChanged()def setDecimals(self, count):如果 count >= 0 并且 count != self.decimals:self.decimals = 计数self.valueFormatChanged()def setDonutThicknessRatio(self, val):self.donutThicknessRatio = max(0., min(val, 1.))自我更新()defpaintEvent(self, event):外半径 = min(self.width(), self.height())baseRect = QtCore.QRectF(1, 1,outerRadius-2,outerRadius-2)缓冲区 = QtGui.QImage(outerRadius,outerRadius,QtGui.QImage.Format_ARGB32)缓冲区填充(0)p = QtGui.QPainter(缓冲区)p.setRenderHint(QtGui.QPainter.Antialiasing)# 数据刷self.rebuildDataBrushIfNeeded()# 背景self.drawBackground(p, buffer.rect())# 基圆self.drawBase(p, baseRect)#数据圈arcStep = 360.0/(self.max - self.min) * self.valueself.drawValue(p, baseRect, self.value, arcStep)# 中心圆innerRect,innerRadius = self.calculateInnerRect(baseRect, outerRadius)self.drawInnerBackground(p,innerRect)# 文本self.drawText(p,innerRect,innerRadius,self.value)# 最后绘制条形图p.end()画家 = QtGui.QPainter(self)Painter.drawImage(0, 0, 缓冲区)def drawBackground(self, p, baseRect):p.fillRect(baseRect, self.palette().background())def drawBase(self, p, baseRect):bs = self.barStyle如果 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):# 没什么可画的如果值 == self.min:返回# 用于线条样式如果 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,-弧长 * 16)返回# 用于 Pie 和 Donut 样式dataPath = QtGui.QPainterPath()dataPath.setFillRule(Qt.Qt.WindingFill)# 饼段外层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):# 用于线条样式如果 self.barStyle == self.StyleLine:内半径 = 外半径 - self.outlinePenWidthelse: # 用于 Pie 和 Donut 样式内半径 = 外半径 * self.donutThicknessRatiodelta = (outerRadius -innerRadius)/2.innerRect = QtCore.QRectF(delta, delta,innerRadius,innerRadius)返回innerRect,innerRadiusdef drawInnerBackground(self, p,innerRect):如果 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):如果不是 self.format:返回text = self.valueToText(value)#!!!修正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 = 内部矩形p.setPen(self.palette().text().color())p.drawText(textRect, Qt.Qt.AlignCenter, text)def valueToText(self, value):textToDraw = self.formatformat_string = '{' + ':.{}f'.format(self.decimals) + '}'如果 self.updateFlags &self.UF_VALUE:textToDraw = textToDraw.replace("%v", format_string.format(value))if self.updateFlags &self.UF_PERCENT:百分比 = (值 - self.min)/(self.max - self.min) * 100.0textToDraw = textToDraw.replace("%p", format_string.format(percent))if self.updateFlags &self.UF_MAX:m = self.max - self.min + 1textToDraw = textToDraw.replace("%m", format_string.format(m))返回 textToDrawdef valueFormatChanged(self):self.updateFlags = 0;如果 self.format 中的%v":self.updateFlags |= self.UF_VALUE如果 self.format 中的%p":self.updateFlags |= self.UF_PERCENT如果 self.format 中的%m":self.updateFlags |= self.UF_MAX自我更新()def rebuildDataBrushIfNeeded(self):如果 self.rebuildBrush:self.rebuildBrush = FalsedataBrush = QtGui.QConicalGradient()dataBrush.setCenter(0.5,0.5)dataBrush.setCoordinateMode(QtGui.QGradient.StretchToDeviceMode)对于 pos,self.gradientData 中的颜色:dataBrush.setColorAt(1.0 - 位置,颜色)# 角度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)躺 = QtGui.QVBoxLayout()lay.addWidget(self.bar)self.setLayout(lay)
Does anybody know how I can implement circular progress bar on PyQt?
Also, I found an existing code:http://sourceforge.net/projects/qroundprogressbar/
But, how it is in C++. How to use it for PyQt?
UPDATE: Using implementation of QRoundProgressBar below, I created a complete demo application with start button to demonstrate the QRoundProgressBar.Save the QRoundProgressBar in circularprogressbar.py and create a new file in the same directory for the code below. Hope it helps others.
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()
解决方案
I have ported QRoundProgressBar on PyQt (and fixed some minor bugs):
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)
Usage example:
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)
这篇关于任何 PyQt 圆形进度条?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!