基于PYQT5中的QLabel标签类的扩展类(图片,动画、按纽,多选按纽,单选按纽)示例

因PYQT5的标签类QLabel可支持显示透明图象,GIF动画等,用此类扩展继承类,封装好继承类以实现低代码就可以完成实现用标签显示图片,动画,文字,模仿图形按纽等,同时扩展来代替按纽,多选按纽,单选按纽的功能,下面以QLabel作为基类编写其扩展子类QLabelEx类(用于显示图片,动画等基本功能),在以QLabelEx类为基类,扩展出以下4个子类(QLabel的孙类)

QLabelExLstImg: 继承QLabelEx类的扩展类,用于定时显示指定的图象序列,显示类似于GIF动画效果

QLabelExBtn: 继承QLabelEx类的扩展类,用于模仿图象按纽,移入移出单击控件时可以用不同的透明图象显示效果

QLabelExBtnCheck: 继承QLabelEx类的扩展类,用于模仿check多选图象按纽

QLabelExBtnRadio: 继承QLabelEx类的扩展类,用于模仿Radio单选图象按纽

示例运行效果如下:(注:代码中用到的1.png等图片请自行找几小透明图片改名到模块目前录中即可,博客中我上传这几个图片可截屏保存,对异型图片要想显示异型按纽效果需要用firwork软件处理成透明图片即可)

原计划封装GIF动画时,用缓冲方式,即先将要用的GIF文件全部加载到内存中,以后不用再在硬盘上读取文件了,但没有成功,只能采用要使用的时候现读取和加载指定文件,如有成功的可以评论区贴下代码,供大家学习。

测试QtLabelEx.py模块的主窗体代码如下:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtCore
from PyQt5.QtGui import QMovie
from PyQt5.QtCore import QByteArray

