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用list或dict字段模式读取文件的方法
Jan 10 Python
Python如何通过subprocess调用adb命令详解
Aug 27 Python
python使用KNN算法手写体识别
Feb 01 Python
python 将字符串转换成字典dict的各种方式总结
Mar 23 Python
python之django母板页面的使用
Jul 03 Python
Python中常用的内置方法
Jan 28 Python
python 使用matplotlib 实现从文件中读取x,y坐标的可视化方法
Jul 04 Python
postman和python mock测试过程图解
Feb 22 Python
python3 sorted 如何实现自定义排序标准
Mar 12 Python
python UIAutomator2使用超详细教程
Feb 19 Python
Python爬虫实战之爬取京东商品数据并实实现数据可视化
Jun 07 Python
一文搞懂Python Sklearn库使用
Aug 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 的加密函数 md5,crypt,base64_encode 等使用介绍
2012/04/09 PHP
PHP批量去除BOM头代码分享
2015/06/26 PHP
Linux平台php命令行程序处理管道数据的方法
2016/11/10 PHP
js变量作用域及可访问性的探讨
2006/11/23 Javascript
jQuery去掉字符串起始和结尾的空格(多种方法实现)
2013/04/01 Javascript
让元素在网页中可拖动示例代码
2013/08/13 Javascript
js 判断控件获得焦点的示例代码
2014/03/04 Javascript
js实现键盘操作实现div的移动或改变的原理及代码
2014/06/23 Javascript
轻松学习jQuery插件EasyUI EasyUI创建RSS Feed阅读器
2015/11/30 Javascript
js 获取站点应用名的简单实例
2016/08/18 Javascript
简易的JS计算器实现代码
2016/10/18 Javascript
JavaScript计算值然后把值嵌入到html中的实现方法
2016/10/29 Javascript
HTML页面定时跳转方法解析(2种任选)
2016/12/22 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(二)
2017/01/21 Javascript
简单谈谈axios中的get,post方法
2017/06/25 Javascript
jQuery中库的引用方法
2018/01/06 jQuery
详解如何使用router-link对象方式传递参数?
2019/05/02 Javascript
jQuery zTree插件快速实现目录树
2019/08/16 jQuery
Vue 3.0 全家桶抢先体验
2020/04/28 Javascript
[43:57]Liquid vs Mineski 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
python中文乱码的解决方法
2013/11/04 Python
Python3实现对列表按元组指定列进行排序的方法分析
2018/12/22 Python
python3+PyQt5 使用三种不同的简便项窗口部件显示数据的方法
2019/06/17 Python
python requests抓取one推送文字和图片代码实例
2019/11/04 Python
python 列表、字典和集合的添加和删除操作
2019/12/16 Python
ALDI奥乐齐官方海外旗舰店:德国百年超市
2017/12/27 全球购物
英国门把手公司:Door Handle Company
2019/05/12 全球购物
解释一下钝化(Swap out)
2016/12/26 面试题
自我评价个人范文
2013/12/16 职场文书
母亲七十大寿答谢词
2014/01/18 职场文书
办理信用卡收入证明范例
2014/09/13 职场文书
师德师风自我剖析材料
2014/09/27 职场文书
单位工作证明
2014/10/07 职场文书
2016教师给学生的毕业寄语
2015/12/04 职场文书
使用Python的开发框架Brownie部署以太坊智能合约
2021/05/28 Python
ORACLE数据库应用开发的三十个注意事项
2021/06/07 Oracle