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之集成开发环境(IDE)
Sep 12 Python
python结合API实现即时天气信息
Jan 19 Python
Python的“二维”字典 (two-dimension dictionary)定义与实现方法
Apr 27 Python
Python 获取当前所在目录的方法详解
Aug 02 Python
在Python web中实现验证码图片代码分享
Nov 09 Python
python实现决策树分类算法
Dec 21 Python
python实现csv格式文件转为asc格式文件的方法
Mar 23 Python
python使用phoenixdb操作hbase的方法示例
Feb 28 Python
python打印异常信息的两种实现方式
Dec 24 Python
python实现PCA降维的示例详解
Feb 24 Python
了解一下python内建模块collections
Sep 07 Python
Django Paginator分页器的使用示例
Jun 23 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
PHP程序61条面向对象分析设计的经验小结
2008/11/12 PHP
浅谈PDO的rowCount函数
2015/06/18 PHP
php实现json编码的方法
2015/07/30 PHP
详解PHP原生DOM对象操作XML的方法
2016/10/17 PHP
JavaScript高级程序设计 阅读笔记(七) ECMAScript中的语句
2012/02/27 Javascript
JavaScript获取function所有参数名的方法
2015/10/30 Javascript
Bootstrap轮播插件简单使用方法介绍
2016/06/21 Javascript
关于页面刷新vuex数据消失问题解决方案
2017/07/03 Javascript
javascript流程控制语句集合
2017/09/18 Javascript
简述vue中的config配置
2018/01/23 Javascript
微信小程序云开发之云函数详解
2019/05/16 Javascript
微信小程序开发中var that =this的用法详解
2020/01/18 Javascript
[01:34]传奇从这开始 2016国际邀请赛中国区预选赛震撼开启
2016/06/26 DOTA
可用于监控 mysql Master Slave 状态的python代码
2013/02/10 Python
python缩进区别分析
2014/02/15 Python
Python中类的继承代码实例
2014/10/28 Python
Python模拟脉冲星伪信号频率实例代码
2018/01/03 Python
python生成1行四列全2矩阵的方法
2018/08/04 Python
Python 移动光标位置的方法
2019/01/20 Python
Python中Numpy mat的使用详解
2019/05/24 Python
Django中间件拦截未登录url实例详解
2019/09/03 Python
Python3.7 pyodbc完美配置访问access数据库
2019/10/03 Python
python实现3D地图可视化
2020/03/25 Python
基于SpringBoot构造器注入循环依赖及解决方式
2020/04/26 Python
基于python实现坦克大战游戏
2020/10/27 Python
HTML5通用接口详解
2016/06/12 HTML / CSS
世界上最大的乐器零售商:Guitar Center
2017/11/07 全球购物
MCAKE蛋糕官方网站:一直都是巴黎的味道
2018/02/06 全球购物
Java多态性的定义以及类型
2014/09/16 面试题
如何转换一个字符串到enum值
2014/04/12 面试题
应届生幼儿园求职信
2013/11/12 职场文书
学校司机岗位职责
2013/11/14 职场文书
小车司机岗位职责
2013/11/25 职场文书
法人代表证明书
2014/09/18 职场文书
安徽导游词
2015/02/12 职场文书
教师纪律作风整顿心得体会
2016/01/23 职场文书