from QtLabelEx import *    #导入自定义的标签扩展类
#测试标签扩展类的主窗体
class MyWidget(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('测试自定义继承QT的常用控件类')
        self.setGeometry(0, 0, 1920, 900)
        self.statusbar = self.statusBar()
        self.statusbar.showMessage('准备')
        self.setStatusTip('准备...')  
        self.qimage = QImage('1.jpg')   #底图
        self.initUI()
    def initUI(self):
        self.btn_Test=QPushButton('测试...',self)
        self.btn_Test.setGeometry(500,50,100,50)
        self.btn_Test.clicked.connect(self.test)
        font=QFont('宋体',9)
        font.setBold(True)
        font.setItalic(True)
        font.setUnderline(True)

        lst=['1.png','2.png','3.png','4.png']   #和模块文件同一目录的几个测试用小图片文件(最好用透明的PNG图)
                
        self.myLabel01 =  QLabelEx(self,50,50,150,150,'图象标签',0.8,font,QColor(255,0,0))
        self.myLabel01.SetAlign('DR')
        self.myLabel01.bDrawRect=True      #是否画出控件边框
        self.myLabel01.bChgCtlRect=False   #控件是否会自动变化其矩形区,以适应当前图象大小
        self.myLabel01.bZoomImgSize=True  #是否将图片放缩填满到控件的当前矩形区域
         
        self.myLabel01.LoadFile('1.gif')   #和模块文件同一目录的1个测试用GIF动画文件
        self.myLabel01.set_GifSpeed(100)
        self.myLabel01.DrawObjRect(QColor(0,0,255),2)

        self.myLabel02 =  QLabelExLstImg(self,250,50,150,150,'播放图象列表标签',0.8,font,QColor(255,0,0))
        self.myLabel02.setLstImg(lst,100)
        self.myLabel02.bDrawRect=False      #是否画出控件边框

        lstbtn=['btn_on.png','btn_on.png','btn_off.png','btn_disable.png']   #和模块文件同一目录的几个测试用小图片文件(最好用透明的PNG图)
        self.myLabel03 =  QLabelExBtn(self,50,250,202,73,'按纽标签')
        self.myLabel03.bDrawRect=False #不画外框
        self.myLabel03.setBtnImg(lstbtn)
        self.myLabel03.showMemImg(0)

        self.myLabel04 =  QLabelExBtnCheck(self,50,450,150,150,'多选按纽标签')
        self.myLabel05 =  QLabelExBtnCheck(self,250,450,150,150,'多选按纽标签')
        self.myLabel04.setBtnImg(lst)
        self.myLabel04.bZoomImgSize=False  #是否将图缩片放填满到控件的当前矩形区域
        self.myLabel04.showMemImg(0)
        self.myLabel05.setBtnImg(lst)
        self.myLabel05.bZoomImgSize=False  #是否将图片缩放填满到控件的当前矩形区域
        self.myLabel05.showMemImg(0)

        self.myLabel06 =  QLabelExBtnRadio(self,50,650,150,150,'单选按纽标签')
        self.myLabel06.setBtnGroup(0,0)  #仅用于QLabelExBtnRadio
        self.myLabel07 =  QLabelExBtnRadio(self,250,650,150,150,'单选按纽标签')
        self.myLabel07.setBtnGroup(0,1)  #仅用于QLabelExBtnRadio
        self.myLabel06.setBtnImg(lst)
        self.myLabel07.setBtnImg(lst)
        self.myLabel06.showMemImg(0)
        self.myLabel07.showMemImg(0)

        self.myLabel01.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel01.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel01.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel01.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 

        self.myLabel02.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel02.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel02.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel02.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 

        self.myLabel03.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel03.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel03.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel03.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 

        self.myLabel04.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel04.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel04.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel04.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 

        self.myLabel05.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel05.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel05.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel05.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 
        
        self.myLabel06.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel06.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel06.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel06.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 

        self.myLabel07.signal_Leftclicked.connect(self.lab_LeftClick) 
        self.myLabel07.signal_Rightclicked.connect(self.lab_RightClick) 
        self.myLabel07.signal_Midclicked.connect(self.lab_MidClick) 
        self.myLabel07.signal_LeftDropRelease.connect(self.lab_LeftDropClick) 

        self.myLabel06.signal_RadioBntSelected.connect(self.lab_RadioClick)  #仅用于QLabelExBtnRadio
        self.myLabel07.signal_RadioBntSelected.connect(self.lab_RadioClick)  #仅用于QLabelExBtnRadio

    #接收Radio标签按纽被单击时的信号   #仅用于QLabelExBtnRadio 
    def lab_RadioClick(self,groupID,obj):
        print('Radio标签按纽被单击反馈到主窗体的槽函数')
    
    #标签被单击时的信号槽函数
    def lab_LeftClick(self,obj):
        print(f'主窗体接收到了标签类发送来的信号signal_Leftclicked,鼠标点击相对控件内的坐标x={obj.startPoint.x()},y={obj.startPoint.y()},相对主窗体位置x={obj.startPoint.x()+obj.x()},y={obj.startPoint.y()+obj.y()}')
    def lab_RightClick(self,obj):
        print(f'主窗体接收到了标签类发送来的信号signal_Rightclicked,鼠标点击相对控件内的坐标x={obj.startPoint.x()},y={obj.startPoint.y()},相对主窗体位置x={obj.startPoint.x()+obj.x()},y={obj.startPoint.y()+obj.y()}')
    def lab_MidClick(self,obj):
        print(f'主窗体接收到了标签类发送来的信号signal_Midclicked,鼠标点击相对控件内的坐标x={obj.startPoint.x()},y={obj.startPoint.y()},相对主窗体位置x={obj.startPoint.x()+obj.x()},y={obj.startPoint.y()+obj.y()}')
    def lab_LeftDropClick(self,obj):
        print(f'主窗体接收到了标签类发送来的信号signal_LeftDropRelease,鼠标点击相对控件内的坐标x={obj.startPoint.x()},y={obj.startPoint.y()},相对主窗体位置x={obj.startPoint.x()+obj.x()},y={obj.startPoint.y()+obj.y()}')
    
    def mouseMoveEvent(self, event):
        #如果没有鼠标双击,执行
        globalPos = self.mapToGlobal(event.pos())
        x = globalPos.x()
        y = globalPos.y()
        self.text = '鼠标位置 {0:4d},{1:4d} '.format(x, y)
        self.update()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        #painter.drawImage(QRect(10, 50, self.qimage.width(),self.qimage.height()), self.qimage)  #会拉伸的在指定矩形中绘出: 本行为1:1
        painter.drawImage(QRect(0,0, self.width(),self.height()-32), self.qimage)
        painter.end() 

########################################################################################
    def test(self):   
        self.myLabel01.set_GifSpeed(200)            #为标签1的GIF播放速度快一倍
        self.myLabel02.setBkCol(QColor(0,255,0))   #为标签2为标签图片设置底色
        #self.myLabel03.ReshowText('abcd1234')
        self.myLabel03.setBtnEnable(False)          #为标签3为按纽设置为失效状态
        self.myLabel04.bDrawTxt=True    #图片和文字同时出现
        self.myLabel04.bDrawRect=False    #不画出控件外框
        self.myLabel05.bDrawTxt=True
        self.myLabel04.RefreshLable()
        self.myLabel05.RefreshLable()

        self.myLabel06.bDrawTxt=True     #图片和文字同时出现
        self.myLabel06.bDrawRect=False    #不画出控件外框
        self.myLabel06.move_Flag=True     #使控件06也支持可拖动了
        self.myLabel07.bDrawTxt=True
        self.myLabel06.RefreshLable()
        self.myLabel07.RefreshLable()

#########################################################################################
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec())

自定义的扩展QLabel的模块文件QtLabel.py文件代码如下:

#模块名:QtLabelEx.py:将QT5/6的标签等常规控件类再扩展对应的子类,更方便快速使用
#包含类名: QLabelEx: 继承QtLable类的扩展类:支持低代码显示图片,动画等功能
#          QLabelExLstImg: 继承QLabelEx类的扩展类,用于可以定时显示指定的图象列表
#          QLabelExBtn: 继承QLabelEx类的扩展类,用于模仿图象按纽,移入移出单击控件时可以用不同的透明图象显示
#          QLabelExBtnCheck: 继承QLabelEx类的扩展类,用于模仿check多选图象按纽
#           QLabelExBtnRadio: 继承QLabelEx类的扩展类,用于模仿Radio单选图象按纽
#           : 
import os,sys 
import PyQt5
from PyQt5 import *
from PyQt5 import QtCore   
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtGui import QMovie
from PyQt5.QtCore import QByteArray
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest

import time
import math
import copy 
import random

