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到代碼目錄下即可

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70328.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70328.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70328.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從0到1:固件分析

固件分析 0x01 固件提取 1、從廠商官網下載 例如D-link的固件&#xff1a; https://support.dlink.com/resource/products/ 2、代理或鏡像設備更新時的流量 發起中間人攻擊MITM #啟用IP轉發功能 echo 1 > /proc/sys/net/ipv4/ip_forward#配置iptables&#xff0c;將目…

使用 Spring Boot 和 Canal 實現 MySQL 數據庫同步

文章目錄 前言一、背景二、Canal 簡介三、主庫數據庫配置1.主庫配置2.創建 Canal 用戶并授予權限 四.配置 Canal Server1.Canal Server 配置文件2.啟動 Canal Server 五.開發 Spring Boot 客戶端1. 引入依賴2. 配置 Canal 客戶端3. 實現數據同步邏輯 六.啟動并測試七.注意事項八…

Linux系統配置阿里云yum源,安裝docker

配置阿里云yum源 需要保證能夠訪問阿里云網站 可以先ping一下看看&#xff08;阿里云可能禁ping&#xff0c;只要能夠解析為正常的ip地址即可&#xff09; ping mirrors.aliyun.com腳本 #!/bin/bash mkdir /etc/yum.repos.d/bak mv /etc/yum.repos.d/*.repo /etc/yum.repos…

后端開發:開啟技術世界的新大門

在互聯網的廣闊天地中&#xff0c;后端開發宛如一座大廈的基石&#xff0c;雖不直接與用戶 “面對面” 交流&#xff0c;卻默默地支撐著整個互聯網產品的穩定運行。它是服務器端編程的核心領域&#xff0c;負責處理數據、執行業務邏輯以及與數據庫和其他后端服務進行交互。在當…

銀河麒麟系統安裝mysql5.7【親測可行】

一、安裝環境 cpu&#xff1a;I5-10代&#xff1b; 主板&#xff1a;華碩&#xff1b; OS&#xff1a;銀河麒麟V10&#xff08;SP1&#xff09;未激活 架構&#xff1a;Linux 5.10.0-9-generic x86_64 GNU/Linux mysql版本&#xff1a;mysql-5.7.34-linux-glibc2.12-x86_64.ta…

從零開始學習PX4源碼9(部署px4源碼到gitee)

目錄 文章目錄 目錄摘要1.gitee上創建倉庫1.1 gitee上創建倉庫PX4代碼倉庫1.2 gitee上創建子倉庫2.固件在gitee部署過程2.1下載固件到本地2.2切換本地分支2.3修改.gitmodules內容2.4同步子模塊倉庫地址2.5同步子模塊倉庫地址更新(下載)子模塊3.一級子模塊和二級子模塊的映射關…

【回溯算法2】

力扣17.電話號碼的字母組合 鏈接: link 思路 這道題容易想到用嵌套的for循環實現&#xff0c;但是如果輸入的數字變多&#xff0c;嵌套的for循環也會變長&#xff0c;所以暴力破解的方法不合適。 可以定義一個map將數字和字母對應&#xff0c;這樣就可以獲得數字字母的映射了…

科普:“Docker Desktop”和“Docker”以及“WSL”

“Docker Desktop”和“Docker”這兩個概念既有緊密聯系&#xff0c;又存在一定區別&#xff1a; 一、聯系 核心功能同源&#xff1a;Docker Desktop 本質上是基于 Docker 核心技術構建的。Docker 是一個用于開發、部署和運行應用程序的開源平臺&#xff0c;它利用容器化技術…

Flutter 網絡請求與數據處理:從基礎到單例封裝

Flutter 網絡請求與數據處理&#xff1a;從基礎到單例封裝 在 Flutter 開發中&#xff0c;網絡請求是一個非常常見的需求&#xff0c;比如獲取 API 數據、上傳文件、處理分頁加載等。為了高效地處理網絡請求和數據管理&#xff0c;我們需要選擇合適的工具并進行合理的封裝。 …

虛擬表格實現全解析

在數據展示越來越復雜的今天&#xff0c;大量數據的渲染就像是“滿漢全席”——如果把所有菜肴一次性擺上桌&#xff0c;既浪費資源也讓人眼花繚亂。幸運的是&#xff0c;我們有兩種選擇&#xff1a; 自己動手&#xff1a;通過二次封裝 Element Plus 的表格組件&#xff0c;實…

