text: from PyQt5 import QtCore, QtGui, QtWidgets
  from PyQt5.QtCore import Qt
  
  
  class _Bar(QtWidgets.QWidget):
  
      clickedValue = QtCore.pyqtSignal(int)
  
      def __init__(self, steps, *args, **kwargs):
          super().__init__(*args, **kwargs)
  
          self.setSizePolicy(
              QtWidgets.QSizePolicy.MinimumExpanding,
              QtWidgets.QSizePolicy.MinimumExpanding
          )
  
          if isinstance(steps, list):
              # list of colours.
              self.n_steps = len(steps)
              self.steps = steps
  
          elif isinstance(steps, int):
              # int number of bars, defaults to red.
              self.n_steps = steps
              self.steps = ['red'] * steps
  
          else:
              raise TypeError('steps must be a list or int')
  
          self._bar_solid_percent = 0.8
          self._background_color = QtGui.QColor('black')
          self._padding = 4.0  # n-pixel gap around edge.
  
      def paintEvent(self, e):
          painter = QtGui.QPainter(self)
  
          brush = QtGui.QBrush()
          brush.setColor(self._background_color)
          brush.setStyle(Qt.SolidPattern)
          rect = QtCore.QRect(0, 0, painter.device().width(),
                              painter.device().height())
          painter.fillRect(rect, brush)
  
          # Get current state.
          parent = self.parent()
          vmin, vmax = parent.minimum(), parent.maximum()
          value = parent.value()
  
          # Define our canvas.
          d_height = painter.device().height() - (self._padding * 2)
          d_width = painter.device().width() - (self._padding * 2)
  
          # Draw the bars.
          step_size = d_height / self.n_steps
          bar_height = step_size * self._bar_solid_percent
          bar_spacer = step_size * (1 - self._bar_solid_percent) / 2
  
          # Calculate the y-stop position, from the value in range.
          pc = (value - vmin) / (vmax - vmin)
          n_steps_to_draw = int(pc * self.n_steps)
  
          for n in range(n_steps_to_draw):
              brush.setColor(QtGui.QColor(self.steps[n]))
              rect = QtCore.QRect(
                  self._padding,
                  self._padding + d_height - ((1 + n) * step_size) + bar_spacer,
                  d_width,
                  bar_height
              )
              painter.fillRect(rect, brush)
  
          painter.end()
  
      def sizeHint(self):
          return QtCore.QSize(40, 120)
  
      def _trigger_refresh(self):
          self.update()
  
      def _calculate_clicked_value(self, e):
          parent = self.parent()
          vmin, vmax = parent.minimum(), parent.maximum()
          d_height = self.size().height() + (self._padding * 2)
          step_size = d_height / self.n_steps
          click_y = e.y() - self._padding - step_size / 2
  
          pc = (d_height - click_y) / d_height
          value = vmin + pc * (vmax - vmin)
          self.clickedValue.emit(value)
  
      def mouseMoveEvent(self, e):
          self._calculate_clicked_value(e)
  
      def mousePressEvent(self, e):
          self._calculate_clicked_value(e)
  
  
  class PowerBar(QtWidgets.QWidget):
      """
      Custom Qt Widget to show a power bar and dial.
      Demonstrating compound and custom-drawn widget.
  
      Left-clicking the button shows the color-chooser, while
      right-clicking resets the color to None (no-color).
      """
  
      colorChanged = QtCore.pyqtSignal()
  
      def __init__(self, steps=5, *args, **kwargs):
          super().__init__(*args, **kwargs)
  
          layout = QtWidgets.QVBoxLayout()
          self._bar = _Bar(steps)
          layout.addWidget(self._bar)
  
          # Create the QDial widget and set up defaults.
          # - we provide accessors on this class to override.
          self._dial = QtWidgets.QDial()
          self._dial.setNotchesVisible(True)
          self._dial.setWrapping(False)
          self._dial.valueChanged.connect(self._bar._trigger_refresh)
  
          # Take feedback from click events on the meter.
          self._bar.clickedValue.connect(self._dial.setValue)
  
          layout.addWidget(self._dial)
          self.setLayout(layout)
  
      def __getattr__(self, name):
          if name in self.__dict__:
              return self[name]
  
          return getattr(self._dial, name)
  
      def setColor(self, color):
          self._bar.steps = [color] * self._bar.n_steps
          self._bar.update()
  
      def setColors(self, colors):
          self._bar.n_steps = len(colors)
          self._bar.steps = colors
          self._bar.update()
  
      def setBarPadding(self, i):
          self._bar._padding = int(i)
          self._bar.update()
  
      def setBarSolidPercent(self, f):
          self._bar._bar_solid_percent = float(f)
          self._bar.update()
  
      def setBackgroundColor(self, color):
          self._bar._background_color = QtGui.QColor(color)
          self._bar.update()
  
  
  if __name__ == "__main__":
      from PyQt5 import QtCore, QtGui, QtWidgets
  
      app = QtWidgets.QApplication([])
      volume = PowerBar(["#5e4fa2", "#3288bd", "#66c2a5", "#abdda4", "#e6f598", "#ffffbf", "#fee08b", "#fdae61", "#f46d43", "#d53e4f", "#9e0142"])
      volume.show()
      app.exec_()
  