时间:2021-07-01 10:21:17 帮助过:54人阅读
本文通过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实现自定义流体混合窗口部件
python3+PyQt5使用数据库表视图
python3+PyQt5实现拖放功能
以上就是python3+PyQt5实现自定义分数滑块部件的详细内容,更多请关注Gxl网其它相关文章!