lst_ImgExName=['BMP','JPG','JPEG','PNG','TIF','TIFF','TGA','WMF','SVG','HEIF','RAW','WEBP']
lst_MovExName=['GIF','AVI','MPEG','MP4','MOV','MKV','WMV','FLV','RMVB','RM','RAM']
lst_AlignType=['TL','TC','TR','CL','CC','CR','DL','DC','DR']
#########################################################################################
#重载标签类,标签可透明显示图像,用于在窗体上加载小分部图像
class QLabelEx(QLabel):  
    objcount=0   # 
    signal_Leftclicked = QtCore.pyqtSignal(object)        #自定信号,标签被左键单击,传回参数:控件对象本身
    signal_Rightclicked = QtCore.pyqtSignal(object)       #自定信号,标签被右键单击,传回参数:控件对象本身
    signal_Midclicked = QtCore.pyqtSignal(object)        #自定信号,标签被中键单击,传回参数:控件对象本身
    signal_LeftDropRelease = QtCore.pyqtSignal(object)    #自定信号,标签被左键拖动后释放,传回参数:控件对象本身

    #初始化对角需传递的参数为  父类,创建矩形,内容,     控件透明度      字体                     字体颜色           背景颜色                    
    def __init__(self,     parent,x,y,w,h,text='',transt=1.0,font=QFont('宋体', 11),fcolor=QColor(0,0,0)):  
        super(QLabel, self).__init__(parent)
        self.type='TXT'   #标签控件的类型,'TXT'=纯文本标签,‘IMG'=可显示图片标签 'MOV':可播放动画标签
        self.setGeometry(x,y,w,h)
        self.ctlRect=QRect(x,y,w,h)     #控件的矩形区域
        self.imgRect=QRect()            #如果控件加载了图象或视频自身尺寸的矩形区域
        self.bDrawRect = True           #是否在标签控件外边画出矩形框        
        self.rectCol=QColor(255,0,0)    #画矩形边框的颜色
        self.rectPenWidth=2             #画矩形边框的线宽度
        self.bChgCtlRect=False          #如果self.ctlRect不能满足文字、图象的矩形区域时,是否允许控件变化其矩形来适应文字或图象要求的矩形区域
        self.move_Flag = True           #标签控件是否可以主窗体上拖动:对窗体元素,应设置为False
        self.bZoomImgSize=True          #控件的矩形区同图象的矩形区不相符时,是否允许图象或视频自动缩放以适应控件矩形区
        self.setScaledContents(self.bZoomImgSize)  # 设置标签的图片,设置True时图片自适应控件,为False时,只显示控件范围图片
        self.setAutoFillBackground(False) #不允许自动填充背景底色
        self.text=text       #标签是文本类型时显示的内容
        self.drawText=text   #标签是图片或视频类型时显示的内容
        self.alignFlags=Qt.AlignTop | Qt.AlignLeft   #对齐方式
        self.bDrawTxt = False   #显示图片的同时,是否将self.drawText画到图象上
        self.fontCol=fcolor   #字体颜色
        self.bkCol=QColor(255,255,255)     #如设置不透明时的标签背景颜色
        self.setFont(font)
        palette = QPalette()
        palette.setColor(QPalette.WindowText, self.fontCol) #设置字体颜色
  
        self.setPalette(palette)
        self.SetTransparent(transt)             #设置控件的透明度,1=不透明,0=完全透明
        self.setText(text)
        self.global_X=self.gobal_Y=0               #标签相对屏幕左上点(0,0)的坐标
        self.startPoint=QPoint()                    #鼠标在标签控件上压下开始的坐标点
        self.endPoint=QPoint()                      #鼠标在标签控件上压下结束时的坐标点
        self.mouse_X=self.mouse_Y=0                #鼠标在标签控件上相对标签控件范围的坐标
        self.origin_x=self.origin_y=0
        self.globalmouse_X=self.globalmouse_Y=0   #鼠标在标签控件上相对屏幕左上点(0,0)的坐标
        self.oldPos=QPoint()                       #移动前标签控件的位置
      
        self.curImgfilename=''
        self.curMovFileName=''
        self.curData=None     #当标签是加载的图片或动画时,将文件同容加载到内存中再显示,避免频繁读写文件
        self.image=QImage()
        self.curRotAngle=0.0 #图片当前旋转角度(角度,非弧度,顺时针为正)
        
        self.gifSpeed=200  #当前要播放的GIF动画的速度

        self.drawtxtX=self.drawtxtY=0
    #如要要不透明的标签,设置标签背景色
    def setBkCol(self,bkcol=QColor(255,255,255)):
        self.bkCol=bkcol
        palette = QPalette()
        self.setAutoFillBackground(True)          
        palette.setColor(QPalette.Background, self.bkCol)
        self.setPalette(palette)

    #设置标签中的文字/图片/GIF动画对齐方式Qt.AlignLeft:左对齐Qt.AlignRight:右对齐 Qt.AlignTop:顶部对齐Qt.AlignBottom:底部对齐Qt.AlignHCenter:水平居中Qt.AlignVCenter:垂直居中Qt.AlignCenter:同时水平和垂直居中
    def SetAlign(self,at='TL'):  #
        at=at.upper()
        self.alignFlags=Qt.AlignTop | Qt.AlignLeft
        if(at=='TL'): self.alignFlags=Qt.AlignTop | Qt.AlignLeft
        elif(at=='TC'): self.alignFlags=Qt.AlignTop | Qt.AlignHCenter
        elif(at=='TR'): self.alignFlags=Qt.AlignTop | Qt.AlignRight
        elif(at=='CL'): self.alignFlags=Qt.AlignVCenter | Qt.AlignLeft
        elif(at=='CC'): self.alignFlags=Qt.AlignVCenter | Qt.AlignHCenter
        elif(at=='CR'): self.alignFlags=Qt.AlignVCenter | Qt.AlignRight
        elif(at=='DL'): self.alignFlags=Qt.AlignBottom | Qt.AlignLeft
        elif(at=='DC'): self.alignFlags=Qt.AlignBottom | Qt.AlignHCenter
        elif(at=='DR'): self.alignFlags=Qt.AlignBottom | Qt.AlignRight
        else:self.alignFlags=Qt.AlignVCenter | Qt.AlignLeft
        self.setAlignment(self.alignFlags)
        self.setText(self.text)  #有时并没有出现对齐效果,只能采用先清除再重加载的方式

    #旋转控件中的图片一指定的角度:角度为正东向,向顺时针旋转的角度为正,反之为负(非弧度)
    def RotateImg(self,angle): 
        if(self.type=='IMG' and self.curData!=None):
            transform = QTransform()  
            transform.rotate(angle)     
            self.image=self.image.transformed(transform);             
            self.setPixmap(QPixmap.fromImage(self.image))  # 显示图片到Qlabel控件
            if(self.bChgCtlRect):   #为真时,旋转后同时调整控件大小
                self.resize(self.image.width(),self.image.height())

    #设置标签控件在加载图片时,控件尺寸同图片尺寸不符时,是否允许控件调整自身的矩形区域,以适应1:1的图象显示
    def ObjToImgSize(self):
        self.setScaledContents(self.bZoomImgSize)  #不允许自适应控件,只1:1显示到控件中,同时调整控件大小
        if(self.bChgCtlRect):   #只有先设置此属性为真时,才允许变化控件尺寸
            if(self.curData!=None):  
                image= QImage.fromData(self.curData)
                self.resize(image.width(),image.height()) #用下行后用设置参数中的矩形,用本行就是图片本身的尺寸
                self.ctlRect=QRect(self.x(),self.y(),self.width(),self.height())

    #设置标签加载的文件名称,可以是图片也可以是动画GIF或视频
    def LoadFile(self,filename=''):
        if(os.path.exists(filename)):
            file_extension = str(filename.split(".")[-1]).upper()
            bOK=False
            for exname in lst_ImgExName:
                if file_extension == exname:
                    self.type='IMG'
                    bOK=True
                    break
            for exname in lst_MovExName:
                if file_extension == exname:
                    self.type='MOV'
                    bOK=True
                    break
            if (bOK):
                with open(filename, 'rb') as f:
                    self.curData = f.read()
                self.image= QImage.fromData(self.curData)    
                self.curMovFileName=filename
                self.RefreshLable()
            else:
                print(f'没有找到对应扩展名: {file_extension} 的分类')
                self.type='TXT'
                self.ReshowText(self.text)
            self.ObjToImgSize()
        else:
            self.type='TXT'
            self.ReshowText(self.text)

    #清除图象,重新显示标签的文本
    def ReshowText(self,txt):
        self.text=txt
        self.clear()
        self.type='TXT'
        self.setText(txt)
    #设置显示图片的同时,画到标签控件上的文本,传入文本为空时,同标签控件初始化时的字符串一致,图形模式下,不调用此函数,默认不会绘出文本
    def setDrawText(self,txt,x=0,y=0):
        self.bDrawTxt=True
        if(len(txt)==0):
            self.drawText=self.text
        else:
            self.drawText=txt
        self.drawtxtX=x
        self.drawtxtY=y
    #重新显示标签(在用了LoadFile后)
    def RefreshLable(self):    #如果图片被调整乱了,且不想要控件尺寸同图片尺寸
        self.setScaledContents(self.bZoomImgSize)  #不允许自适应控件,只1:1显示到控件中,同时调整控件大小
        if(self.type=='IMG'):
            self.image= QImage.fromData(self.curData)
            self.setPixmap(QPixmap.fromImage(self.image))  # 显示图片到Qlabel控件
            self.imgRect=QRect(self.x(),self.y(),self.image.width(),self.image.height())
            if(self.bChgCtlRect):
                self.resize(self.image.width(),self.image.height()) #用下行后用设置参数中的矩形,用本行就是图片本身的尺寸             
            
        elif(self.type=='MOV'):
            """
            #用内存文件来播放GIF没成功??
            #从bytes创建一个QBuffer对象
            buffer=QBuffer()
            buffer.open(QBuffer.ReadOnly)
            buffer.write(self.curData)
            #self.movie = QMovie(self)
            #self.movie.setDevice(QByteArray(self.curData))

            # 使用QMovie来播放GIF
            #self.movie = QMovie(buffer)
            #self.movie.setSpeed(10)
            # 将movie应用到label上
            self.setMovie(self.movie)
            self.total_frame = self.movie.frameCount()
            self.gifSpeed=self.movie.speed()
            print(f'当前GIF文件=’{self.curMovFileName}‘,总帧数={self.total_frame},默认正常播放速度={self.gifSpeed}')
            self.set_GifSpeed(2.0)   #设置播放动画GIF的整速度:方法接受的是每1000毫秒播放的帧数比例,如是1:表示,一秒显示全部帧数,0.5表示一秒显示半数的帧数。
            self.movie.start()
            #self.setLabelLayer(True)
            """
            self.movie = QMovie(self.curMovFileName)
            # 将movie应用到label上
            self.setMovie(self.movie)
            self.total_frame = self.movie.frameCount()
            self.gifSpeed=self.movie.speed()
            #print(f'当前GIF文件=’{self.curMovFileName}‘,总帧数={self.total_frame},默认正常播放速度={self.gifSpeed}')
            self.set_GifSpeed(self.gifSpeed)   #设置播放动画GIF的整速度:方法接受的是每1000毫秒播放的帧数比例,如是1:表示,一秒显示全部帧数,0.5表示一秒显示半数的帧数。
            self.movie.start()
            #"""
        else:    #self.type=='TXT'
            pass 

    #设置播放GIF动画的速度:  interval值哦本准备播放GIF的默认播放速度的倍数,如当前GIF默认播放速度为100
    def set_GifSpeed(self,interval=100.0):
        self.gifSpeed=interval
        if(self.type=='MOV' and self.movie!=None):
            self.movie.setSpeed(interval)  # 设置播放速度
    #设置标签控件的透明程度:对文字及图片均有效
    def SetTransparent(self,trans):
        if trans>1:trans=1
        elif trans<0:trans=0
        self.Transparent=trans
        opacity_effect = QGraphicsOpacityEffect(parent=self)
        opacity_effect.setOpacity(trans)  # 设置透明度
        self.setGraphicsEffect(opacity_effect)  # 将透明度效果应用到标签上
        #self.setWindowOpacity(self.Transparent)
    #设置本标签对象是在最上方还是在最下方    
    def setLabelLayer(self,bTop=True):
        if(bTop):self.raise_()
        else:self.lower()
    #设置标签显示的文本的字体
    def setTextFont(self,fontname='宋体',fontsize=11,bBold=False,bItalic=False,bUnderline=False):
        font = QFont()
        font.setFamily(fontname)       # 设置字体名称
        font.setPointSize(fontsize)    # 设置字体大小
        font.setBold(bBold)            # 设置字体加粗
        font.setItalic(False)
        font.setUnderline(False)
        self.setFont(font)
    #设置标签显示的文本的字体
    def setTextCol(self,fcol=QColor(0,0,0)):
        self.setStyleSheet(f"QLabel {{ color: {fcol.name()}; }}")
     #设置标签显示的背景颜色(非透明状态下时)
    def setTextBkCol(self,bkcol=QColor(255,255,255)):
        if( not self.bTransparent):   #对非透明模式才支持设置标签背景颜色
            self.setAutoFillBackground(True)  # 确保背景自动填充
            palette = self.palette()
            palette.setColor(QPalette.Window, bkcol)  
            self.setPalette(palette)
    #得到标签矩形中心位置 
    def getObjRect(self):
        size = self.geometry()
        self.centerX=size.x()+size.width()/2
        self.centerY=size.y()+size.height()/2
        return size.x(),size.y(),size.width(),size.height()
    
    #鼠标按下事件重载   
    def mousePressEvent(self, event):  
        self.startPoint=event.pos()
        self.oldPos=QPoint(event.globalX(),event.globalY())                         
        # 核心部分: 当鼠标点击是左键 并且 在top控件内点击时候触发 
        if (event.button() == Qt.LeftButton and self.move_Flag):    #and self.top.underMouse():
            self.setCursor(Qt.OpenHandCursor)    #移动时设置成手型光标
            # 但判断条件满足时候, 把拖动标识位设定为真
            #self.move_Flag = True
            self.globalmouse_X = event.globalX()
            self.globalmouse_Y = event.globalY()
            # 获取窗体当前坐标
            self.origin_x = self.x()
            self.origin_y = self.y()
        
     #鼠标移动事件重载          
    def mouseMoveEvent(self, event):  
        # 拖动标识位设定为真时, 进入移动事件
        if self.move_Flag:
            # 计算鼠标移动的x,y位移
            move_x = event.globalX() - self.globalmouse_X
            move_y = event.globalY() - self.globalmouse_Y
            # 计算窗体更新后的坐标:更新后的坐标 = 原本的坐标 + 鼠标的位移
            dest_x = self.origin_x + move_x
            dest_y = self.origin_y + move_y
            # 移动本标签控件
            size = self.geometry()
            self.move(dest_x, dest_y)
            self.ctlRect=QRect(self.x(),self.y(),self.width(),self.height())
            self.setLabelLayer(True)    #拖动的标签控件角色在最顶端显示
            
    # 鼠标左键释放        
    def mouseReleaseEvent(self, event):
        self.endPoint=event.pos()
        newPos=QPoint(event.globalX(),event.globalY())  
        if (event.button() == Qt.LeftButton and self.move_Flag): 
            self.setCursor(Qt.ArrowCursor) # 设定鼠标为普通状态: 箭头
        if(self.move_Flag==False):   #非对象拖动状态,鼠标在控件区域移动一位置
            if(abs(self.endPoint.x()-self.startPoint.x())<2 and abs(self.endPoint.y()-self.startPoint.y())<2 ):  #判断是否单击
                if(event.button() == Qt.LeftButton):
                    print('非拖动状态下:是左键单击不是拖动')
                    self.signal_Leftclicked.emit(self)
                elif(event.button() == Qt.RightButton):
                    print('非拖动状态下:是右键单击不是拖动')
                    self.signal_Rightclicked.emit(self)
                elif(event.button() == Qt.MidButton):
                    print('非拖动状态下:是中键单击不是拖动')
                    self.signal_Midclicked.emit(self)
            else:
                print('非拖动状态下,鼠标在控件上移动了一位置')
        else:   #拖动对象状态,除非一点也没拖动,否则不对单位处理
            if(abs(self.oldPos.x()-newPos.x())<2 and abs(self.oldPos.y()-newPos.y())<2 ):
                print('虽是拖动状态但是并没拖动对象')
                if(event.button() == Qt.LeftButton):
                    print('拖动状态下:是左键单击不是拖动')
                    self.signal_Leftclicked.emit(self)
                elif(event.button() == Qt.RightButton):
                    print('拖动状态下:是右键单击不是拖动')
                    self.signal_Rightclicked.emit(self)
                elif(event.button() == Qt.MidButton):
                    print('拖动状态下:是中键单击不是拖动')
                    self.signal_Midclicked.emit(self)
            else:   #拖动对象移动了位置 
                print('拖动状态下:左键拖动控件移动了位置')
                self.signal_LeftDropRelease.emit(self)
                     
    #重载绘图函数:
    def paintEvent(self, event):
        if (self.bDrawRect):  #标签控件是否绘制边框架
            self.DrawObjRect(self.rectCol,self.rectPenWidth)   #为控件画出外边框
        if(self.bDrawTxt): #是否在标签控件上画出文本
            pen = QPen()                    # 创建画笔对象
            painter = QPainter(self)        # 此QPainter只能在paintEvent中定义,不能定义成类的self成员对象,也不能在其地方(如其他窗口,线程中)定义,否则没有绘画功能显示
            #绘制
            pen.setColor(self.fontCol)                 
            painter.drawText(self.drawtxtX,self.drawtxtY,self.width(),self.height(),self.alignFlags,self.drawText) 
        return super().paintEvent(event)                #调用主窗口的重绘事件,不用不会加载动画只显示第一帖,用了动画加载正常,但又多了一静态图第一帖
        
    #画出当前控件的矩形框(用于对象被选择时)
    def DrawObjRect(self,pencol,penwidth):
        self.rectCol=pencol
        self.rectPenWidth=penwidth
        if(self.bDrawRect):
            pen = QPen()                    # 创建画笔对象
            brush = QBrush()                # 创建画刷对象
            painter = QPainter(self)        # 此QPainter只能在paintEvent中定义,不能定义成类的self成员对象,也不能在其地方(如其他窗口,线程中)定义,否则没有绘画功能显示
            #绘制
            pen.setColor(pencol)                 
            pen.setStyle(Qt.SolidLine)               
            pen.setWidth(penwidth)          # 设置画笔宽度
            painter.setPen(pen)             # 设置画笔
            self.pixmap = QPixmap.fromImage(self.image)
           #painter.drawPixmap(0, 0, self.pixmap)
            painter.drawRect(0,0,self.width(),self.height()) 

