pyside6学习专栏(三):自定义QLabel标签扩展类QLabelEx
标签是界面设计中最常用的控件,本文演示了如何基于PySide6的QLabex控件类扩展定义QLabelEX类,以实现更少的编码完成各种图像、彩色文本、动画的加载和显示,丰富界面显示
本示例演示了QLabel和其扩展类QLabelEx分别显示文本、图像、动画的使用方法

示例主窗口模块代码如下:
# -*- coding:utf-8 -*-
import sys
from PySide6 import *
from PySide6.QtWidgets import *
from PySide6.QtCore import *
#from PySide6.QtGui import * #如果运行时没有任何界面调出,也不报错,请屏蔽此行,原因不详
import PySide6.QtChartsfrom PySide6.QtCore import Signal, QEvent,Property, QSize
from PySide6.QtCore import (QDateTime, QFile,QDir, QLibraryInfo, QSysInfo, Qt,QTimer,Slot, QAbstractTableModel, QModelIndex,QPoint,QPointF,QStandardPaths, QUrl, QIODevice, QRectF,qFatal,qWarning,qVersion)
from PySide6.QtGui import (QCursor,QIcon,QImage,QPicture,QDesktopServices, QGuiApplication,QKeySequence, QShortcut, QStandardItem,QStandardItemModel)
from PySide6.QtGui import (QPen,QBrush,QColor,QFont, QPainter,QGradient,QMatrix4x4,QPlatformSurfaceEvent, QSurface, QWindow,QSurfaceFormat)
from PySide6.QtGui import (QRhi, QRhiBuffer,QPixmap,QAction,QWheelEvent,QRhiDepthStencilClearValue,QRhiGraphicsPipeline, QRhiNullInitParams,QRhiGles2InitParams, QRhiRenderBuffer,QRhiSampler, QRhiShaderResourceBinding,QRhiShaderStage, QRhiTexture,QMovie,QRhiVertexInputAttribute, QRhiVertexInputBinding,QRhiVertexInputLayout, QRhiViewport, QShader)
from PySide6.QtWidgets import (QApplication, QDialog,QWidget, QFileDialog, QMainWindow, QMessageBox)
from PySide6.QtWidgets import (QCheckBox, QComboBox,QCommandLinkButton, QDateTimeEdit, QDial,QDialog, QDialogButtonBox, QFileSystemModel,QGridLayout, QGroupBox, QHBoxLayout, QLabel,QLineEdit, QListView, QMenu, QPlainTextEdit,QProgressBar, QPushButton, QRadioButton,QScrollBar, QSizePolicy, QSlider, QSpinBox,QStyleFactory, QTableWidget, QTabWidget,QTextBrowser, QTextEdit, QToolBox, QToolButton,QTreeView, QVBoxLayout)
from QLabelEx import * #导入标签扩展类################################################################################
class mainWindow(QWidget):def __init__(self, parent=None):super(mainWindow, self).__init__(parent)self.resize(500, 800)self.setWindowTitle("PySide QLabel及扩展标签类QLabelEx的几种用法示例")# 全局布局(1个):水平wlayout = QHBoxLayout()# 局部布局(2个):竖直self.layout1 = QVBoxLayout()self.layout1.setSpacing(10)self.layout2 = QVBoxLayout()self.layout2.setSpacing(10)'''配置'''# 配置文本内容label1 = QLabel(self)label1.setText("本列为原始PySide QLabel示例")# 设置图片label2 = QLabel(self)label2.setPixmap(QPixmap("2.png"))# 限制图片大小,并允许图片自适应限制label3 = QLabel(self)label3.setPixmap(QPixmap("2.png"))label3.setFixedSize(40, 40) # 限制图片大小label3.setScaledContents(True) # 图片自适应限制# 设置居中对齐label4 = QLabel(self)label4.setText("设置居中对齐")label4.setAlignment(Qt.AlignmentFlag.AlignCenter)# 设置缩进label5 = QLabel(self)label5.setText("设置缩进")label5.setIndent(20)# 设置边距;setStyleSheet("border:边框粗细 实体 颜色;")label6 = QLabel(self)label6.setText('文本边框显示,边框2倍框,实体边框,红色')label6.setStyleSheet("border:2px solid red;")# 文本内容距离边框的间距label7 = QLabel(self)label7.setText('文本内容距离边框的间距')label7.setStyleSheet("border:1px solid;")label7.setMargin(10)# 设置文本格式label8 = QLabel(self)label8.setText('设置文本格式为超文本')label8.setTextFormat(Qt.TextFormat.RichText)# 允许文本被编辑和选中label9 = QLabel(self)label9.setText('允许文本被编辑和选中')label9.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse | Qt.TextInteractionFlag.TextEditable)# 打开外部链接(可选择交互)label10 = QLabel(self)label10.setText("<a href='www.baidu.com' target='_blank'>超链接:百度</a>")label10.setOpenExternalLinks(True) # 允许打开链接# 画图案,drawEllipse(第1、2个参数是矩形的坐标原点,第3、4个参数是矩形的长和宽)label11 = QLabel(self)pic = QPicture() # 图片对象painter = QPainter(pic) # 画家对象painter.setBrush(QBrush(QColor(100, 120, 155))) # 设置画刷painter.drawEllipse(0, 0, 50, 100)label11.setPicture(pic)# 展示动图label12 = QLabel(self)movie = QMovie("1.gif")label12.setMovie(movie)label12.setFixedSize(100, 100) # 限制图片大小label12.setScaledContents(True) # 图片自适应限制movie.start() # !! 开始动画movie.setSpeed(100) # 设置动画的速度100%# movie.stop() # 关闭动画# 设计标签并清空label13 = QLabel(self)label13.setText('清空')label13.clear()# 字体label14 = QLabel(self)label14.setText('字体加粗,14号,黑体')label14.setFont(QFont('Bold', 14, QFont.Black))'''布局'''self.layout1.addWidget(label1)self.layout1.addWidget(label2)self.layout1.addWidget(label3)self.layout1.addWidget(label4)self.layout1.addWidget(label5)self.layout1.addWidget(label6)self.layout1.addWidget(label7)self.layout1.addWidget(label8)self.layout1.addWidget(label9)self.layout1.addWidget(label10)self.layout1.addWidget(label11)self.layout1.addWidget(label12)self.layout1.addWidget(label13)self.layout1.addWidget(label14)# 文本类扩展标签labelEx01 = QLabelEx(self,0,0,0,0,'本列为原始PySide QLabel类继承扩展QLabelEx类示例',0.5,QFont('黑体',18),QColor(255,0,0))self.layout2.addWidget(labelEx01)# 图像类扩展标签labelEx02 = QLabelEx(self,0,0,0,0,'图片扩展标签02') #默认是自动缩放装满标签矩形框:默认左中对齐labelEx02.LoadFile("2.png")self.layout2.addWidget(labelEx02)labelEx03 = QLabelEx(self,0,0,0,0,'图片扩展标签03') #默认是自动缩放装满标签矩形框labelEx03.bZoomImgSize=False #原图大小不缩放labelEx03.bDrawRect=True #画出控件矩形区域线框labelEx03.SetAlign('DR') #图片右下角对齐显示labelEx03.LoadFile("2.png")self.layout2.addWidget(labelEx03)# 动画类扩展标签labelEx04 = QLabelEx(self,0,0,0,0,'动画扩展标签04') #默认是自动缩放装满标签矩形框labelEx04.LoadFile("1.gif")self.layout2.addWidget(labelEx04)labelEx05 = QLabelEx(self,0,0,0,0,'动画扩展标签05') #默认是自动缩放装满标签矩形框labelEx05.bZoomImgSize=False #原图大小不进行缩放labelEx05.bDrawRect=True #画出控件矩形区域线框labelEx05.SetAlign('CC') #动画上下左右居中显示labelEx05.LoadFile("2.gif")self.layout2.addWidget(labelEx05)# 准备2个子窗体部件,分别定义上面准备布局的2个区域hwg = QWidget()vwg = QWidget()hwg.setLayout(self.layout1)vwg.setLayout(self.layout2)# 四个部件加至全局布局(沿水平方向,竖向7等分平区为8块,水平占3等份网格占3等份,其他占1等份)wlayout.addWidget(hwg)wlayout.addWidget(vwg)# 窗体本体设置全局布局self.setLayout(wlayout)if __name__ == '__main__':app = QApplication(sys.argv)mainwin = mainWindow()mainwin.show()sys.exit(app.exec_())
自定义标签扩展类模块QLabeEx.py代码如下
#模块名:QLabelEx.py:将PySide6的标签、编辑框、按纽等常规控件类再扩展对应的子类,更方便快速使用
#包含类名: QLabelEx: 继承QtLable类的扩展类:支持低代码显示图片,动画等功能
# QLabelExLstImg: 继承QLabelEx类的扩展类,用于可以定时显示指定的图象列表
# QLabelExBtn: 继承QLabelEx类的扩展类,用于模仿图象按纽,移入移出单击控件时可以用不同的透明图象显示
# QLabelExBtnCheck: 继承QLabelEx类的扩展类,用于模仿check多选图象按纽
# QLabelExBtnRadio: 继承QLabelEx类的扩展类,用于模仿Radio单选图象按纽
# :
import os,sys,time,math,copy,random
"""已不需要PyQt5,转为PySide6支持了
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
"""
from PySide6 import *
from PySide6.QtWidgets import *
from PySide6.QtCore import *
#from PySide6.QtGui import * #如果运行时没有任何界面调出,也不报错,请屏蔽此行,原因不详
import PySide6.QtChartsfrom PySide6.QtCore import Signal, QEvent,Property, QSize
from PySide6.QtCore import (QDateTime, QFile,QDir, QLibraryInfo, QSysInfo, Qt,QTimer,Slot, QAbstractTableModel, QModelIndex,QPoint,QPointF,QStandardPaths, QUrl, QIODevice, QRectF,qFatal,qWarning,qVersion)
from PySide6.QtGui import (QCursor,QIcon,QImage,QPicture,QDesktopServices, QGuiApplication,QKeySequence, QShortcut, QStandardItem,QStandardItemModel)
from PySide6.QtGui import (QPen,QBrush,QColor,QFont,QPalette,QPainter,QGradient,QMatrix4x4,QPlatformSurfaceEvent, QSurface, QWindow,QSurfaceFormat)
from PySide6.QtGui import (QRhi, QRhiBuffer,QPixmap,QAction,QWheelEvent,QRhiDepthStencilClearValue,QRhiGraphicsPipeline, QRhiNullInitParams,QRhiGles2InitParams, QRhiRenderBuffer,QRhiSampler, QRhiShaderResourceBinding,QRhiShaderStage, QRhiTexture,QMovie,QRhiVertexInputAttribute, QRhiVertexInputBinding,QRhiVertexInputLayout, QRhiViewport, QShader)
from PySide6.QtWidgets import (QApplication, QDialog,QWidget, QFileDialog, QMainWindow, QMessageBox)
from PySide6.QtWidgets import (QCheckBox, QComboBox,QCommandLinkButton, QDateTimeEdit, QDial,QDialog, QDialogButtonBox, QFileSystemModel,QGridLayout, QGroupBox, QHBoxLayout, QLabel,QLineEdit, QListView, QMenu, QPlainTextEdit,QProgressBar, QPushButton, QRadioButton,QScrollBar, QSizePolicy, QSlider, QSpinBox,QStyleFactory, QTableWidget, QTabWidget,QTextBrowser, QTextEdit, QToolBox, QToolButton,QTreeView, QVBoxLayout)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 = Signal(object) #自定信号,标签被左键单击,传回参数:控件对象本身signal_Rightclicked = Signal(object) #自定信号,标签被右键单击,传回参数:控件对象本身signal_Midclicked = Signal(object) #自定信号,标签被中键单击,传回参数:控件对象本身signal_LeftDropRelease = Signal(object) #自定信号,标签被左键拖动后释放,传回参数:控件对象本身#初始化对角需传递的参数为 父类,创建矩形,内容, 控件透明度 字体 字体颜色 背景颜色 def __init__(self,parent=None,x=0,y=0,w=0,h=0,text='',transt=1.0,font=QFont('宋体', 11),fcolor=QColor(0,0,0)): super(QLabelEx, 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 = False #是否在标签控件外边画出矩形框 self.rectCol=QColor(255,0,0) #画矩形边框的颜色self.rectPenWidth=2 #画矩形边框的线宽度self.bChgCtlRect=False #如果self.ctlRect不能满足文字、图象的矩形区域时,是否允许控件变化其矩形来适应文字或图象要求的矩形区域self.move_Flag = False #标签控件是否可以主窗体上拖动:对窗体元素,应设置为Falseself.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.ColorRole.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=0self.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=bkcolpalette = QPalette()self.setAutoFillBackground(True) palette.setColor(QPalette.ColorRole.Window, 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.AlignLeftif(at=='TL'): self.alignFlags=Qt.AlignTop | Qt.AlignLeftelif(at=='TC'): self.alignFlags=Qt.AlignTop | Qt.AlignHCenterelif(at=='TR'): self.alignFlags=Qt.AlignTop | Qt.AlignRightelif(at=='CL'): self.alignFlags=Qt.AlignVCenter | Qt.AlignLeftelif(at=='CC'): self.alignFlags=Qt.AlignVCenter | Qt.AlignHCenterelif(at=='CR'): self.alignFlags=Qt.AlignVCenter | Qt.AlignRightelif(at=='DL'): self.alignFlags=Qt.AlignBottom | Qt.AlignLeftelif(at=='DC'): self.alignFlags=Qt.AlignBottom | Qt.AlignHCenterelif(at=='DR'): self.alignFlags=Qt.AlignBottom | Qt.AlignRightelse:self.alignFlags=Qt.AlignVCenter | Qt.AlignLeftself.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=Falsefor exname in lst_ImgExName:if file_extension == exname:self.type='IMG'bOK=Truebreakfor exname in lst_MovExName:if file_extension == exname:self.type='MOV'bOK=Truebreakif (bOK):with open(filename, 'rb') as f:self.curData = f.read()self.image= QImage.fromData(self.curData) self.curMovFileName=filenameself.RefreshLable()else:print(f'没有找到对应扩展名: {file_extension} 的分类')self.type='TXT'self.ReshowText(self.text)self.ObjToImgSize()else:self.type='TXT'self.ReshowText(self.text)self.RefreshLable() #清除图象,重新显示标签的文本def ReshowText(self,txt):self.text=txtself.clear()self.type='TXT'self.setText(txt)#设置显示图片的同时,画到标签控件上的文本,传入文本为空时,同标签控件初始化时的字符串一致,图形模式下,不调用此函数,默认不会绘出文本def setDrawText(self,txt,x=0,y=0):self.bDrawTxt=Trueif(len(txt)==0):self.drawText=self.textelse:self.drawText=txtself.drawtxtX=xself.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默认播放速度为100def set_GifSpeed(self,interval=100.0):self.gifSpeed=intervalif(self.type=='MOV' and self.movie!=None):self.movie.setSpeed(interval) # 设置播放速度#设置标签控件的透明程度:对文字及图片均有效def SetTransparent(self,trans):if trans>1:trans=1elif trans<0:trans=0self.Transparent=transopacity_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.ColorRole.Window, bkcol) self.setPalette(palette)#得到标签矩形中心位置 def getObjRect(self):size = self.geometry()self.centerX=size.x()+size.width()/2self.centerY=size.y()+size.height()/2return 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 = Trueself.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_Xmove_y = event.globalY() - self.globalmouse_Y# 计算窗体更新后的坐标:更新后的坐标 = 原本的坐标 + 鼠标的位移dest_x = self.origin_x + move_xdest_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=pencolself.rectPenWidth=penwidthif(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=100self.curindex = 0self.curPlayCount=0self.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=Falseself.curPlayCount=0self.lstImgFile=lstfilenameself.curtimespeed=timesleepself.imgPlayCount = playcountself.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):returnif(self.curindex>=(count-1)): #已循环一遍if(self.imgPlayCount>=0):self.curPlayCount+=1if(self.imgPlayCount>0 and self.curPlayCount>=self.imgPlayCount):self.curPlayCount = self.imgPlayCount+1self.curData = self.getImgData(count-1)self.bStop=Truereturnself.curData = self.getImgData(self.curindex)self.curindex=0else: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): # 没图片,则不执行任何操作returnsize = 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=lstfilenameself.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 = enableprint(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=lstfilenameself.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.bCheckedif(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 = enableif(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 = Signal(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 #check按纽所属组数self.ID=0self.move_Flag=False #控件不可在主窗体上被拖动self.memImgFile=[]self.bEnable=True #是否可用self.bChecked=False #是否被选中QLabelExBtnRadio.lst_btnRadio.append(self) #单选按纽本身加入公用列表#设置按纽所属组和在组中的编号IDdef setBtnGroup(self,group,ID):self.groupID=groupself.ID=ID#设置要图片列表:0=按纽未被选中时的图片,1=按纽被选中时的图片,2=按纽未被选中失效时的图片,3=按纽被选中失效时的图片def setBtnImg(self,lstfilename):self.lstImgFile=lstfilenameself.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 = enableif(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 = checkedif(self.bChecked):self.showMemImg(1)else:self.showMemImg(0)
本示例用到图像文件:1.png 1.jpg 2.png 1.gif 2.gif等文件自行找些改名后,copy到代码目录下即可
相关文章:
pyside6学习专栏(三):自定义QLabel标签扩展类QLabelEx
标签是界面设计中最常用的控件,本文演示了如何基于PySide6的QLabex控件类扩展定义QLabelEX类,以实现更少的编码完成各种图像、彩色文本、动画的加载和显示,丰富界面显示 本示例演示了QLabel和其扩展类QLabelEx分别显示文本、图像、动画的使用…...
后“智驾平权”时代,谁为安全冗余和体验升级“买单”
线控底盘,正在成为新势力争夺下一个技术普及红利的新赛点。 尤其是进入2025年,比亚迪、长安等一线传统自主品牌率先开启高阶智驾的普及战,加上此前已经普及的智能座舱,舱驾智能的「科技平权」进一步加速行业启动「线控底盘」上车窗…...
springboot408-基于Java的樱洵宾馆住宿管理系统(源码+数据库+纯前后端分离+部署讲解等)
💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
C语言中 %* 的用法总结
C语言中 %* 的用法总结 一、scanf 中的 %* 作用:跳过输入字段,读取数据但不存储到变量。语法:%*[格式] 示例格式:%*d(跳过一个整数)、%*s(跳过一个字符串)。 适用场景:…...
EasyRTC:基于WebRTC与P2P技术,开启智能硬件音视频交互的全新时代
在数字化浪潮的席卷下,智能硬件已成为我们日常生活的重要组成部分,从智能家居到智能穿戴,从工业物联网到远程协作,设备间的互联互通已成为不可或缺的趋势。然而,高效、低延迟且稳定的音视频交互一直是智能硬件领域亟待…...
鸿蒙NEXT应用App测试-通用测试
注意:大家记得学完通用测试记得再学鸿蒙专项测试 https://blog.csdn.net/weixin_51166786/article/details/145768653 注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章…...
transfmer学习认识
整体架构 1.自注意机制 1.1.softmax 在机器学习和深度学习中,softmax 函数是一个常用的激活函数,用于将一个向量转换为一个概率分布。softmax 函数的公式如下: …...
人工智能(AI)的不同维度分类
人工智能(AI)的分类 对机器学习进行分类的方式多种多样,可以根据算法的特性、学习方式、任务类型等不同维度进行分类这些分类都不是互斥的: 1、按数据模态不同:图像,文本,语音,多态等 2、按目标函数不同:判别式模型…...
三、linux字符驱动详解
在上一节完成NFS开发环境的搭建后,本节将探讨Linux字符设备驱动的开发。字符设备驱动作为Linux内核的重要组成部分,主要负责管理与字符设备(如串口、键盘等)的交互,并为用户空间程序提供统一的读写操作接口。 驱动代码…...
谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇
前言 ES 7.10 可能是现在比较常见的 ES 版本。但是对于一些相迭代比较慢的早期业务系统来说,ES 6.8 是一个名副其实的“钉子户”。 借着工作内升级调研的任务东风,我整理从 ES 6.8 到 ES 7.10 ELastic 重点列出的新增功能和优化内容。将分为 6 个篇幅给…...
我用Ai学Android Jetpack Compose之LinearProgressIndicator
本篇,我们来学习LinearProgressIndicator,答案来自 通义千问 Q:我想学习LinearProgressIndicator,麻烦你介绍一下 当然可以!LinearProgressIndicator 是 Jetpack Compose 中的一个组件,用于显示线性进度条。它非常适…...
代码随想录算法训练营day40(补0208)
买卖股票专栏 1.买卖股票最佳时机 贪心法,好想 题目 121. 买卖股票的最佳时机 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖…...
在群晖上使用Docker安装思源笔记
最近一段时间,docker的镜像地址都失效了,在群晖系统中,无论是早期版本的docker,还是最新版本中的Container Manager,注册表中都无法链接到docker的镜像,于是,就花了点时间查找资料&#x…...
【废物研究生刷算法】字符串
文章目录 1. 反转字符串2. 替换数字3. 反转字符串中的单词4. 右旋字符串总结1、字符串处理函数2、字符串切片 如果使用python处理字符串,有很多py内置的函数可以使用,主要还是记住这些处理方法。 1. 反转字符串 class Solution:def reverseStr(self, s, …...
断开ssh连接程序继续运行
在使用 SSH 远程连接服务器时,我们常希望在断开连接后仍然让程序继续运行,以下是几种常见的方法: 1. 使用 screen 或 tmux screen 和 tmux 是两款非常强大的终端复用工具,它们允许你在后台运行会话,即使断开 SSH 连接…...
Kafka客户端连接服务端异常 Can‘t resolve address: VM-12-16-centos:9092
前置条件: 已在CentOs上搭建好kafka节点服务器,已启动kafka服务已在Springboot项目中引入kafka客户端配置,kafka.bootstrap-serverip:port,并启动客户端服务 异常过程: 在客户端Springboot服务启动过程,控…...
视频mp4垂直拼接 水平拼接
视频mp4垂直拼接 水平拼接 pinjie_v.py import imageio import numpy as np import os import cv2def pinjie_v(dir1,dir2,out_dir):os.makedirs(out_dir, exist_okTrue)# 获取目录下的所有视频文件video_files_1 [f for f in os.listdir(dir1) if f.endswith(.mp4)]video_fi…...
idea-代码补全快捷键
文章目录 前言idea-代码补全快捷键1. 基本补全2. 类型匹配补全3. 后缀补全4. 代码补全 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差,…...
Transformer为什么需要多头注意力(Multi-Head Attention)?如果没有多头会怎么样?
直接回答 关键点: Transformer 中的多头注意力(Multi-Head Attention)允许模型同时关注输入数据的不同方面,提升性能。 如果没有多头,模型可能无法捕捉复杂关系,表现会下降。 什么是多头注意力ÿ…...
我们来学人工智能 -- DeepSeek客户端
DeepSeek客户端 题记使用后记系列文章 题记 我选择了 Cherry Studio是国内产品由CherryHQ团队开源是一个平台在这里,有豆包、kimi、通义千问的入口当然,最主要是作为大模型的UI正如标题,这里,作为DeepSeep的客户端 使用 下载本…...
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34) 题目描述:输入输出样例:题解:解题思路:思路一(一次二分查找挨个搜索):思路二(两次二…...
洛谷 P1102 A-B 数对(详解)c++
题目链接:P1102 A-B 数对 - 洛谷 1.题目分析 2.算法原理 解法一:暴力 - 两层for循环 因为这道题需要你在数组中找出来两个数,让这两个数的差等于定值C就可以了,一层for循环枚举A第二层for循环枚举B,求一下看是否等于…...
计算机视觉:主流数据集整理
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络(附代码) 第五章࿱…...
2025软件测试面试常问的题(详细解析)
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 测试技术面试题 1、什么是兼容性测试?兼容性测试侧重哪些方面? 参考答案: 兼容测试主要是检查软件在不同的硬件平台、软件平…...
项目POC的作用是什么
在项目管理和开发中,POC(Proof of Concept,概念验证)作为一个关键的步骤,扮演着非常重要的角色。POC的作用主要是验证某个概念、技术或方案的可行性,通过小规模实验或原型验证项目的关键假设,帮…...
初探动态规划--记忆化搜索
记忆化搜索 暴力dfs 记录答案 记忆化搜索是一种优化技术,结合了暴力深度优先搜索 (dfs) 和记录答案的方式。 在动态规划的学习过程中,我们可以将问题划分为以下阶段:dfs暴力搜索,记忆化搜索,以及最终的递推。 动态规…...
java开发——为什么要使用动态代理?
举个例子:假如有一个杀手专杀男的,不杀女的。代码如下: public interface Killer {void kill(String name, String sex);void watch(String name); }public class ManKiller implements Killer {Overridepublic void kill(String name, Stri…...
集合 数据结构 泛型
文章目录 1.Collection集合1.1数组和集合的区别【理解】1.2集合类体系结构【理解】1.3Collection 集合概述和使用【应用】内部类匿名内部类Lambda表达式 1.4Collection集合的遍历【应用】1.5增强for循环【应用】 2.List集合2.1List集合的概述和特点【记忆】2.2List集合的特有方…...
特征提取:如何从不同模态中获取有效信息?
在多模态学习中,特征提取是一个至关重要的过程。它是将原始数据(如文本、图像、视频和语音等)转化为机器能够理解和处理的特征的核心步骤。不同于传统的单一模态任务,在多模态学习中,如何有效地从每种模态中提取出有意…...
