Search code examples
pythonpysideqprogressbar

Paint ticks on custom QProgressBar in Pyside


I'm trying to paint some ticks in my custom progressbar but I'm not clear on why the line isn't showing up at all?

enter image description here

import sys
import os

sys.path.append('Z:\\pipeline\\site-packages')
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from PySide import QtGui, QtCore

class QProgressBarPro(QtGui.QProgressBar):

    progressClicked = QtCore.Signal()
    progressChanging = QtCore.Signal()
    progressChanged = QtCore.Signal()

    def __init__(self, parent=None):
        super(QProgressBarPro, self).__init__(parent)
        self.default_value = 50.0
        self.lmb_pressed = False
        self.setFormat('%p')
        self.setRange(0.0, 100.0)
        self.stepEnabled = True
        self.step = 5
        self.setToolTip('<strong>Press+Hold+Ctrl</strong> for percise values<br><strong>Right-Click</strong> to reset default value')

    def step_round(self, x, base=5):
        return int(base * round(float(x)/base))

    def set_value_from_cursor(self, xpos):
        width = self.frameGeometry().width()
        percent = float(xpos) / width
        val = self.maximum() * percent

        if self.stepEnabled:
            modifiers = QtGui.QApplication.keyboardModifiers()
            if modifiers != QtCore.Qt.ControlModifier:
                val = self.step_round(val, self.step)

        self.setValue(val)

    def mousePressEvent(self, event):
        self.progressClicked.emit()
        mouse_button = event.button()

        if mouse_button == QtCore.Qt.RightButton:
            self.setValue(self.default_value)
        else:
            xpos = event.pos().x()
            self.set_value_from_cursor(xpos)
            self.lmb_pressed = True
        self.progressChanging.emit()

    def mouseReleaseEvent(self, event):
        self.lmb_pressed = False
        self.progressChanged.emit()

    def mouseMoveEvent(self, event):
        if self.lmb_pressed:
            xpos = event.pos().x()
            self.set_value_from_cursor(xpos)
            self.progressChanging.emit()

    def paintEvent(self, event):
        painter = QtGui.QPainter()
        painter.drawLine(10, 0, 10, 10)
        QtGui.QProgressBar.paintEvent(self, event)


# DEMO
class Example(QtGui.QWidget):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):

        self.ui_progress = QProgressBarPro()
        self.ui_progress.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.ui_progress.setValue(10)

        gdl = QtGui.QVBoxLayout()
        gdl.addWidget(self.ui_progress)
        self.setLayout(gdl)

        self.resize(300, 300)
        self.setWindowTitle('Tooltips')    
        self.show()

def main():

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Solution

  • You need to change your paintEvent function.

    I wrote a first approach that provides same result as in your image:

    def paintEvent(self, event):
        QtGui.QProgressBar.paintEvent(self, event)
        painter = QtGui.QPainter(self)
        brush = QtGui.QBrush(QtCore.Qt.SolidPattern)
        # Set gray color
        brush.setColor(QtGui.QColor(204,204,204))
        painter.setPen(QtGui.QPen(brush, 2, QtCore.Qt.SolidLine,QtCore.Qt.RoundCap))
        #print(str(self.width())+","+str(self.height()))
        progressbarwidth = self.width()
        progressbarheight = self.height()
        ## Drawing one vertical line each 1/5
        painter.drawLine(progressbarwidth*1/5, 0, progressbarwidth*1/5, progressbarheight)
        painter.drawLine(progressbarwidth*2/5, 0, progressbarwidth*2/5, progressbarheight)
        painter.drawLine(progressbarwidth*3/5, 0, progressbarwidth*3/5, progressbarheight)
        painter.drawLine(progressbarwidth*4/5, 0, progressbarwidth*4/5, progressbarheight)
    

    The achieved outcome is shown here.