QT 讀寫鎖

一、概述 1、讀寫鎖是一種線程同步機制&#xff0c;用于解決多線程環境下的讀寫競爭問題。 2、讀寫鎖允許多個線程同時獲取讀鎖&#xff08;共享訪問&#xff09;&#xff0c;但只允許一個線程獲取寫鎖&#xff08;獨占訪問&#xff09;。 3、這種機制可以提高并發性能&…

2025 vue3面試題匯總,通俗易懂

一、基礎概念與核心特性 1. Vue3 相比 Vue2 的改進&#xff08;通俗版&#xff09; 問題&#xff1a;Vue3 比 Vue2 好在哪&#xff1f; 答案&#xff1a; 更快&#xff1a; Proxy 代理&#xff1a;Vue2 的響應式像“逐個監聽保險箱”&#xff08;每個屬性單獨監聽&#xff0…

第5章:在LangChain中如何使用AI Services

這篇文章詳細介紹了 LangChain4j 中的 AI Services 概念&#xff0c;展示了如何通過高層次的抽象來簡化與大語言模型&#xff08;LLM&#xff09;的交互。AI Services 的核心思想是隱藏底層復雜性&#xff0c;讓開發者專注于業務邏輯&#xff0c;同時支持聊天記憶、工具調用和 …

二叉樹(數據結構)

二叉樹 二叉樹也是用過遞歸定義的結構 先序遍歷又稱前序遍歷 ?? ?? 按照先序遍歷的方法去手算處理這個二叉樹 ?? 先A B C 再 A B D E C&#xff08;也就是把B換成BDE再放進去&#xff09; 再 A B D E C F 看這個插入的方法要掌握像二叉樹這樣向一個…

機器學習筆記——常用損失函數

大家好&#xff0c;這里是好評筆記&#xff0c;公主號&#xff1a;Goodnote&#xff0c;專欄文章私信限時Free。本筆記介紹機器學習中常見的損失函數和代價函數&#xff0c;各函數的使用場景。 熱門專欄 機器學習 機器學習筆記合集 深度學習 深度學習筆記合集 文章目錄 熱門…

Wireshark使用介紹

文章目錄 Wireshark介紹Wireshark使用工作模式介紹1. 混雜模式&#xff08;Promiscuous Mode&#xff09;2. 普通模式&#xff08;Normal Mode&#xff09;3. 監視模式&#xff08;Monitor Mode&#xff09; 界面分區捕獲過濾器語法基本語法邏輯運算符高級語法使用示例捕獲過濾…

#滲透測試#批量漏洞挖掘#暢捷通T+SQL注入漏洞

免責聲明 本教程僅為合法的教學目的而準備,嚴禁用于任何形式的違法犯罪活動及其他商業行為,在使用本教程前,您應確保該行為符合當地的法律法規,繼續閱讀即表示您需自行承擔所有操作的后果,如有異議,請立即停止本文章讀。 目錄 一、漏洞全景解析 1. 高危漏洞案例庫 2.…

【小游戲】C++控制臺版本俄羅斯輪盤賭

制作團隊&#xff1a;洛谷813622&#xff08;Igallta&#xff09; 989571&#xff08;_ayaka_&#xff09; Mod&#xff1a;_ayaka_ 雙人模式&#xff1a;Igallta 公告&#xff1a; 原先的9.8改名為 Alpha 1.0&#xff0c;以后每次更新都增加 0.1。 Alpha 1.11 改為 Beta 1…

nvm安裝、管理node多版本以及配置環境變量【保姆級教程】

引言 不同的項目運行時可能需要不同的node版本才可以運行&#xff0c;由于來回進行卸載不同版本的node比較麻煩&#xff1b;所以需要使用node工程多版本管理。 本人在配置時&#xff0c;通過網絡搜索教程&#xff0c;由于文章時間過老&#xff0c;或者文章的互相拷貝導致配置時…

框架--Mybatis3

一.特殊符號處理 < < > > " &quot; &apos; & &amp; 除了可以使用上述轉義字符外&#xff0c;還可以使<![CDATA[ ]]>用來包裹特殊字符。 二.mybatis 一級緩存二級緩存 1.為什么緩存 緩存&#xff1a;數據緩存&#xf…