#定义可用计时器播放连续图片以形成动画的标签扩展类    
class QLabelExLstImg(QLabelEx):
    def __init__(self, parent,x,y,w,h,text='',transt=1.0,font=QFont('宋体', 11),fcolor=QColor(0,0,0)):  
        super().__init__(parent,x,y,w,h,text,transt,font,fcolor)
        self.type='IMG'
        self.memImgFile=[]
        self.curtimespeed=100
        self.curindex = 0
        self.curPlayCount=0
        self.imgPlayCount = 0 #图象列表播放遍数,0=循环播放,大于0时为播放的遍数后,自动停止到最后一帖位置
        self.bStop=False      #指定遍数放完后,此开关为True
        # 创建计时器,设置时间间隔为100毫秒(1秒)
        self.timer = QTimer()
        # 计时器信号连接到timeout_slot槽函数
        self.timer.timeout.connect(self.time_objmove_slot)
        self.timer.start(self.curtimespeed)  # 开始计时器:

    #设置要播放的图片列表,及图象列表间播放的间隔
    def setLstImg(self,lstfilename,timesleep=50,playcount=0):
        self.bStop=False
        self.curPlayCount=0
        self.lstImgFile=lstfilename
        self.curtimespeed=timesleep
        self.imgPlayCount = playcount
        self.makeMemFile()
    #创建图片的内存文件
    def makeMemFile(self):
        self.memImgFile.clear()
        for imgFilename in self.lstImgFile:
            # 打开图片
            if(os.path.exists(imgFilename)):
                with open(imgFilename, 'rb') as f:
                    img = f.read()
                    self.memImgFile.append(img)

    #得到对象的文件内存数据:序号
    def getImgData(self,index):  
        count=len(self.memImgFile)
        if(count>0 and index>=0 and index<count):
            return self.memImgFile[index]
        else:
            print(f'返回一空图象{index},{count}')
            return None
        
    #显示内存文件数据:序号    
    def showMemImg(self,index):
        if(self.getImgData(index)!=None):
            self.curData = self.getImgData(index)
            self.RefreshLable()

    #在标签控件中播放下一帧
    def next_frame(self):
        count=len(self.memImgFile)
        if(count==0 or self.bStop):return
        if(self.curindex>=(count-1)): #已循环一遍
            if(self.imgPlayCount>=0):
                self.curPlayCount+=1
                if(self.imgPlayCount>0 and self.curPlayCount>=self.imgPlayCount):
                    self.curPlayCount = self.imgPlayCount+1
                    self.curData = self.getImgData(count-1)
                    self.bStop=True
                    return
                self.curData = self.getImgData(self.curindex)
                self.curindex=0
        else:
            self.curData = self.getImgData(self.curindex)
            self.curindex = (self.curindex + 1) % count 
        self.timer.setInterval(self.curtimespeed)

    #对象计时器来显示动画效果
    def time_objmove_slot(self):
        self.next_frame()   #得到下一帖图象
        #移动前对图象进行方向进行处理
        if (self.curData==None):   # 没图片,则不执行任何操作
            return
        size = self.geometry()
        fx = size.x()+size.width()/2 #对象矩形中心的坐标
        fy = size.y()+size.height()/2 
        if(self.type=='IMG'):  #对GIF,计时器会会造成播放过快无法控制
            self.RefreshLable()
       
