《PyQt5 快速编程》例子注释

本文提供了从qt4版本升级到qt5的Fraction Slider.py代码示例,详细注释了修改过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Fraction Slider.py的qt4代码修改后的qt5版本

import platform
import PyQt5
from PyQt5.QtCore import QPointF,QRectF,QSize,Qt,QObject,pyqtSignal
from PyQt5.QtGui import QColor,QFont,QFontMetricsF,QPainter,QPalette,QPolygonF,QKeyEvent
from PyQt5.QtWidgets import (QApplication,QDialog,QGridLayout,QLCDNumber,
                                QLabel,QSizePolicy,QSpinBox,QWidget)


# 这段代码貌似与界面x11有关 暂时看不明白要干嘛
X11=hasattr(PyQt5.QtGui,"qt_x11_wait_for_window_manager")
X11 = True

try:
    from PyQt5.QtGui import qt_x11_wait_for_window_manager
except ImportError:
    X11 = False


class FractionSlider(QWidget):
    #定义边距
    XMARGIN=12
    YMARGIN=9
    WSTRING='999'

    #定义一个valueChanged的信号
    # valueChanged=signal().valueChanged
    valueChanged=pyqtSignal(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)
        #可以伸展和收缩,不过sizeHint() 的返回值规定了
        # widget 能缩小到的最小尺寸,同时它比 Preferred 更具优势去获取额外空间
        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')
        #更新widget绘制
        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):
        #event.x() 是不是指的是widget内部的坐标
        self.moveSlider(event.x())

    def moveSlider(self,x):
        span=self.width()-2*FractionSlider.XMARGIN
        offset=span-x+FractionSlider.XMARGIN
        #根据鼠标的位置来确定分子的大小
        numerator=int(round(self.__denominator*(1-offset/span)))
        numerator=max(0,min(numerator,self.__denominator))
        if numerator!=self.__numerator:
            self.__numerator=numerator
            #发射值改变的信号 
            #emit参数可以附带参数信息
            self.valueChanged.emit(self.__numerator)

            #重新绘制图形 
            self.update()

    #根据按下的按键的不同确定change的变化程度
    def KeyPressEvent(self, event: QKeyEvent):
        change=0
        key=None
        if key==Qt.Key_Home:
            change=-self.__denominator
        elif key in (Qt.Key_Up,Qt.Key_Right):
            change=1
        elif key in (Qt.Key_Down,Qt.Key_Right):
            change=-1
        elif key==Qt.Key_PageDown:
            change=-(self.__denominator//10+1)
        elif key==Qt.Key_PageUp:
            change=self.__denominator//10+1
        elif key==Qt.Key_End:
            change=self.__denominator
        if change:
            numerator=self.__numerator+change
            numerator=max(0,min(numerator,self.__denominator))
            if numerator!=self.__numerator:
                self.__numerator=numerator
                self.valueChanged.emit(self.__numerator)
                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()-self.XMARGIN*2
        value=self.decimal()
        painter=QPainter(self)
        #设置反锯齿 
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.TextAntialiasing)
        #QPalette参见page337
        #pen用于绘制文字和轮廓 调色板设定颜色
        painter.setPen(self.palette().color(QPalette.Mid))
        #brush负责填充背景
        painter.setBrush(self.palette().brush(QPalette.AlternateBase))
        painter.drawRect(self.rect())

        #绘制了一个进度条区域方便指针在上面滑动
        segColor=QColor(Qt.green).darker(120)
        #darker函数默认参数是200
        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
        ymargin=FractionSlider.YMARGIN
        yOffeset=segHeight+fm.height()

        for i in range(self.__denominator+1):
            painter.setPen(segLineColor)
            #draw from pos1 to pos2
            painter.drawLine(x,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,str(i))
            #绘制分母
            y=yOffeset
            rect.moveCenter(QPointF(x,y+fm.height()/2.0))
            painter.drawText(rect,Qt.AlignCenter,str(self.__denominator))  
            #绘制分割线 indent是半个字宽
            painter.drawLine(QPointF(rect.left()+indent,y),QPointF(rect.right()-indent,y))

            x+=segWidth

        #绘制三角形刻度标记图标
        #其实这段代码写的是有问题的 只有 XMARGIN = Span/(denominator-1)时 才能这么写 
        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,y+fm.height())]

        #确定三角形中间那个点的位置
        x=FractionSlider.XMARGIN+value*span
        # 确定三角形上边长度/2的长度
        trianglewidth=segWidth-indent
        #找出围的三角形的点
        triangle=[QPointF(x-trianglewidth,y),QPointF(x+trianglewidth,y),QPointF(x,y+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()
    denominatorSpinBox.setRange(3,30)
    denominatorSpinBox.setValue(slider.fraction()[1])
    denominatorSpinBox.setAlignment(Qt.AlignRight|Qt.AlignCenter)
    denominatorLabel.setBuddy(denominatorSpinBox)

    numeratorLabel=QLabel('&Numberator')
    numeratorLCD=QLCDNumber()
    numeratorLCD.setSegmentStyle(QLCDNumber.Flat)
    numeratorLabel.setBuddy(numeratorLCD)


    #网格布局
    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(denominitor):
        numerator=slider.decimal()*denominitor
        slider.setFraction(numerator,denominitor)
        numeratorLCD.display(numerator)

    def dsp(num):
        numeratorLCD.display(num)
    #分母发生变化
    denominatorSpinBox.valueChanged.connect(valueChanged)
    #分子发生变化
    slider.valueChanged.connect(dsp)

    form.setWindowTitle('Fraction Slider')
    form.show()
    app.exec_()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值