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


Posted in Python onApril 24, 2018

本文通过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实现自定义分数滑块部件

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python部署web开发程序的几种方法
May 05 Python
Python数据分析之双色球统计单个红和蓝球哪个比例高的方法
Feb 03 Python
windows下安装python的C扩展编译环境(解决Unable to find vcvarsall.bat)
Feb 21 Python
解决Python plt.savefig 保存图片时一片空白的问题
Jan 10 Python
解决Python设置函数调用超时,进程卡住的问题
Aug 08 Python
Python 分发包中添加额外文件的方法
Aug 16 Python
Python turtle库绘制菱形的3种方式小结
Nov 23 Python
Python数据可视化:顶级绘图库plotly详解
Dec 07 Python
Python+OpenCV 实现图片无损旋转90°且无黑边
Dec 12 Python
python实现指定ip端口扫描方式
Dec 17 Python
tensorflow的计算图总结
Jan 12 Python
Python3 socket即时通讯脚本实现代码实例(threading多线程)
Jun 01 Python
详解tensorflow载入数据的三种方式
Apr 24 #Python
关于Tensorflow中的tf.train.batch函数的使用
Apr 24 #Python
TensorFlow入门使用 tf.train.Saver()保存模型
Apr 24 #Python
Python使用 Beanstalkd 做异步任务处理的方法
Apr 24 #Python
Windows上使用Python增加或删除权限的方法
Apr 24 #Python
python编写暴力破解zip文档程序的实例讲解
Apr 24 #Python
解决python删除文件的权限错误问题
Apr 24 #Python
You might like
这部好评如潮的动漫 知名梗频出 但是画风劝退很多人
2020/03/08 日漫
咖啡知识 除了喝咖啡还有那些知识点
2021/03/06 新手入门
PHP实现将科学计数法转换为原始数字字符串的方法
2014/12/16 PHP
php创建桌面快捷方式实现方法
2015/12/31 PHP
php无法连接mysql数据库的正确解决方法
2016/07/01 PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
2016/09/23 PHP
Smarty模板语法详解
2019/07/20 PHP
laravel 解决后端无法获取到前端Post过来的值问题
2019/10/22 PHP
jQuery Tools Dateinput使用介绍
2012/07/14 Javascript
简洁Ajax函数处理(示例代码)
2013/11/15 Javascript
JS window对象的top、parent、opener含义介绍
2013/12/03 Javascript
JS父页面与子页面相互传值方法
2014/03/05 Javascript
JavaScript中读取和保存文件实例
2014/05/08 Javascript
JavaScript对象学习小结
2015/09/02 Javascript
jquery validate表单验证的基本用法入门
2016/01/18 Javascript
JavaScript基于DOM操作实现简单的数学运算功能示例
2017/01/16 Javascript
利用Jquery实现几款漂亮实用的时间轴(附示例代码)
2017/02/15 Javascript
vue中改变滚动条样式的方法
2020/03/03 Javascript
对Python3 * 和 ** 运算符详解
2019/02/16 Python
OpenCV HSV颜色识别及HSV基本颜色分量范围
2019/03/22 Python
Python3日期与时间戳转换的几种方法详解
2019/06/04 Python
Python使用Slider组件实现调整曲线参数功能示例
2019/09/06 Python
Python restful框架接口开发实现
2020/04/13 Python
详解numpy.ndarray.reshape()函数的参数问题
2020/10/13 Python
二年级小学生评语
2014/04/21 职场文书
省级优秀毕业生主要事迹
2014/05/29 职场文书
任命书模板
2014/06/04 职场文书
教师三严三实对照检查材料
2014/09/25 职场文书
2014年安全保卫工作总结
2014/11/13 职场文书
2015年清明节网上祭英烈留言寄语
2015/03/04 职场文书
总经理岗位职责范本
2015/04/01 职场文书
报案材料怎么写
2015/05/25 职场文书
消防宣传标语大全
2015/08/03 职场文书
公司保密管理制度
2015/08/04 职场文书
学习杨善洲同志先进事迹心得体会
2016/01/23 职场文书
Python 的 sum() Pythonic 的求和方法详细
2021/10/16 Python