#定义标签类按纽扩展类      
class QLabelExBtn(QLabelEx):
    def __init__(self, parent,x,y,w,h,text='',transt=1.0,font=QFont('宋体', 11),fcolor=QColor(0,0,0)):  
        super().__init__(parent,x,y,w,h,text,transt,font,fcolor)
        self.type='IMG'
        self.memImgFile=[]
        self.bEnable=True
    #设置要图片列表:0=按纽常规状态下的图片,1=鼠标移入控件时的图片,2=鼠标点击按纽时的图片,3=按纽失效时的图片
    def setBtnImg(self,lstfilename):
        self.lstImgFile=lstfilename
        self.makeMemFile()
    #创建图片的内存文件
    def makeMemFile(self):
        self.memImgFile.clear()
        for imgFilename in self.lstImgFile:
            # 打开图片
            if(os.path.exists(imgFilename)):
                with open(imgFilename, 'rb') as f:
                    img = f.read()
                    self.memImgFile.append(img)

    #得到对象的文件内存数据:序号
    def getImgData(self,index):  
        count=len(self.memImgFile)
        if(count>0 and index>=0 and index<count):
            return self.memImgFile[index]
        else:
            print(f'返回一空图象{index},{count}')
            return None
        
    #显示内存文件数据:序号    
    def showMemImg(self,index):
        if(self.getImgData(index)!=None):
            self.curData = self.getImgData(index)
            self.RefreshLable()
    #移入控件事件
    def enterEvent(self, event):     
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件                   
        self.showMemImg(1)
    #移出控件事件
    def leaveEvent(self,event):   
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件                      
        self.showMemImg(0)

    #鼠标按下事件重载   
    def mousePressEvent(self, event): 
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        if (event.button() == Qt.LeftButton): 
            self.showMemImg(2)
        return super().mousePressEvent(event)
      #鼠标移动事件重载          
    def mouseMoveEvent(self, event):  
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        return super().mouseMoveEvent(event)
     # 鼠标左键释放        
    def mouseReleaseEvent(self, event):
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        return super().mouseReleaseEvent(event)
    def setBtnEnable(self,enable):
        self.bEnable = enable
        print(f'self.bEnable={self.bEnable}')
        if(enable):self.showMemImg(0)
        else:self.showMemImg(3)
    
