Home  >  Article  >  Backend Development  >  python3+PyQt5 implements custom score slider component

python3+PyQt5 implements custom score slider component

不言
不言Original
2018-04-24 14:55:361910browse

This article mainly introduces python3 PyQt5 to implement custom score slider components in detail. It has certain reference value. Interested friends can refer to it.

This article implements customization through Python3 PyQt5 Widget – Score slider. It supports both keyboard and mouse and is displayed via drawing using physical (viewport) coordinates.

#!/usr/bin/env python3

import platform
from PyQt5.QtCore import (QPointF, QRectF, QSize, Qt,pyqtSignal)
from PyQt5.QtWidgets import (QApplication, QDialog,QSizePolicy,
     QGridLayout, QLCDNumber, QLabel,
    QSpinBox, QWidget)
from PyQt5.QtGui import QColor,QFont,QPainter,QFontMetricsF,QPalette, QPolygonF
X11 = True
try:
  from PyQt5.QtGui import qt_x11_wait_for_window_manager
except ImportError:
  X11 = False


class FractionSlider(QWidget):

  XMARGIN = 12.0
  YMARGIN = 5.0
  WSTRING = "999"
  valueChanged = pyqtSignal(int,int) 

  def __init__(self, numerator=0, denominator=10, parent=None):
    super(FractionSlider, self).__init__(parent)
    self.__numerator = numerator
    self.__denominator = denominator
    self.setFocusPolicy(Qt.WheelFocus)
    self.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding,
                    QSizePolicy.Fixed))


  def decimal(self):
    return self.__numerator / float(self.__denominator)


  def fraction(self):
    return self.__numerator, self.__denominator


  def sizeHint(self):
    return self.minimumSizeHint()


  def minimumSizeHint(self):
    font = QFont(self.font())
    font.setPointSize(font.pointSize() - 1)
    fm = QFontMetricsF(font)
    return QSize(fm.width(FractionSlider.WSTRING) *
           self.__denominator,
           (fm.height() * 4) + FractionSlider.YMARGIN)


  def setFraction(self, numerator, denominator=None):
    if denominator is not None:
      if 3 <= denominator <= 60:
        self.__denominator = denominator
      else:
        raise ValueError("denominator out of range")
    if 0 <= numerator <= self.__denominator:
      self.__numerator = numerator
    else:
      raise ValueError("numerator out of range")
    self.update()
    self.updateGeometry()


  def mousePressEvent(self, event):
    if event.button() == Qt.LeftButton:
      self.moveSlider(event.x())
      event.accept()
    else:
      QWidget.mousePressEvent(self, event)


  def mouseMoveEvent(self, event):
    self.moveSlider(event.x())


  def moveSlider(self, x):
    span = self.width() - (FractionSlider.XMARGIN * 2)
    offset = span - x + FractionSlider.XMARGIN
    numerator = int(round(self.__denominator *
            (1.0 - (offset / span))))
    numerator = max(0, min(numerator, self.__denominator))
    if numerator != self.__numerator:
      self.__numerator = numerator
      #self.emit(SIGNAL("valueChanged(int,int)"),
      #     self.__numerator, self.__denominator)
      self.valueChanged.emit(self.__numerator, self.__denominator)
      self.update()


  def keyPressEvent(self, event):
    change = 0
    if event.key() == Qt.Key_Home:
      change = -self.__denominator
    elif event.key() in (Qt.Key_Up, Qt.Key_Right):
      change = 1
    elif event.key() == Qt.Key_PageUp:
      change = (self.__denominator // 10) + 1
    elif event.key() in (Qt.Key_Down, Qt.Key_Left):
      change = -1
    elif event.key() == Qt.Key_PageDown:
      change = -((self.__denominator // 10) + 1)
    elif event.key() == Qt.Key_End:
      change = self.__denominator
    if change:
      numerator = self.__numerator
      numerator += change
      numerator = max(0, min(numerator, self.__denominator))
      if numerator != self.__numerator:
        self.__numerator = numerator
        #self.emit(SIGNAL("valueChanged(int,int)"),
        #     self.__numerator, self.__denominator)
        self.valueChanged.emit(self.__numerator, self.__denominator)
        self.update()
      event.accept()
    else:
      QWidget.keyPressEvent(self, event)


  def paintEvent(self, event=None):
    font = QFont(self.font())
    font.setPointSize(font.pointSize() - 1)
    fm = QFontMetricsF(font)
    fracWidth = fm.width(FractionSlider.WSTRING)
    indent = fm.boundingRect("9").width() / 2.0
    if not X11:
      fracWidth *= 1.5
    span = self.width() - (FractionSlider.XMARGIN * 2)
    value = self.__numerator / float(self.__denominator)
    painter = QPainter(self)
    painter.setRenderHint(QPainter.Antialiasing)
    painter.setRenderHint(QPainter.TextAntialiasing)
    painter.setPen(self.palette().color(QPalette.Mid))
    painter.setBrush(self.palette().brush(
        QPalette.AlternateBase))
    painter.drawRect(self.rect())
    segColor = QColor(Qt.green).darker(120)
    segLineColor = segColor.darker()
    painter.setPen(segLineColor)
    painter.setBrush(segColor)
    painter.drawRect(FractionSlider.XMARGIN,
             FractionSlider.YMARGIN, span, fm.height())
    textColor = self.palette().color(QPalette.Text)
    segWidth = span / self.__denominator
    segHeight = fm.height() * 2
    nRect = fm.boundingRect(FractionSlider.WSTRING)
    x = FractionSlider.XMARGIN
    yOffset = segHeight + fm.height()
    for i in range(self.__denominator + 1):
      painter.setPen(segLineColor)
      painter.drawLine(x, FractionSlider.YMARGIN, x, segHeight)
      painter.setPen(textColor)
      y = segHeight
      rect = QRectF(nRect)
      rect.moveCenter(QPointF(x, y + fm.height() / 2.0))
      #painter.drawText(rect, Qt.AlignCenter,
               #QString.number(i))
      painter.drawText(rect, Qt.AlignCenter,str(i))      
      y = yOffset
      rect.moveCenter(QPointF(x, y + fm.height() / 2.0))
      painter.drawText(rect, Qt.AlignCenter,
               str(self.__denominator))
      painter.drawLine(QPointF(rect.left() + indent, y),
               QPointF(rect.right() - indent, y))
      x += segWidth
    span = int(span)
    y = FractionSlider.YMARGIN - 0.5
    triangle = [QPointF(value * span, y),
          QPointF((value * span) +
              (2 * FractionSlider.XMARGIN), y),
          QPointF((value * span) +
              FractionSlider.XMARGIN, fm.height())]
    painter.setPen(Qt.yellow)
    painter.setBrush(Qt.darkYellow)
    painter.drawPolygon(QPolygonF(triangle))


if __name__ == "__main__":
  import sys

  app = QApplication(sys.argv)
  form = QDialog()
  sliderLabel = QLabel("&Fraction")
  slider = FractionSlider(denominator=12)
  sliderLabel.setBuddy(slider)
  denominatorLabel = QLabel("&Denominator")
  denominatorSpinBox = QSpinBox()
  denominatorLabel.setBuddy(denominatorSpinBox)
  denominatorSpinBox.setRange(3, 60)
  denominatorSpinBox.setValue(slider.fraction()[1])
  denominatorSpinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
  numeratorLabel = QLabel("Numerator")
  numeratorLCD = QLCDNumber()
  numeratorLCD.setSegmentStyle(QLCDNumber.Flat)
  layout = QGridLayout()
  layout.addWidget(sliderLabel, 0, 0)
  layout.addWidget(slider, 0, 1, 1, 5)
  layout.addWidget(numeratorLabel, 1, 0)
  layout.addWidget(numeratorLCD, 1, 1)
  layout.addWidget(denominatorLabel, 1, 2)
  layout.addWidget(denominatorSpinBox, 1, 3)
  form.setLayout(layout)

  def valueChanged(denominator):
    numerator = int(slider.decimal() * denominator)
    slider.setFraction(numerator, denominator)
    numeratorLCD.display(numerator)

  #form.connect(slider, SIGNAL("valueChanged(int,int)"),
         #numeratorLCD, SLOT("display(int)"))
  slider.valueChanged[int,int].connect(numeratorLCD.display)
  #form.connect(denominatorSpinBox, SIGNAL("valueChanged(int)"),
         #valueChanged)
  denominatorSpinBox.valueChanged[int].connect(valueChanged)
  form.setWindowTitle("Fraction Slider")
  form.show()
  app.exec_()

Run results:


##Related Recommended:

python3 PyQt5 implements custom fluid mixing widget

python3 PyQt5 uses database table view

python3 PyQt5 implements drag and drop function

The above is the detailed content of python3+PyQt5 implements custom score slider component. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn