Pyqt поддерживает сложенный индикатор выполнения с двумя значениями? - PullRequest
2 голосов
/ 29 марта 2019

Похоже на этот вопрос , но для pyqt.У меня есть приложение, которое имеет два потока, один из которых обрабатывает некоторые данные (отнимает много времени), а второй поток представляет результаты и запрашивает подтверждение результатов.Я хочу показать количество объектов, обработанных в индикаторе выполнения.Тем не менее, я также хочу показать количество объектов, проверенных пользователем.Обработанное число всегда будет равно или больше количества проверенных объектов (поскольку вы не можете проверить, что не было проверено).По сути, это что-то вроде полосы загрузки видео на YouTube или чего-то еще, показывая серую часть, которая «загружена», и красную часть, которая «просматривается».Это то, что может быть поддержано в pyqt?Документация для QProgressBar , похоже, не намекает на какую-либо поддержку.Использование PyQt5 и Python 3.6.

Это должно выглядеть примерно так: multi progress bar

Вот минимальный жизнеспособный код, который имеет ДВА отдельных индикатора выполнения, один для числаобработанных объектов и других для проверенного числа, но я хочу, чтобы они перекрывались ...

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_())

Результат сверху кода:

enter image description here

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Возможным решением является создание нового атрибута в QProgressBar, который показывает альтернативное продвижение, и для рисования мы можем использовать 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_())

enter image description here

0 голосов
/ 02 апреля 2019

Спасибо за @eyllanesc за надежное решение.Я решил использовать более легкое (по общему признанию хакерское) решение, состоящее в том, чтобы перекрывать два индикатора выполнения и сделать верхнюю панель немного прозрачной, используя QGraphicsOpacityEffect.

    # Opaque prog bar
    self.verifyProgress = QProgressBar(self)
    self.verifyProgress.setGeometry(5, 5, 300, 25)
    self.verifyProgress.setMaximum(self.objectsToProcess)
    self.verifyProgress.setFormat('%p% /                 ')
    self.verifyProgress.setAlignment(Qt.AlignCenter)

    # Must set the transparent prog bar second to overlay on top of opaque prog bar
    self.processProgress = QProgressBar(self)
    self.processProgress.setGeometry(5, 5, 300, 25)
    self.processProgress.setMaximum(self.objectsToProcess)
    self.processProgress.setFormat('   %p%')
    self.processProgress.setAlignment(Qt.AlignCenter)
    op = QGraphicsOpacityEffect(self.processProgress)
    op.setOpacity(0.5)
    self.processProgress.setGraphicsEffect(op)

Результат:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...