#定义标签CHECK类按纽扩展类    
class QLabelExBtnCheck(QLabelEx):
    def __init__(self, parent,x,y,w,h,text='',transt=1.0,font=QFont('宋体', 11),fcolor=QColor(0,0,0)):  
        super().__init__(parent,x,y,w,h,text,transt,font,fcolor)
        self.type='IMG'
        self.groupID=0  #check按纽所属组数
        self.move_Flag=False  #控件不可在主窗体上被拖动
        self.memImgFile=[]
        self.bEnable=True     #是否可用
        self.bChecked=False   #是否被选中
    #设置按纽所属组
    def setBtnGroup(self,group):
        self.groupID=group
    #设置要图片列表:0=按纽未被选中时的图片,1=按纽被选中时的图片,2=按纽未被选中失效时的图片,3=按纽被选中失效时的图片
    def setBtnImg(self,lstfilename):
        self.lstImgFile=lstfilename
        self.makeMemFile()
    #创建图片的内存文件
    def makeMemFile(self):
        self.memImgFile.clear()
        for imgFilename in self.lstImgFile:
            # 打开图片
            if(os.path.exists(imgFilename)):
                with open(imgFilename, 'rb') as f:
                    img = f.read()
                    self.memImgFile.append(img)

    #得到对象的文件内存数据:序号
    def getImgData(self,index):  
        count=len(self.memImgFile)
        if(count>0 and index>=0 and index<count):
            return self.memImgFile[index]
        else:
            print(f'返回一空图象{index},{count}')
            return None
        
    #显示内存文件数据:序号    
    def showMemImg(self,index):
        if(self.getImgData(index)!=None):
            self.curData = self.getImgData(index)
            self.RefreshLable()

    #鼠标按下事件重载   
    def mousePressEvent(self, event): 
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        if (event.button() == Qt.LeftButton): 
            self.bChecked=not self.bChecked
            if(self.bChecked):
                self.showMemImg(1)
            else:
                self.showMemImg(0)
        return super().mousePressEvent(event)
      #鼠标移动事件重载          
    def mouseMoveEvent(self, event):  
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        return super().mouseMoveEvent(event)
     # 鼠标左键释放        
    def mouseReleaseEvent(self, event):
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        return super().mouseReleaseEvent(event)
    def setBtnEnable(self,enable):
        self.bEnable = enable
        if(enable):
            if(self.bChecked):
                self.showMemImg(1)
            else:
                self.showMemImg(0)
        else:
            if(self.bChecked):
                self.showMemImg(2)
            else:
                self.showMemImg(3)
