十分簡單的一個畫板程序,用QLabel控件作為畫布,在畫布上可以畫出直線、矩形、填充矩形、園,橢園、隨手畫、文本等內容。
將原先發布的畫板程序中的畫文本方法修改成了原位創建一編輯框,編輯框失去焦點后,即將文本畫在畫布上。
畫板原碼myPaint.py
# -*- coding: utf-8 -*-
"""
myPaint.py:基于python+pyside6的簡易畫板模塊
"""
import sys,os,time,random,copy,math
from math import *
from PySide6 import *
from PySide6.QtWidgets import *
from PySide6.QtCore import *
#from PySide6.QtGui import * #如果運行時沒有任何界面調出,也不報錯,請屏蔽此行,原因不詳
import PySide6.QtCharts
from PySide6.QtCore import Signal, QEvent,Property, QSize
from PySide6.QtGui import (QCursor,QIcon,QImage, QGuiApplication)
from PySide6.QtGui import (QPen,QBrush,QColor,QFont, QPalette,QPainter,QPixmap,QAction)
from PySide6.QtWidgets import (QDialog,QWidget, QFileDialog, QMainWindow, QMessageBox)
from PySide6.QtWidgets import (QApplication,QLabel, QLineEdit,QMenu, QToolButton)class enu_DrawType():"""定義繪制的類型枚舉"""DRAW_NO=0DRAW_LINE=1DRAW_RECT=2DRAW_FILLRECT=3DRAW_CIRCLE=4DRAW_ELLIPSE=5DRAW_FREE=6DRAW_TEXT=7#
class MypaintWindow(QMainWindow): """定義主窗口類(繼承自QMainWindow)"""def __init__(self):super().__init__()self.resize(1600, 905)self.setMaximumSize(1428,905)self.setWindowTitle('PySide6簡易畫板')self.initUi()def initUi(self):# 創建狀態欄self.statusbar = self.statusBar()self.statusbar.showMessage('準備')#創建標簽畫板(本類要重載繼承QLabel),在窗體右側,作為畫板區域)self.label_Draw = MyLabel(self)# 設置label的尺寸self.label_Draw.setMaximumSize(1418,800)self.label_Draw.setGeometry(5, 76, 1418, 800)# 把pix_img傳遞給label#self.label_Draw.setPixmap(self.pix)# 設置pix_img填充滿Label#self.label_Draw.label_DrawsetScaledContents(True)self.label_Draw.setScaledContents(True)#self.label_Draw.setPixmap(QPixmap("1.jpg")) #此語句無效,標簽同畫板綁定后,不會加載外部圖像了#初始化工具欄self.initToolBar()#定義一菜單對象menubar = self.menuBar()fileMenu = menubar.addMenu('文件')menu_New = QAction('保存畫板', self)menu_New.setStatusTip('在狀態欄上顯示內容:將當前畫板中的圖像保存到文件')fileMenu.addAction(menu_New)menu_Load = QMenu('導入', self)subMenu_LoadImg= QAction('導入圖像', self)subMenu_LoadImg.setStatusTip('在狀態欄上顯示內容:導入一外部圖形文件到畫板')menu_Load.addAction(subMenu_LoadImg)fileMenu.addMenu(menu_Load)mnu_Exit = QAction(QIcon("t08.png"),'退出程序',self)mnu_Exit.setShortcut("ctrl+Q") mnu_Exit.setStatusTip('在狀態欄上顯示內容:退出程序')mnu_Exit.triggered.connect(qApp.quit)fileMenu.addAction(mnu_Exit)sta = self.statusBar() #狀態欄# 本例創建了一個行為菜單。這個行為/動作能切換狀態欄顯示或者隱藏。menu_View = menubar.addMenu('選項')viewStatAct = QAction('顯示/隱藏狀態欄', self, checkable=True)viewStatAct.setStatusTip('在狀態欄上顯示內容:視圖菜單->顯示/隱藏狀態欄') # 用checkable選項創建一個能選中的菜單。viewStatAct.setChecked(True) # 默認設置為選中狀態menu_View.addAction(viewStatAct)#初始化工具欄:定義主窗口類(繼承自QMainWindow)def initToolBar(self):self.toolBar_main = QToolBar("繪圖工具欄")self.addToolBar(self.toolBar_main )#self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.toolBar_main)self.toolBar_main.setObjectName(u"toolBar_main")self.toolBar_main.setFocusPolicy(Qt.FocusPolicy.ClickFocus)self.toolBar_main.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)self.setIconSize(QSize(24, 24))self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)#代碼用到的圖像資源請放在程序目錄下的res子目錄下,當然可以自行更改位置和文件名self.act_DrawLine = QAction(QIcon("./res/t01.png"), "畫線", self)self.act_DrawLine.setObjectName(u"act_DrawLine")self.act_DrawLine.triggered.connect(self.draw_Line)self.toolBar_main.addAction(self.act_DrawLine)self.act_DrawRect = QAction(QIcon("./res/t02.png"), "畫矩形", self)self.act_DrawRect.setObjectName(u"act_DrawRect")self.act_DrawRect.triggered.connect(self.draw_Rect)self.toolBar_main.addAction(self.act_DrawRect)self.act_DrawFillRect = QAction(QIcon("./res/t03.png"), "畫填充矩形", self)self.act_DrawFillRect.setObjectName(u"act_DrawFillRect")self.act_DrawFillRect.triggered.connect(self.draw_FillRect)self.toolBar_main.addAction(self.act_DrawFillRect)self.act_DrawCircle = QAction(QIcon("./res/t04.png"), "畫圓", self)self.act_DrawCircle.setObjectName(u"act_DrawCircle")self.act_DrawCircle.triggered.connect(self.draw_Circle)self.toolBar_main.addAction(self.act_DrawCircle)self.act_DrawEllptic = QAction(QIcon("./res/t05.png"), "畫橢圓", self)self.act_DrawEllptic.setObjectName(u"act_DrawEllptic")self.act_DrawEllptic.triggered.connect(self.draw_Ellptic)self.toolBar_main.addAction(self.act_DrawEllptic)self.act_DrawFree = QAction(QIcon("./res/t06.png"), "涂手畫", self)self.act_DrawFree.setObjectName(u"act_DrawFree")self.act_DrawFree.triggered.connect(self.Draw_Free)self.toolBar_main.addAction(self.act_DrawFree)self.act_DrawText = QAction(QIcon("./res/t07.png"), "畫文本", self)self.act_DrawText.setObjectName(u"act_DrawText")self.act_DrawText.triggered.connect(self.draw_Text)self.toolBar_main.addAction(self.act_DrawText)self.act_DrawQuit = QAction(QIcon("./res/t08.png"), "退出繪畫", self)self.act_DrawQuit.setObjectName(u"self.act_DrawExit")self.act_DrawQuit.triggered.connect(self.draw_Quit)self.toolBar_main.addAction(self.act_DrawQuit)#在菜單事件中:定義一右鍵菜單def contextMenuEvent(self, event):cmenu = QMenu(self)act_New = cmenu.addAction("新建") #僅示例,新建時不對已畫圖形作保存等處理,直接清空畫板,余同print(act_New)act_Open = cmenu.addAction("打開")print(act_Open)act_Quit = cmenu.addAction("退出")print(act_Quit)#關聯菜單信號對象action = cmenu.exec_(self.mapToGlobal(event.pos()))#處理對應菜單的響應函數if action == act_Quit:qApp.quit() #僅示例,退出時不對是否保存圖像作細化處理elif action == act_Open:print('打開') #僅示例,沒有具體功能代碼,自行完善elif action == act_New:print('新建')self.label_Draw.pix.fill(Qt.white)self.label_Draw.repaint() #清空標簽畫板上的圖形#對應主菜單:視圖-->顯示/隱藏狀態欄的信號槽函數def toggleMenu(self, state):if state:self.statusbar.show()else:self.statusbar.hide()####################################################################################槽函數:畫直線def draw_Line(self):print('畫直線')self.label_Draw.draw_Type=enu_DrawType.DRAW_LINEcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:畫矩形def draw_Rect(self):print('畫矩形') self.label_Draw.draw_Type=enu_DrawType.DRAW_RECTcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:畫矩形def draw_FillRect(self):print('畫填充矩形') self.label_Draw.draw_Type=enu_DrawType.DRAW_FILLRECTcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:畫園def draw_Circle(self):print('畫圓') self.label_Draw.draw_Type=enu_DrawType.DRAW_CIRCLEcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:畫橢圓def draw_Ellptic(self):print('畫橢圓') self.label_Draw.draw_Type=enu_DrawType.DRAW_ELLIPSEcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:隨手畫def Draw_Free(self): print('隨手畫') self.label_Draw.draw_Type=enu_DrawType.DRAW_FREEcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:畫文本def draw_Text(self): print('畫文本') self.label_Draw.draw_Type=enu_DrawType.DRAW_TEXTcursor = QCursor(Qt.CrossCursor)self.setCursor(cursor)#槽函數:退出繪圖模式 def draw_Quit(self): print('退出繪圖模式') self.label_Draw.draw_Type=enu_DrawType.DRAW_NOcursor = QCursor(Qt.ArrowCursor)self.setCursor(cursor)bDrawOK=True ####################################################################################################################
#自定義標簽類1,把標簽區域作為畫板區域
class MyLabel(QLabel):#鼠標起點,鼠標終點lastPoint = QPoint() #在類函數體外可以不加self前綴,但在函數體名類對象引用時,必須要加self的前綴endPoint = QPoint()bDrawOK=True #處理因重載繪圖事件過快,可能會多畫一此不可預料的雜圖,初始化應True,讓畫布畫白底一次#初始化def __init__(self, text=''):super(MyLabel, self).__init__(text) self.setFont(QFont('宋體', 16)) # 設置字體和大小self.bLeftMouseKey=False #定義只鼠標左鍵才能進行繪畫#定義繪圖的設置(字典數據方式)self.dic_Set={'線型':'SolidLine', #SolidLine=實線 DashLine=虛線 DotLine=點線 DashDotLine=點劃線 DashDotDotLine=雙點劃線 CustomDashLine=自定義線'線寬':2,'線顏色':'black', #black=黑色 red=紅色 blue=藍色.......'畫刷類型':'SolidPattern', #SolidPattern=純色填充 Dense1Pattern=密度樣式1 Dense2Pattern=密度樣式2... HorPattern=水平線樣式 VerPattern=垂直線樣式 CrossPattern=交通叉線樣式 DiagCrossPattern=傾斜交叉線樣式 BDiagPattern=反斜線樣式 FDiagPattern傾斜樣式 '填充色':'blue','文本':'示例文本內容','字體名稱':'宋體','字號':16,'粗體':False,'斜體':False,'下劃線':False,'刪除線':False,'字體顏色':'black','其他設置自行擴展':''}self.edtCtlPosX=0 #保存畫文本圖形時,調出對話框或編輯框控件的左上角位置 self.edtCtrlPosY=0self.lst_LineType=['實線','虛線','點線','點劃線','雙點劃線','自定義線']self.lst_Col=["black", "red", "green", "blue", "purple", "orange", "MediumSlateBlue", "CornflowerBlue","DodgerBlue", "DeepskyBlue", "LightSkyBlue", "SkyBlue", "LightBlue","請自行增加..."]self.lst_FillType=['純色','密度樣式1','密度樣式2','密度樣式3','密度樣式4','密度樣式5','密度樣式6','密度樣式7','水平線樣式','垂直線樣式','交叉線樣式','傾斜交叉線樣式','反斜線樣式','傾斜樣式']cursor = QCursor(Qt.CrossCursor) #光標類型#定義當前繪畫類型self.draw_Type=enu_DrawType.DRAW_NO #PY中沒有枚舉,這里采用數字方式比對 0=非繪畫模式 1=畫線模式 2=畫矩形模式 3=畫填充矩形模式 4=畫圓模式 5=畫橢圓模式 6=隨手畫模式 7=畫文本模式#在窗體上設置一區域為畫布,畫布大小為1418*800,背景為白色self.pix = QPixmap(1418, 800) #實例化QPixmap類self.pix.fill(Qt.white)# 把pix_img傳遞給labelself.setPixmap(self.pix)self.noPatter = QPainter(self.pix).brush()# 創建并配置字體self.font = QFont()self.font.setFamily('宋體') # 字體名稱self.font.setPointSize(12) # 字號(磅)self.font.setBold(False) # 加粗self.font.setItalic(False) # 斜體self.font.setUnderline(False) # 下劃線self.font.setStrikeOut(False) # 刪除線self.txtCol='black'self.lstText=['',QRect(0,0,0,0),self.txtCol,self.font] self.newWidth=0self.newHeight=0self.autoWidth=True #文字過長時是否自動加寬繪制文本的矩形框#def getLineType(self,typeTxt='實線'): """得到畫線類型""" linetype=Qt.SolidLineif(typeTxt==self.lst_LineType[0]):linetype=Qt.SolidLineelif(typeTxt==self.lst_LineType[1]):linetype=Qt.DashLineelif(typeTxt==self.lst_LineType[2]):linetype=Qt.DotLineelif(typeTxt==self.lst_LineType[3]):linetype=Qt.DashDotLineelif(typeTxt==self.lst_LineType[4]):linetype=Qt.DashDotLineelif(typeTxt==self.lst_LineType[5]):linetype=Qt.DashDotDotLineelse: linetype=Qt.SolidLinereturn linetype#def getFillType(self,typeTxt='純色'): """得到填充類型""" filltype=Qt.SolidPatternif(typeTxt==self.lst_FillType[0]):filltype=Qt.SolidPatternelif(typeTxt==self.lst_FillType[1]):filltype=Qt.Dense1Patternelif(typeTxt==self.lst_FillType[2]):filltype=Qt.Dense2Patternelif(typeTxt==self.lst_FillType[3]):filltype=Qt.Dense3Patternelif(typeTxt==self.lst_FillType[4]):filltype=Qt.Dense4Patternelif(typeTxt==self.lst_FillType[5]):filltype=Qt.Dense5Patternelif(typeTxt==self.lst_FillType[6]):filltype=Qt.Dense6Patternelif(typeTxt==self.lst_FillType[7]):filltype=Qt.Dense7Patternelif(typeTxt==self.lst_FillType[8]):filltype=Qt.HorPatternelif(typeTxt==self.lst_FillType[9]):filltype=Qt.VerPatternelif(typeTxt==self.lst_FillType[10]):filltype=Qt.CrossPatternelif(typeTxt==self.lst_FillType[11]):filltype=Qt.DiagCrossPatternelif(typeTxt==self.lst_FillType[12]):filltype=Qt.BDiagPatternelif(typeTxt==self.lst_FillType[13]):filltype=Qt.FDiagPattern else: filltype=Qt.SolidPatterreturn filltypedef getSet(self,setName):"""從字典變量得到設置值,有錯誤時得到默認值,僅為示例,可以通過讀取INI文件或注冊表來得到初始設置值"""if(setName=='線型'): defValue='SolidLine'elif(setName=='線寬'): defValue=2elif(setName=='線顏色'): defValue='black'elif(setName=='畫刷類型'): defValue='SolidPattern'elif(setName=='填充色'): defValue='blue'elif(setName=='文本'): defValue='示例文本內容'elif(setName=='字體名稱'): defValue='宋體'elif(setName=='字號'): defValue=12elif(setName=='粗體'): defValue=Falseelif(setName=='斜體'): defValue=Falseelif(setName=='下劃線'): defValue=Falseelif(setName=='刪除線'): defValue=Falseelif(setName=='字體顏色'): defValue='black'else: print('無此設置項')value = self.dic_Set.get(setName, defValue)return value#def SetValue(self,setName,value):"""運行中設置配置值"""self.dic_Set[setName]=valuedef setBackgroundColor(self, color):"""設置標簽畫板的背景色"""pal = self.palette()pal.setColor(self.backgroundRole(), QColor(color))self.setPalette(pal)#def paintEvent(self, event):"""重載繪圖函數:根據選擇設置,畫不同的圖形 #0=非繪畫模式 1=畫線模式 2=畫矩形模式 3=畫填充矩形模式 4=畫圓模式 5=畫橢圓模式 6=隨手畫模式 7=畫文本模式"""pen = QPen() # 創建畫筆對象brush = QBrush() # 創建畫刷對象pp = QPainter(self.pix)if(self.draw_Type==enu_DrawType.DRAW_FREE): #隨手畫模式:固定畫筆,不用隨機模式用設置值pencol = QColor(self.getSet('線顏色'))pen.setWidth(2) pp.setPen(pen) # 設置畫筆 else: lineType = self.getLineType(self.lst_LineType[random.randrange(0,5)]) #畫線類型,隨機選一種fillType = self.getFillType(self.lst_FillType[random.randrange(0,13)]) #填充類型:隨機選一種#pencol = QColor(self.getSet('線顏色')) #不用設置色,用隨機色pencol = QColor(self.lst_Col[random.randrange(0,12)]) #畫筆顏色:隨機選一種pen.setColor(pencol) # 設置畫筆顏色為紅色pen.setStyle(lineType) # 設置畫筆類型pen.setWidth(random.randrange(1,8)) # 設置畫筆寬度#pp.setBrush(QColor(self.getSet('填充色'))) #不用設置的初始值brush.setColor(QColor(self.lst_Col[random.randrange(0,12)])) #畫刷顏色為隨機選一種brush.setStyle(fillType) pp.setPen(pen) #設置畫筆pp.setBrush(brush) #設置畫刷x1 = self.lastPoint.x()y1 = self.lastPoint.y()x2 = self.endPoint.x()y2 = self.endPoint.y()point1=QPoint(x1,y1)point2=QPoint(x2,y2)if(self.bDrawOK==False): #此繪畫開關沒打開前,避免誤畫圖形returnif(self.draw_Type==enu_DrawType.DRAW_LINE): #畫直線模式pp.drawLine(point1, point2)elif(self.draw_Type==enu_DrawType.DRAW_RECT): #畫矩形模式pp.setBrush(self.noPatter) #畫非填充矩形時:暫沒找到透明畫刷的得到方法,用的保存了一初始畫刷沒有加載顏色等時的值if(x1<=x2): #從上往下拖pp.drawRect(x1,y1,abs(x2-x1),abs(y2-y1)) else: #從下往上拖pp.drawRect(x2,y2,abs(x1-x2),abs(y1-y2)) elif(self.draw_Type==enu_DrawType.DRAW_FILLRECT): #畫填充矩形模式if(x1<=x2): #從上往下拖pp.drawRect(x1,y1,abs(x2-x1),abs(y2-y1)) else: #從下往上拖pp.drawRect(x2,y2,abs(x1-x2),abs(y1-y2)) elif(self.draw_Type==enu_DrawType.DRAW_CIRCLE): #畫圓模式pp.setBrush(self.noPatter) #畫非填充圓時#計算出圓半徑,并更改結束點坐標已滿足最大圓D=min(abs(x2-x1),abs(y2-y1))if(x1<=x2):x2 = x1+Dy2 = y1+Delse:x2 = x1 - Dy2 = y1 - Dif(x1<=x2): #從上往下拖pp.drawEllipse(x1,y1,abs(x2-x1),abs(y2-y1)) else: #從下往上拖pp.drawEllipse(x2,y2,abs(x1-x2),abs(y1-y2)) elif(self.draw_Type==enu_DrawType.DRAW_ELLIPSE): #橢圓模式pp.setBrush(self.noPatter) #畫非填充圓時if(x1<=x2): #從上往下拖pp.drawEllipse(x1,y1,abs(x2-x1),abs(y2-y1)) else: #從下往上拖pp.drawEllipse(x2,y2,abs(x1-x2),abs(y1-y2)) elif(self.draw_Type==enu_DrawType.DRAW_FREE): #隨手畫模式# 根據鼠標指針前后兩個位置繪制直線self.bDrawOK=Truepp.drawLine(self.lastPoint, self.endPoint)# 讓前一個坐標值等于后一個坐標值,這樣就能實現畫出連續的線self.lastPoint = self.endPointelif(self.draw_Type==enu_DrawType.DRAW_TEXT): #畫文本模式#打開一個自定義子窗體,初始化錄入文本,也可采用類似CAD方式,在鼠標按下位置創建一編輯框控件實時進行編輯print('開始畫文本')if(len(self.lstText[0])>0):pp.setPen(QColor(self.lstText[2])) # 設置筆的顏色# 設置字體pp.setFont(self.lstText[3]) if(self.autoWidth):pp.drawText(QRect(self.lstText[1].x(),self.lstText[1].y(),self.newWidth,self.newHeight), Qt.AlignLeft, self.lstText[0])else: #限定繪制文本的范圍pp.drawText(self.lstText[1], Qt.AlignLeft, self.lstText[0])"""if(x1<=x2): #從上往下拖從X1,Y1開始畫文本#畫出文本pp.drawText(QRect(x1,y1,abs(x2-x1),abs(y2-y1)), Qt.AlignLeft, self.getSet('文本'))else: #從下往上拖,從X2,Y2開始畫文本pp.drawText(QRect(x2,y2,abs(x2-x1),abs(y2-y1)), Qt.AlignLeft, self.getSet('文本'))""" painter = QPainter(self)#繪制畫布到窗口指定位置處painter.drawPixmap(0, 0, self.pix)if(self.draw_Type!=enu_DrawType.DRAW_FREE or self.draw_Type!=enu_DrawType.DRAW_TEXT):self.bDrawOK=False# def mousePressEvent(self, event):"""鼠標按下事件重載"""if(self.draw_Type!=enu_DrawType.DRAW_FREE or self.draw_Type!=enu_DrawType.DRAW_TEXT):self.bDrawOK=False #關閉重繪事件print(f'當前坐標:x={event.pos().x()},y={event.pos().y()}')# 鼠標左鍵按下if event.button() == Qt.LeftButton:if(self.draw_Type==enu_DrawType.DRAW_TEXT):self.create_editor(event.pos()) #創建編輯框控件self.bLeftMouseKey=Trueself.lastPoint = event.pos()self.endPoint = self.lastPointself.edtCtlPosX = event.pos().x()self.edtCtlPosY = event.pos().y()+30 #沒對超出屏幕時作坐標處理。。。else:self.bLeftMouseKey=False#self.paintEvent() #防止畫文本時因創建了控件,已繪出的圖象沒有顯示# def mouseMoveEvent(self, event): """鼠標移動事件重載""" print(f'當前坐標:x={event.pos().x()},y={event.pos().y()}')if event.buttons() and self.bLeftMouseKey:if(self.draw_Type==enu_DrawType.DRAW_FREE): #僅隨手畫時要實時得到坐標位置并畫出self.endPoint = event.pos()# 進行重新繪制self.bDrawOK=True #打開重繪事件self.update()else:pass#print('非隨手畫模式請自行增加代碼來畫一臨時虛框顯示繪圖過程,但不真正繪會出來')# def mouseReleaseEvent(self, event):"""鼠標左鍵釋放事件重載"""print(f'當前坐標:x={event.pos().x()},y={event.pos().y()}')if event.button() == Qt.LeftButton:self.endPoint = event.pos()print(f'當前坐標:x={event.pos().x()},y={event.pos().y()}')# 進行重新繪制self.bDrawOK=Trueself.update()def create_editor(self, pos):"""創建可拖動的編輯框"""self.editor = DraggableLineEdit(self)#在父類中初步設置編輯框的字體等屬性self.editor.apply_font_properties(self.getSet('字體顏色'),self.getSet('字體名稱'),int(self.getSet('字號')),self.getSet('粗體'),self.getSet('斜體'),self.getSet('下劃線'),self.getSet('刪除線'))self.editor.setGeometry(pos.x(), pos.y(), 200, 40)self.editor.setPlaceholderText("輸入文本... (Alt+拖動移動)")self.editor.signal_sendDrawText.connect(self.getEditText)# 優化焦點獲取self.editor.setFocus()QTimer.singleShot(10, lambda: self.editor.setFocus() or self.editor.selectAll())# 設置樣式self.editor.setStyleSheet("""QLineEdit {border: 2px solid #3498db;border-radius: 8px;padding: 8px;background-color: #ffffff;font-size: 14px;selection-background-color: #3498db;selection-color: white;}QLineEdit:focus {border-color: #e74c3c;background-color: #fef9e7;}QLineEdit:hover {border-color: #9b59b6;}""")# 設置工具提示self.editor.setToolTip("Alt+鼠標左鍵拖動來移動\n點擊外部提交內容")self.editor.show()def getEditText(self,lstDatas):"""得到編輯框發送來的要繪制的文本數據['',QRect(x,y,w,h),QFont['字體',字號,加粗,下劃線,傾斜,傾斜線]]"""print(f'得到編輯框發送來的數據{lstDatas}')self.lstText=lstDatasspaceX=3 #文字間橫向間隔spaceY=6 #文字豎向間隔dpi=96self.newWidth=len(self.lstText[0])*(self.lstText[3].pointSize()+spaceX)self.newHeight=self.lstText[3].pointSize()+spaceY#字號同像素點的轉換def points_to_pixels(self,points, dpi):return points * dpi / 72.0def pixels_to_points(self,pixels, dpi):return pixels * 72.0 / dpi####################################################################################################
class DraggableLineEdit(QLineEdit):"""定義一個錄入文本的動態編輯框控件"""signal_sendDrawText = Signal(list) #自定信號:從編輯框中得到要繪制文本的數據(在編輯框失去焦點時發出信號)def __init__(self, parent=None):super().__init__(parent)self.dragging = Falseself.drag_start_position = QPoint()self.apply_font_properties('red') #構造時先應用默認值def mousePressEvent(self, event):# 當按下Alt鍵并點擊時開始拖動if event.modifiers() == Qt.AltModifier and event.button() == Qt.LeftButton:self.dragging = Trueself.drag_start_position = event.globalPosition().toPoint()self.initial_pos = self.pos()self.setCursor(Qt.ClosedHandCursor)event.accept()returnsuper().mousePressEvent(event)def mouseMoveEvent(self, event):"""鼠標在編輯框控件上移動時"""if self.dragging:# 計算鼠標移動距離并更新控件位置delta = event.globalPosition().toPoint() - self.drag_start_positionself.move(self.initial_pos + delta)event.accept()returnsuper().mouseMoveEvent(event)def mouseReleaseEvent(self, event):"""鼠標按下后釋放時"""if self.dragging and event.button() == Qt.LeftButton:self.dragging = Falseself.setCursor(Qt.IBeamCursor)event.accept()returnsuper().mouseReleaseEvent(event)def apply_font_properties(self,txtCol='black',fontName="微軟雅黑",fontSize=12,bBold=False,bItalic=False,bUnderLine=False,bStrikeOut=False):"""創建并配置字體 """self.font = QFont()self.font.setFamily(fontName) # 字體名稱self.font.setPointSize(fontSize) # 字號(磅)self.font.setBold(bBold) # 加粗self.font.setItalic(bItalic) # 斜體self.font.setUnderline(bUnderLine) # 下劃線self.font.setStrikeOut(bStrikeOut) # 刪除線self.txtCol=txtCol#使用QPalette設置顏色palette = QPalette()palette.setColor(QPalette.Text, QColor(self.txtCol)) # 暗紅色文本# 應用到字體self.setFont(self.font)#def focusOutEvent(self, event):"""當編輯框失去焦點時,各其父窗口發送信號,傳遞當前編輯框的文本,并在框當前位置處繪制出來"""print(f"錄入內容: {self.text()}")lstDatas=[self.text(),QRect(self.x(),self.y(),self.width(),self.height()),self.txtCol,self.font]self.signal_sendDrawText.emit(lstDatas)self.deleteLater()super().focusOutEvent(event)########################################################################################
if __name__ == '__main__':"""程序入口"""app = QApplication(sys.argv)form = MypaintWindow()form.show()sys.exit(app.exec())
程序用到的幾個圖像如下(位于代碼目錄的res子目錄下,文件名為t01.png~t08.png)