python+pyside6的簡易畫板

十分簡單的一個畫板程序,用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)

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

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

相關文章

【數據可視化-76】從釋永信被查,探索少林寺客流量深度分析:Python + Pyecharts 炫酷大屏可視化(含完整數據和代碼)

&#x1f9d1; 博主簡介&#xff1a;曾任某智慧城市類企業算法總監&#xff0c;目前在美國市場的物流公司從事高級算法工程師一職&#xff0c;深耕人工智能領域&#xff0c;精通python數據挖掘、可視化、機器學習等&#xff0c;發表過AI相關的專利并多次在AI類比賽中獲獎。CSDN…

WPF TreeView自帶自定義滾動條

放在TreeView.Resources中&#xff1a;<Style TargetType"ScrollBar"><Setter Property"Stylus.IsPressAndHoldEnabled" Value"false"/><Setter Property"Stylus.IsFlicksEnabled" Value"false"/><Set…

MongoDB 詳細用法與 Java 集成完整指南

MongoDB 詳細用法與 Java 集成完整指南 目錄 MongoDB 基礎概念MongoDB 安裝與配置MongoDB Shell 基本操作Java 環境準備Java MongoDB 驅動集成連接配置基本 CRUD 操作高級查詢操作索引操作聚合管道事務處理Spring Boot 集成最佳實踐 1. MongoDB 基礎概念 1.1 核心概念對比 …

【Flutter3.8x】flutter從入門到實戰基礎教程(四):自定義實現一個自增的StatefulWidget組件

fluttet中實現一個自定義的StatefulWidget組件&#xff0c;可以在數據變化后&#xff0c;把最新的頁面效果展示給客戶 實現效果實現代碼 pages文件夾下新加一個counter_page.dart文件 class CounterPage extends StatefulWidget {const CounterPage({super.key});overrideState…

[AI8051U入門第十三步]W5500實現MQTT通信

前言 學習目標: 1、學習MQTT協議 2、了解MQTT數據幀格式 3、自己編寫MQTT程序 4、調試MQTT程序一、MQTT協議介紹 MQTT(Message Queuing Telemetry Transport) 是一種輕量級的 發布/訂閱(Pub/Sub) 消息傳輸協議,專為 低帶寬、高延遲或不可靠網絡 環境設計,廣泛應用于 物…

四、基于SpringBoot,MVC后端開發筆記

整合第三方技術&#xff1a; 1、整合Junit (1)名稱&#xff1a;SpringBootTest (2)類型&#xff1b;測試類注解 (3)位置&#xff1a;測試類定義上方 (4)作用&#xff1a;設置Junit加載的SpringBoot啟動類 (5)相關屬性&#xff1a;classes&#xff1a;設置SpringBoot啟動類 2、整…

深入講講異步FIFO

一、異步 FIFO 的基本概念1.1 定義與核心作用異步 FIFO&#xff08;Asynchronous FIFO&#xff09;是一種讀寫時鐘完全獨立的先進先出&#xff08;First-In-First-Out&#xff09;數據緩沖器&#xff0c;主要用于跨時鐘域數據傳輸場景。在數字系統中&#xff0c;當兩個模塊工作…

linux81 shell通配符:[list],‘‘ ``““

shell 文件處理工具 grep 別名顯示顏色 grep --colorauto ‘root’ passwd alias grep‘grep --colorauto’ vim /etc/bashrc alias grep‘grep --colorauto’ source /etc/bashrc [rootsamba tmp]# grep --colorauto root 2.txt root:x:0:0:root:/root:/bin/bash operator:x:1…

CMake、CMakeLists.txt 基礎語法

前言 代碼變成可執行文件&#xff0c;叫做編譯&#xff08;compile&#xff09;&#xff1b;先編譯這個&#xff0c;還是先編譯那個&#xff08;即編譯的安排&#xff09;&#xff0c;叫做構建&#xff08;build&#xff09;。CMake是最常用的構建工具&#xff0c;誕生于1977年…

《文明5》錯誤代碼0xc0000142修復方法