#定义标签Radio类按纽扩展类    
class QLabelExBtnRadio(QLabelEx):
    lst_btnRadio=[]    #定义到类构造外所有的类成员共用,每增加一个类成员实例化对象,同时加到此列表中以处理类似radio单选按纽的效果
    signal_RadioBntSelected = QtCore.pyqtSignal(int,object)        #自定信号,radio类按纽被单击时,通知主窗口,所有本组中的其他同类radio按结全部去除被选择状态,传回参数:所属组号
    def __init__(self, parent,x,y,w,h,text='',transt=1.0,font=QFont('宋体', 11),fcolor=QColor(0,0,0)):  
        super().__init__(parent,x,y,w,h,text,transt,font,fcolor)
        self.type='IMG'
        self.groupID=0  #单选按纽所属组数
        self.ID=0       #单选按纽在组中的序号:同组不可重复
        self.move_Flag=False  #控件不可在主窗体上被拖动
        self.memImgFile=[]
        self.bEnable=True     #是否可用
        self.bChecked=False   #是否被选中
        QLabelExBtnRadio.lst_btnRadio.append(self)  #单选按纽本身加入公用列表
    #设置按纽所属组和在组中的编号ID
    def setBtnGroup(self,group,ID):
        self.groupID=group
        self.ID=ID
    #设置要图片列表:0=按纽未被选中时的图片,1=按纽被选中时的图片,2=按纽未被选中失效时的图片,3=按纽被选中失效时的图片
    def setBtnImg(self,lstfilename):
        self.lstImgFile=lstfilename
        self.makeMemFile()
    #创建图片的内存文件
    def makeMemFile(self):
        self.memImgFile.clear()
        for imgFilename in self.lstImgFile:
            # 打开图片
            if(os.path.exists(imgFilename)):
                with open(imgFilename, 'rb') as f:
                    img = f.read()
                    self.memImgFile.append(img)

    #得到对象的文件内存数据:序号
    def getImgData(self,index):  
        count=len(self.memImgFile)
        if(count>0 and index>=0 and index<count):
            return self.memImgFile[index]
        else:
            print(f'返回一空图象{index},{count}')
            return None
        
    #显示内存文件数据:序号    
    def showMemImg(self,index):
        if(self.getImgData(index)!=None):
            self.curData = self.getImgData(index)
            self.RefreshLable()

    #鼠标按下事件重载   
    def mousePressEvent(self, event): 
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        if (event.button() == Qt.LeftButton):  
            self.setBtnChecked(True)  #本对象被选中,同组内的其他成员去除选中状态,一组成员中只能有一个被选中
            for obj in QLabelExBtnRadio.lst_btnRadio:
                if(self.groupID==obj.groupID and self.ID!=obj.ID):  #是同一组其他对象
                    obj.setBtnChecked(False)

            self.signal_RadioBntSelected.emit(self.groupID,self)
        return super().mousePressEvent(event)   #调用父类的按下事件
      #鼠标移动事件重载          
    def mouseMoveEvent(self, event):  
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        return super().mouseMoveEvent(event)
     # 鼠标左键释放        
    def mouseReleaseEvent(self, event):
        if(not self.bEnable): return     #当按纽状记为不可用时,不接受鼠标事件
        return super().mouseReleaseEvent(event)
    def setBtnEnable(self,enable):
        self.bEnable = enable
        if(enable):
            if(self.bChecked):
                self.showMemImg(1)
            else:
                self.showMemImg(0)
        else:
            if(self.bChecked):
                self.showMemImg(2)
            else:
                self.showMemImg(3)
    #设置Radio按纽的显示状态
    def setBtnChecked(self,checked):
        if(not self.bEnable): return     #当按纽标记为不可用时,不接受鼠标事件
        self.bChecked = checked
        if(self.bChecked):
            self.showMemImg(1)
        else:
            self.showMemImg(0)

代码中用到的几个图片粘到文章中,方便小白截屏使用看效果(不加工成透明,无法演示图片周围异形外的透时效果哦)

以下图片依次为'1.png','2.png','3.png','4.png'

以下图片依次为

'btn_on.png','btn_on.png','btn_off.png','btn_disable.png'

主窗体用底图'1.jpg',  任意COPY个屏保底图改名成1.jpg即可

动画用'1.gif'用的下面的GIF

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mr_LuoWei2009

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值