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基于twisted实现简单的web服务器
Sep 29 Python
python OpenCV学习笔记之绘制直方图的方法
Feb 08 Python
Python使用OpenCV进行标定
May 08 Python
python3.6.3转化为win-exe文件发布的方法
Oct 31 Python
Django框架模板注入操作示例【变量传递到模板】
Dec 19 Python
python实现抽奖小程序
Apr 15 Python
python实现最大子序和(分治+动态规划)
Jul 05 Python
pytorch之ImageFolder使用详解
Jan 06 Python
python 画条形图(柱状图)实例
Apr 24 Python
使用pandas读取表格数据并进行单行数据拼接的详细教程
Mar 03 Python
如何用python插入独创性声明
Mar 31 Python
Python学习之时间包使用教程详解
Mar 21 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下对字符串的递增运算代码
2010/08/21 PHP
MySQL时间字段究竟使用INT还是DateTime的说明
2012/02/27 PHP
作为PHP程序员应该了解MongoDB的五件事
2013/06/03 PHP
PHP计数器的实现代码
2013/06/08 PHP
PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
2014/06/25 PHP
IE6/7/8中Option元素未设value时Select将获取空字符串
2011/04/07 Javascript
通过JavaScript控制字体大小的代码
2011/10/04 Javascript
jquery中push()的用法(数组添加元素)
2014/11/25 Javascript
JavaScript中函数(Function)的apply与call理解
2015/07/08 Javascript
关于function类中定义变量this的简单说明
2016/05/28 Javascript
js设置和获取自定义属性的方法
2016/10/20 Javascript
详解AngularJS ui-sref的简单使用
2017/04/24 Javascript
详解html-webpack-plugin用法全解
2018/01/22 Javascript
cnpm加速Angular项目创建的方法
2018/09/07 Javascript
JS实现换肤功能的方法实例详解
2019/01/30 Javascript
小程序的上传文件接口的注意要点解析
2019/09/17 Javascript
Layui tree 下拉菜单树的实例代码
2019/09/21 Javascript
[01:15:16]DOTA2-DPC中国联赛 正赛 Elephant vs Aster BO3 第一场 1月26日
2021/03/11 DOTA
用Python从零实现贝叶斯分类器的机器学习的教程
2015/03/31 Python
Django之form组件自动校验数据实现
2020/01/14 Python
Python基于gevent实现文件字符串查找器
2020/08/11 Python
Python基于execjs运行js过程解析
2020/11/27 Python
python使用scapy模块实现ARP扫描的过程
2021/01/21 Python
selenium+超级鹰实现模拟登录12306
2021/01/24 Python
css3 实现滚动条美化效果的实例代码
2021/01/06 HTML / CSS
欧舒丹英国官网:购买欧舒丹护手霜等明星产品
2017/01/17 全球购物
澳洲健康食品网上商店:Aussie Health Products
2018/06/15 全球购物
切尔西足球俱乐部官方网上商店:Chelsea FC
2019/06/17 全球购物
阿拉伯时尚购物网站:Nisnass
2021/02/07 全球购物
旅游管理实习自我鉴定
2013/09/29 职场文书
学生打架检讨书大全
2014/01/23 职场文书
《桥》教学反思
2014/04/09 职场文书
公司向个人借款协议书范本
2014/10/09 职场文书
2015年学校远程教育工作总结
2015/07/20 职场文书
浅谈vue2的$refs在vue3组合式API中的替代方法
2021/04/18 Vue.js
postgresql 删除重复数据案例详解
2021/08/02 PostgreSQL