只要是錯誤代碼為0xc0000142&#xff1f;不管是哪種錯誤&#xff0c;都是一樣的。 修復方法有很多&#xff0c;我先推薦個人認為比較好用的修復方法 方式一&#xff1a;第三方軟件修復&#xff1a; 地址在這里獲取&#xff1a;修復軟件點這里 添加圖片注釋&#xff0c;不超過 …

【Java面試題】緩存穿透

什么是緩存穿透 緩存穿透是指當秒殺請求在Redis中未命中緩存時&#xff0c;系統會轉而查詢數據庫。若數據庫中也不存在該數據&#xff0c;大量此類請求將直接沖擊數據庫&#xff0c;造成數據庫負載激增。解決方案 緩存空值 當我們查詢數據庫發現數據庫當中也不存在該數據時&…

SpringBoot與Rust實戰指南

基于Spring Boot和Rust的實用 以下是基于Spring Boot和Rust的實用示例,涵蓋常見開發場景,分為Spring Boot(Java)和Rust兩部分: Spring Boot 示例 RESTful API 開發 @RestController @RequestMapping("/api") public class UserController {@GetMapping("…

【世紀龍科技】汽車整車維護仿真教學軟件-智構整車維護實訓

在職業院校汽車專業實訓教學中&#xff0c;"設備損耗大、操作風險高、場景覆蓋有限"三大痛點長期制約著教學質量提升——傳統實訓車間里&#xff0c;學生接觸實車的機會受限于車輛臺套數與維護周期&#xff0c;復雜工位流程難以反復演練&#xff1b;高危操作環節&…

CMake set_source_files_properties使用解析

set_source_files_properties() 是 CMake 中用于精細化控制源文件屬性的多功能命令。除了設置編譯標志外&#xff0c;它還有許多其他重要用途。以下是全面的用法解析&#xff1a;一、核心功能分類 1. 編譯控制 編譯器選項&#xff1a;COMPILE_FLAGS / COMPILE_OPTIONSset_sourc…

雷達微多普勒特征代表運動中“事物”的運動部件。

雷達微多普勒特征代表運動中“事物”的運動部件。 即使一個人在椅子上來回搖晃&#xff0c;肉眼看來這個動作也很簡單。但對雷達來說&#xff0c;這是微動作的豐富混合&#xff1a;移動膝蓋和腿、擺動手臂&#xff0c;甚至是傾斜的椅子。所有這些都會產生獨特但復雜的微多普勒特…

FreeRTOS硬件中斷發生時的現場

在FreeRTOS中&#xff0c;當硬件中斷發生時&#xff0c;當前正在運行的任務會立即被掛起&#xff0c;處理器會跳轉到中斷相關的中斷服務程序中&#xff0c;在中斷服務程序執行期間&#xff0c;遵循以下規則&#xff1a;1、中斷獨占CPU&#xff0c;ISR擁有最高的執行優先級&…

kotlin語法和特性分析

核心設計哲學&#xff1a; 簡潔 (Concise): 減少樣板代碼&#xff08;如 getter/setter、類型推導&#xff09;&#xff0c;讓代碼表達更直接。安全 (Safe): 從語言層面設計來避免常見錯誤&#xff08;尤其是空指針異常&#xff09;。互操作性 (Interoperable): 與 Java 無縫集…

二進制數本身沒有默認的有符號或無符號解釋

文章目錄1. ?**?硬件層面&#xff1a;CPU 不區分有符號/無符號?**?2. ?**?解釋權在程序員手中?**?3. ?**?默認傾向性&#xff08;非絕對規則&#xff09;?**?4. ?**?如何避免混淆&#xff1f;?**?5. ?**?經典示例?**?總結1. **解釋為無符號數&#xff08;U…

(AI) Server (Hardware) Architecture

Overview by Atlas T800 Just found a good product demo. from Huawei for its Atlas T800, here 計算產品3D展示 First turn off all modules and we can delve into how this server is organized. Core This is an AI server with 910B as its main feature, which is …

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - 微博評論數據可視化分析-用戶評論詞云圖實現

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解微博評論數據可視化分析-用戶評論詞云圖實現…