python3+PyQt5实现自定义分数滑块部件

本文通过Python3+PyQt5实现自定义部件–分数滑块。它既能支持键盘也支持鼠标,使用物理(视口)坐标通过绘制方式显示。

#!/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_()

运行结果:

以上是 python3+PyQt5实现自定义分数滑块部件 的全部内容, 来源链接: utcz.com/z/353983.html

回到顶部