十分简单的一个画板程序,用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=0
DRAW_LINE=1
DRAW_RECT=2
DRAW_FILLRECT=3
DRAW_CIRCLE=4
DRAW_ELLIPSE=5
DRAW_FREE=6
DRAW_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_LINE
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:画矩形
def draw_Rect(self):
print('画矩形')
self.label_Draw.draw_Type=enu_DrawType.DRAW_RECT
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:画矩形
def draw_FillRect(self):
print('画填充矩形')
self.label_Draw.draw_Type=enu_DrawType.DRAW_FILLRECT
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:画园
def draw_Circle(self):
print('画圆')
self.label_Draw.draw_Type=enu_DrawType.DRAW_CIRCLE
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:画椭圆
def draw_Ellptic(self):
print('画椭圆')
self.label_Draw.draw_Type=enu_DrawType.DRAW_ELLIPSE
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:随手画
def Draw_Free(self):
print('随手画')
self.label_Draw.draw_Type=enu_DrawType.DRAW_FREE
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:画文本
def draw_Text(self):
print('画文本')
self.label_Draw.draw_Type=enu_DrawType.DRAW_TEXT
cursor = QCursor(Qt.CrossCursor)
self.setCursor(cursor)
#槽函数:退出绘图模式
def draw_Quit(self):
print('退出绘图模式')
self.label_Draw.draw_Type=enu_DrawType.DRAW_NO
cursor = 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=0
self.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传递给label
self.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=0
self.newHeight=0
self.autoWidth=True #文字过长时是否自动加宽绘制文本的矩形框
#
def getLineType(self,typeTxt='实线'):
"""
得到画线类型
"""
linetype=Qt.SolidLine
if(typeTxt==self.lst_LineType[0]):linetype=Qt.SolidLine
elif(typeTxt==self.lst_LineType[1]):linetype=Qt.DashLine
elif(typeTxt==self.lst_LineType[2]):linetype=Qt.DotLine
elif(typeTxt==self.lst_LineType[3]):linetype=Qt.DashDotLine
elif(typeTxt==self.lst_LineType[4]):linetype=Qt.DashDotLine
elif(typeTxt==self.lst_LineType[5]):linetype=Qt.DashDotDotLine
else: linetype=Qt.SolidLine
return linetype
#
def getFillType(self,typeTxt='纯色'):
"""
得到填充类型
"""
filltype=Qt.SolidPattern
if(typeTxt==self.lst_FillType[0]):filltype=Qt.SolidPattern
elif(typeTxt==self.lst_FillType[1]):filltype=Qt.Dense1Pattern
elif(typeTxt==self.lst_FillType[2]):filltype=Qt.Dense2Pattern
elif(typeTxt==self.lst_FillType[3]):filltype=Qt.Dense3Pattern
elif(typeTxt==self.lst_FillType[4]):filltype=Qt.Dense4Pattern
elif(typeTxt==self.lst_FillType[5]):filltype=Qt.Dense5Pattern
elif(typeTxt==self.lst_FillType[6]):filltype=Qt.Dense6Pattern
elif(typeTxt==self.lst_FillType[7]):filltype=Qt.Dense7Pattern
elif(typeTxt==self.lst_FillType[8]):filltype=Qt.HorPattern
elif(typeTxt==self.lst_FillType[9]):filltype=Qt.VerPattern
elif(typeTxt==self.lst_FillType[10]):filltype=Qt.CrossPattern
elif(typeTxt==self.lst_FillType[11]):filltype=Qt.DiagCrossPattern
elif(typeTxt==self.lst_FillType[12]):filltype=Qt.BDiagPattern
elif(typeTxt==self.lst_FillType[13]):filltype=Qt.FDiagPattern
else: filltype=Qt.SolidPatter
return filltype
def getSet(self,setName):
"""
从字典变量得到设置值,有错误时得到默认值,仅为示例,可以通过读取INI文件或注册表来得到初始设置值
"""
if(setName=='线型'): defValue='SolidLine'
elif(setName=='线宽'): defValue=2
elif(setName=='线颜色'): defValue='black'
elif(setName=='画刷类型'): defValue='SolidPattern'
elif(setName=='填充色'): defValue='blue'
elif(setName=='文本'): defValue='示例文本内容'
elif(setName=='字体名称'): defValue='宋体'
elif(setName=='字号'): defValue=12
elif(setName=='粗体'): defValue=False
elif(setName=='斜体'): defValue=False
elif(setName=='下划线'): defValue=False
elif(setName=='删除线'): defValue=False
elif(setName=='字体颜色'): defValue='black'
else: print('无此设置项')
value = self.dic_Set.get(setName, defValue)
return value
#
def SetValue(self,setName,value):
"""
运行中设置配置值
"""
self.dic_Set[setName]=value
def 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): #此绘画开关没打开前,避免误画图形
return
if(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+D
y2 = y1+D
else:
x2 = x1 - D
y2 = y1 - D
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_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=True
pp.drawLine(self.lastPoint, self.endPoint)
# 让前一个坐标值等于后一个坐标值,这样就能实现画出连续的线
self.lastPoint = self.endPoint
elif(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=True
self.lastPoint = event.pos()
self.endPoint = self.lastPoint
self.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=True
self.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=lstDatas
spaceX=3 #文字间横向间隔
spaceY=6 #文字竖向间隔
dpi=96
self.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.0
def 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 = False
self.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 = True
self.drag_start_position = event.globalPosition().toPoint()
self.initial_pos = self.pos()
self.setCursor(Qt.ClosedHandCursor)
event.accept()
return
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
"""
鼠标在编辑框控件上移动时
"""
if self.dragging:
# 计算鼠标移动距离并更新控件位置
delta = event.globalPosition().toPoint() - self.drag_start_position
self.move(self.initial_pos + delta)
event.accept()
return
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
"""
鼠标按下后释放时
"""
if self.dragging and event.button() == Qt.LeftButton:
self.dragging = False
self.setCursor(Qt.IBeamCursor)
event.accept()
return
super().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)