Issue
Similar to this question, but for pyqt. I have an application that has two threads, one of which processes some data (time consuming), and the second thread that presents the results and asks for verification on the results. I want to show the number of objects processed in a progress bar. However, I also want to show the number of objects verified by user. Number processed will always be equal or greater than the number of objects verified (since you can't verify what hasn't been verified). In essence, it's kind of like the loading bar of a youtube video or something, showing a grey part that is "loaded" and red part that is "watched." Is this something that can be supported in pyqt? The documentation for QProgressBar does not seem to hint that there's any support. Using PyQt5 and Python 3.6.
It should look similar to this:
Here's a minimal viable code that has TWO separate progress bars, one for the number of objects processed and the other for the number verified, but I want them overlapped...
import sys
from PyQt5.QtWidgets import (QApplication, QDialog,
QProgressBar, QPushButton)
class Actions(QDialog):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.objectsToProcess = 100
self.objectsProcessed = 0
self.objectsVerified = 0
self.processProgress = QProgressBar(self)
self.processProgress.setGeometry(5, 5, 300, 25)
self.processProgress.setMaximum(self.objectsToProcess)
self.verifyProgress = QProgressBar(self)
self.verifyProgress.setGeometry(5, 35, 300, 25)
self.verifyProgress.setMaximum(self.objectsToProcess)
self.processButton = QPushButton('Process', self)
self.processButton.move(5, 75)
self.verifyButton = QPushButton('Verify', self)
self.verifyButton.move(90, 75)
self.show()
self.processButton.clicked.connect(self.process)
self.verifyButton.clicked.connect(self.verify)
def process(self):
if self.objectsProcessed + 1 < self.objectsToProcess:
self.objectsProcessed += 1
self.processProgress.setValue(self.objectsProcessed)
def verify(self):
if self.objectsVerified < self.objectsProcessed:
self.objectsVerified += 1
self.verifyProgress.setValue(self.objectsVerified)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Actions()
sys.exit(app.exec_())
Result from above code:
Solution
A possible solution is to create a new attribute in QProgressBar that shows the alternative advance, and to do the painting we can use a QProxyStyle:
from PyQt5 import QtCore, QtGui, QtWidgets
class ProxyStyle(QtWidgets.QProxyStyle):
def drawControl(self, element, option, painter, widget):
if element == QtWidgets.QStyle.CE_ProgressBar:
super(ProxyStyle, self).drawControl(element, option, painter, widget)
if hasattr(option, 'alternative'):
alternative = option.alternative
last_value = option.progress
last_pal = option.palette
last_rect = option.rect
option.progress = alternative
pal = QtGui.QPalette()
# alternative color
pal.setColor(QtGui.QPalette.Highlight, QtCore.Qt.red)
option.palette = pal
option.rect = self.subElementRect(QtWidgets.QStyle.SE_ProgressBarContents, option, widget)
self.proxy().drawControl(QtWidgets.QStyle.CE_ProgressBarContents, option, painter, widget)
option.progress = last_value
option.palette = last_pal
option.rect = last_rect
return
super(ProxyStyle, self).drawControl(element, option, painter, widget)
class ProgressBar(QtWidgets.QProgressBar):
def paintEvent(self, event):
painter = QtWidgets.QStylePainter(self)
opt = QtWidgets.QStyleOptionProgressBar()
if hasattr(self, 'alternative'):
opt.alternative = self.alternative()
self.initStyleOption(opt)
painter.drawControl(QtWidgets.QStyle.CE_ProgressBar, opt)
@QtCore.pyqtSlot(int)
def setAlternative(self, value):
self._alternative = value
self.update()
def alternative(self):
if not hasattr(self, '_alternative'):
self._alternative = 0
return self._alternative
class Actions(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.objectsToProcess = 100
self.objectsProcessed = 0
self.objectsVerified = 0
self.progress_bar = ProgressBar(maximum=self.objectsToProcess)
self.process_btn = QtWidgets.QPushButton('Process')
self.verify_btn = QtWidgets.QPushButton('Verify')
self.process_btn.clicked.connect(self.process)
self.verify_btn.clicked.connect(self.verify)
lay = QtWidgets.QGridLayout(self)
lay.addWidget(self.progress_bar, 0, 0, 1, 2)
lay.addWidget(self.process_btn, 1, 0)
lay.addWidget(self.verify_btn, 1, 1)
def process(self):
if self.objectsProcessed + 1 < self.objectsToProcess:
self.objectsProcessed += 1
self.progress_bar.setValue(self.objectsProcessed)
def verify(self):
if self.objectsVerified < self.objectsProcessed:
self.objectsVerified += 1
self.progress_bar.setAlternative(self.objectsVerified)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle(ProxyStyle(app.style()))
w = Actions()
w.show()
sys.exit(app.exec_())
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.