,,python3+PyQt5图形项的自定义和交互 python3实现page Designer应用程序

,,python3+PyQt5图形项的自定义和交互 python3实现page Designer应用程序

这篇文章主要为大家详细介绍了python3 PyQt5图形项的自定义和交互,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文通过Python3 PyQt5实现《python Qt Gui 快速编程》 这本书的页面设计者应用程序,采用QGraphicsView,QGraphicsScene,QGraphicsItem,这个程序包含有多个文本,图片和框的页面。有些图形类在PyQt5已过时,所以本代码改动幅度比较大。主要的类或方法的改变如下:

QMatrix==QTransform

setMatrix==setTransform

rotate==setRotation

本例中,由于event.delta()已过时,还重写了车轮事件方法:

定义车轮事件(自身,事件):

#因子=1.41 * *(-事件增量()/240.0)

# factor=1.41 * *(-ABS(事件。startx()-事件。y())/240.0)

factor=event.angleDelta().y()/120.0

if event.angleDelta().y()/120.0 0:

因子=2

否则:

因子=0.5

自我尺度(因子,因子)

为了保持代码可读行,增加了一个类:

类GraphicsPixmapItem(QGraphicsPixmapItem):#由杨荣东添加

def __init__(self,pixmap):

super(QGraphicsPixmapItem,self).__init__(点阵图)

本例中还有包含菜单的按钮:

if text=='Align ':

menu=QMenu(自身)

对于文本,在(

('左对齐,第四季度.AlignLeft),

('右对齐,第四季度.AlignRight),

('顶部对齐,第四季度.AlignTop),

('底部对齐,第四季度.AlignBottom)):

包装器=func工具。部分(自我。设置对齐,arg)

自我包装.追加(包装)

menu.addAction(文本、包装)

button.setMenu(菜单)

本例中还针对qstyleoptiongraphicsitem。详细程度已过时,改写如下:

选项。levelofdetailfromtransform(self。转换())

下面为完整的代码:

#!/usr/bin/env python3

导入功能工具

随机导入

导入系统

来自PyQt5 .QtCore导入(QByteArray,QDataStream,QFile,QFileInfo,

QIODevice,QPoint,QPointF,QRectF,Qt)

来自PyQt5 .QtWidgets导入(QApplication,QDialog,

QDialogButtonBox,QFileDialog,QFontComboBox,

QGraphicsItem,QGraphicsPixmapItem,

QGraphicsScene,QGraphicsTextItem,QGraphicsView,QGridLayout,

QHBoxLayout,QLabel,QMenu,QMessageBox,QPushButton,QSpinBox,

QStyle、QTextEdit、QVBoxLayout)

来自PyQt5 .QtGui导入QFont、QCursor、QFontMetrics、QTransform、QPainter、QPen、QPixmap

来自PyQt5 .QtPrintSupport导入QPrinter,QPrintDialog

MAC=真

尝试:

来自PyQt5 .QtGui导入qt_mac_set_native_menubar

除了导入错误:

MAC=假

#PageSize=(595,842) # A4磅

PageSize=(612,792) #美国磅字母

点数=10

MagicNumber=0x70616765

文件版本=1

脏=假

类TextItemDlg(QDialog):

def __init__(自身,项目=无,位置=无,场景=无,父项=无):

超级(QDialog,self).__init__(父级)

self.item=项目

自我定位=位置

self.scene=场景

self.editor=QTextEdit()

自我。编辑。setacceptrichtext(False)

自我。编辑。setabchangesfocus(True)

editorLabel=QLabel('Text:')

编辑器标签。设置好友(自我。编辑)

自我。font combobox=qfont combobox()

自我。字体组合框。setcurrentfont(q font(' Times ',PointSize))

fontLabel=QLabel('Font:')

字体标签。设置好友(自我。字体组合框)

self.fontSpinBox=QSpinBox()

自我。字体微调框。设置校准(Qt .对齐|Qt .AlignVCenter)

self.fontSpinBox.setRange(6,280)

自我。字体微调框。setvalue(点数)

fontSizeLabel=QLabel('Size:')

字体大小标签。设置好友(自我。fontspinbox)

自我。button box=QDialogButtonBox(QDialogButtonBox .好的|

QDialogButtonBox .取消)

自我。按钮盒。按钮(QDialogButtonBox .好的)。setEnabled(False)

如果自我项目不为无:

自我。编辑。设置laintext(self。项目。toplaintext())

自我。字体组合框。setcurrentfont(self。项目。字体())

自我。字体微调框。setvalue(自身。项目。字体().pointSize())

layout=QGridLayout()

layout.addWidget(editorLabel,0,0)

layout.addWidget(self.editor,1,0,1,6)

layout.addWidget(fontLabel,2,0)

布局。添加小部件(自我。字体组合框,2,1,1,2)

layout.addWidget(fontSizeLabel,2,3)

布局。添加小部件(自我。fontspinbox,2,4,1,2)

布局。添加小部件(自我。按钮盒,3,0,1,6)

self.setLayout(布局)

自我。字体组合框。currentfontchanged。连接(自我。更新用户界面)

自我。fontspinbox。值已更改。连接(自我。更新用户界面)

自我。编辑。文本已更改。连接(自我。更新用户界面)

自我。按钮盒。接受。连接(自我。接受)

自我。按钮盒。被拒。连接

self.setWindowTitle('页面设计器- {0}文本项')。格式(

"如果自我项目不是其他项目,则添加"编辑"))

self.updateUi()

def updateUi(自身):

font=self。字体组合框。当前字体()

字体。setpointsize(self。fontspinbox。value())

self.editor.document().setDefaultFont(字体)

自我。按钮盒。按钮(QDialogButtonBox .好的)。setEnabled(

bool(self.editor.toPlainText()))

定义接受(自身):

如果自我项目为无:

self.item=TextItem(' ',self.position,self.scene)

font=self。字体组合框。当前字体()

字体。setpointsize(self。fontspinbox。value())

self.item.setFont(font)

自我。项目。设置laintext(self。编辑。toplaintext())

self.item.update()

全局脏

脏=真

QDialog.accept(自我)

类TextItem(QGraphicsTextItem):

def __init__(自身,文本,位置,场景,

font=QFont('Times ',PointSize),matrix=QTransform()):

超级(TextItem,self).__init__(文本)

self.setFlags(QGraphicsItem .ItemIsSelectable|

QGraphicsItem .ItemIsMovable)

self.setFont(字体)

self.setPos(位置)

self.setTransform(矩阵)

场景. clearSelection()

scene.addItem(self)

self.setSelected(真)

全局脏

脏=真

def parentWidget(self):

返回self.scene().视图()[0]

定义项目变更(自身、变更、变体):

如果换!=QGraphicsItem .ItemSelectedChange:

全局脏

脏=真

返回qgraphicstextitem。项目变更(自身、变更、变体)

def mouseDoubleClickEvent(self,Event):

dialog=TextItemDlg(self,self.parentWidget())

dialog.exec_()

类GraphicsPixmapItem(QGraphicsPixmapItem):#由杨荣东添加

def __init__(self,pixmap):

super(QGraphicsPixmapItem,self).__init__(点阵图)

类BoxItem(QGraphicsItem):

def __init__(self,position,scene,style=Qt .实线,

rect=None,matrix=QTransform()):

超级(BoxItem,self).__init__()

self.setFlags(QGraphicsItem .ItemIsSelectable|

QGraphicsItem .ItemIsMovable|

QGraphicsItem .ItemIsFocusable)

如果矩形为无:

rect=QRectF(-10 * PointSize,-PointSize,20 * PointSize,

2 *磅值)

self.rect=rect

自我风格=风格

self.setPos(位置)

self.setTransform(矩阵)

scene.clearSelection()

scene.addItem(self)

self.setSelected(真)

self.setFocus()

全局脏

脏=真

def parentWidget(self):

返回self.scene().视图()[0]

def boundingRect(self):

返回自校正(-2,-2,2,2)

定义绘画(自身、绘画、选项、小部件):

pen=QPen(self.style)

钢笔颜色(黑色)

pen.setWidth(1)

if option.state QStyle .状态_选定:

钢笔设置颜色(蓝色)

painter.setPen(钢笔)

painter.drawRect(self.rect)

定义项目变更(自身、变更、变体):

如果换!=QGraphicsItem .ItemSelectedChange:

全局脏

脏=真

返回QGraphicsItem.itemChange(自身、变更、变体)

def contextMenuEvent(self,Event):

wrapped=[]

menu=QMenu(self.parentWidget())

对于文本,参数输入(

('固,第四季度.实线),

('虚线,第四季度.仪表板线),

('点'的,第四季度.点线),

('虚线点,第四季度.虚线),

(' DashDotDotted ',Qt .DashDotDotLine)):

包装器=func工具。部分(自我。设置样式,参数)

wrapped.append(包装)

menu.addAction(文本,包装)

menu.exec_(event.screenPos())

def setStyle(self,Style):

自我风格=风格

self.update()

全局脏

脏=真

def keyPressEvent(self,Event):

因子=点数/4

已更改=假

if event.modifiers() Qt .变化修饰符:

if event.key()==Qt .向左键:

自我。直肠。设置正确(自我。直肠。右()-因子)

已更改=真

elif event.key()==Qt .右键:

自我。直肠。设置正确(自我。直肠。右()因子)

已更改=真

elif event.key()==Qt .向上键:

自我。直肠。设置底部(自我。直肠。底部()-因子)

已更改=真

elif event.key()==Qt .向下键:

自我。直肠。设置底部(自我。直肠。底部()因子)

已更改=真

如果更改:

self.update()

全局脏

脏=真

否则:

qgraphicsitem。按键事件(自身,事件)

类图形视图(QGraphicsView):

def __init__(self,parent=None):

超级(图形视图,自我).__init__(父级)

self.setDragMode(QGraphicsView .橡皮带拖动)

self.setRenderHint(QPainter .抗锯齿)

self.setRenderHint(QPainter .文本抗锯齿)

定义车轮事件(自身,事件):

#因子=1.41 * *(-事件增量()/240.0)

factor=event.angleDelta().y()/120.0

if event.angleDelta().y()/120.0 0:

因子=2

否则:

因子=0.5

自我尺度(因子,因子)

类主窗体(QDialog):

def __init__(self,parent=None):

超级(主窗体,自我).__init__(父级)

self.filename=' '

self.copiedItem=QByteArray()

self.pasteOffset=5

self.prevPoint=QPoint()

self.addOffset=5

self.borders=[]

self.printer=QPrinter(QPrinter .高分辨率)

自我。打印机。setpagesize(q打印机.信)

self.view=GraphicsView()

self.scene=QGraphicsScene(self)

自我。场景。sets center(0,0,PageSize[0],PageSize[1])

self.addBorders()

self.view.setScene(自我场景)

self.wrapped=[] #需要保持包装器活动

buttonLayout=QVBoxLayout()

对于文本,插入(

('添加文本,self.addText),

('添加框,self.addBox),

('添加像素图,self.addPixmap),

('对齐,无),

(' Copy ',self.copy),

('切自切),

(' Paste ',self.paste),

('删除.',self.delete),

(' Rotate ',self.rotate),

('打印.',self.print_),

('打开……'self.open),

(' Save ',self.save),

(' Quit ',self.accept)):

按钮=按钮(文本)

如果不是MAC:

setFocusPolicy(Qt .无焦点)

如果插槽不为无:

button.clicked.connect(插槽)

if text=='Align ':

menu=QMenu(自身)

对于文本,在(

('左对齐,第四季度.AlignLeft),

('右对齐,第四季度.AlignRight),

('顶部对齐,第四季度.AlignTop),

('底部对齐,第四季度.AlignBottom)):

包装器=func工具。部分(自我。设置对齐,arg)

自我包装.追加(包装)

menu.addAction(文本、包装)

button.setMenu(菜单)

如果text=='打印. ':

buttonLayout.addStretch(5)

if text=='Quit ':

buttonLayout.addStretch(1)

buttonLayout.addWidget(按钮)

buttonLayout.addStretch()

layout=QHBoxLayout()

layout.addWidget(self.view,1)

layout.addLayout(buttonLayout)

self.setLayout(布局)

fm=QFontMetrics(self.font())

自我。调整大小(自身。场景。宽度()FM。宽度('删除. ')) 50,

self.scene.height() 50)

self.setWindowTitle('页面设计器)

def addBorders(自身):

self.borders=[]

rect=QRectF(0,0,PageSize[0],PageSize[1])

自我。边框。追加(自我。场景。添加rect(rect,Qt.yellow))

边距=5.25 *磅值

自我。边框。追加(自我。场景。添加矩形(

rect.adjusted(margin,margin,-margin,-margin),

黄色))

def移除边框(自身):

而自我边界:

item=self.borders.pop()

self.scene.removeItem(item)

删除项目

定义拒绝(自身):

自我接受()

定义接受(自身):

self.offerSave()

QDialog.accept(自我)

def offerSave(self):

if(Dirty和qmessagebox。问题(自我,

页面设计器-未保存的更改,

保存未保存的更改吗?

QMessageBox .是|QMessageBox .否)==

QMessageBox .是):

self.save()

定义位置(自身):

点=自我。mapfromglobal(q光标。pos())

如果不是self.view.geometry().包含(点):

coord=random.randint(36,144)

point=QPoint(坐标,坐标)

否则:

如果point==self.prevPoint:

point=QPoint(self.addOffset,self.addOffset)

self.addOffset=5

否则:

self.addOffset=5

self.prevPoint=point

返回self.view.mapToScene(点)

def addText(自身):

dialog=TextItemDlg(position=self。位置(),

scene=self.scene,parent=self)

dialog.exec_()

定义添加框(自身):

BoxItem(self.position()、self.scene)

def addPixmap(自身):

path=(QFileInfo(self.filename).路径()

if self.filename else ' . ')

fname,filetype=qfiledialog。获取打开的文件名(自身、

页面设计器-添加像素图,路径,

像素映射文件(*。bmp * .jpg * .png * .xpm)')

如果不是名称:

返回

自我。createpixmapitem(qpix map(fname),self.position())

def createPixmapItem(self,pixmap,position,matrix=QTransform()):

item=GraphicsPixmapItem(pixmap)

item.setFlags(QGraphicsItem .ItemIsSelectable|

QGraphicsItem .ItemIsMovable)

item.setPos(位置)

item.setTransform(矩阵)

self.scene.clearSelection()

self.scene.addItem(项目)

item.setSelected(True)

全局脏

脏=真

退货项目

def selectedItem(self):

items=self.scene.selectedItems()

如果len(items)==1:

返回项目[0]

不返回

定义副本(自身):

item=self.selectedItem()

如果项目为无:

返回

self.copiedItem.clear()

self.pasteOffset=5

stream=QDataStream(self。复制设备.只写)

self.writeItemToStream(stream,item)

定义切割(自我):

item=self.selectedItem()

如果项目为无:

返回

self.copy()

self.scene.removeItem(item)

删除项目

定义粘贴(自身):

if self.copiedItem.isEmpty():

返回

stream=QDataStream(self。复制设备.只读)

self.readItemFromStream(stream,self.pasteOffset)

self.pasteOffset=5

定义setAlignment(自身,对齐):

#项以任意顺序返回

items=self.scene.selectedItems()

如果len(项目)=1:

返回

#收集坐标数据

leftXs,rightXs,topYs,bottomYs=[],[],[],[]

对于项目中的项目:

rect=item.sceneBoundingRect()

leftXs.append(rect.x())

右x。追加(rect。x()rect。宽度())

topYs.append(rect.y())

底部ys。追加(rect。y()矩形。高度())

#执行校准

如果对齐==Qt .对齐左侧:

xAlignment=min(leftXs)

对于我,枚举中的项(项):

项目。移动方式(x对齐-左xs[I],0)

否则如果对齐==Qt .对齐权:

xAlignment=max(rightXs)

对于我,枚举中的项(项):

项目。移动方式(x对齐-右xs[I],0)

否则如果对齐==Qt .AlignTop:

yAlignment=min(topYs)

对于我,枚举中的项(项):

item.moveBy(0,yAlignment - topYs[i])

否则如果对齐==Qt .对齐底部:

yAlignment=max(bottomYs)

对于我,枚举中的项(项):

item.moveBy(0,yAlignment - bottomYs[i])

全局脏

脏=真

定义旋转(自身):

对于self.scene.selectedItems()中的项目:

项目。设置旋转(项目。旋转()30度)

定义删除(自己):

items=self.scene.selectedItems()

if (len(items)和QMessageBox.question(self,

页面设计者-删除,

删除{0}项{1}?格式(len(items)、

s' if len(items)!=1 else ' '),

QMessageBox .是|QMessageBox .否)==

QMessageBox .是):

在…期间项目:

item=items.pop()

self.scene.removeItem(item)

删除项目

全局脏

脏=真

定义打印_(自我):

dialog=qprindialog(self。打印机)

if dialog.exec_():

painter=QPainter(自助打印机)

painter.setRenderHint(QPainter .抗锯齿)

painter.setRenderHint(QPainter .文本抗锯齿)

self.scene.clearSelection()

self.removeBorders()

self.scene .渲染(画家)

self.addBorders()

定义打开(自身):

self.offerSave()

path=(QFileInfo(self.filename).路径()

if self.filename else ' . ')

fname,filetype=qfiledialog。获取打开的文件名(自身、

页面设计器-打开,路径,

页面设计器文件(*。pgd)')

如果不是名称:

返回

self.filename=fname

fh=无

尝试:

fh=QFile(self.filename)

如果不是fh.open(QIODevice .只读):

引发IOError(str(fh.errorString()))

items=self.scene.items()

在…期间项目:

item=items.pop()

self.scene.removeItem(item)

删除项目

self.addBorders()

stream=QDataStream(fh)

stream.setVersion(QDataStream .Qt_5_7)

magic=stream.readInt32()

如果魔法!=魔术编号:

引发IOError('不是有效的100 . PGD文件)

fileVersion=stream.readInt16()

if fileVersion!=文件版本:

引发IOError('无法识别100 . PGD文件版本)

而不是fh.atEnd():

self.readItemFromStream(流)

除了IOError作为e:

QMessageBox.warning(self,'页面设计器-打开错误,

未能打开{0}: {1}。格式(self.filename,e))

最后:

如果消防栓(Fire Hydrant的缩写)不为无:

fh.close()

全局脏

脏=假

定义保存(自己):

如果不是self .文件名:

路径="."

fname,filetype=qfiledialog。getsave文件名(自身,

网页设计器-另存为,路径,

页面设计器文件(*。pgd)')

如果不是名称:

返回

self.filename=fname

fh=无

尝试:

fh=QFile(self.filename)

如果不是fh.open(QIODevice .只写):

引发IOError(str(fh.errorString()))

self.scene.clearSelection()

stream=QDataStream(fh)

stream.setVersion(QDataStream .Qt_5_7)

stream.writeInt32(MagicNumber)

stream.writeInt16(文件版本)

对于self.scene.items()中的项目:

self.writeItemToStream(stream,item)

除了IOError作为e:

QMessageBox.warning(self,'页面设计器-保存错误,

未能保存{0}: {1}。格式(self.filename,e))

最后:

如果消防栓(Fire Hydrant的缩写)不为无:

fh.close()

全局脏

脏=假

def readItemFromStream(self,Stream,offset=0):

类型=' '

position=QPointF()

matrix=QTransform()

rotateangle=0 #由杨荣东添加

type=stream.readQString()

流位置矩阵

如果偏移:

位置=QPointF(偏移量,偏移量)

如果type=='Text ':

text=' '

font=QFont()

text=stream.readQString()

流字体

rotateangle=stream.readFloat()

tx=TextItem(文本,位置,自身场景,字体,矩阵)

tx.setRotation(旋转角度)

elif type=='Box ':

rect=QRectF()

流矩形

style=Qt .PenStyle(stream.readInt16())

rotateangle=stream.readFloat()

bx=BoxItem(position,self.scene,style,rect,matrix)

bx.setRotation(rotateangle)

elif type=='Pixmap ':

pixmap=QPixmap()

流像素图

rotateangle=stream.readFloat()

px=自我。createpixmapitem(像素映射,位置,矩阵)

px.setRotation(rotateangle)

def writeItemToStream(self,Stream,item):

if isinstance(item,TextItem):

stream.writeQString('Text ')

streamitem.pos() item.transform()

溪流。writeqstring(item。toplaintext())

stream item.font()

溪流。写浮点型(项目。rotation())# add by杨荣东

elif isinstance(item,GraphicsPixmapItem):

stream.writeQString('Pixmap ')

流项目。pos()项目。transform()项。像素图()

溪流。写浮点型(项目。rotation())# add by杨荣东

elif isinstance(item,BoxItem):

stream.writeQString('Box ')

流项目。pos()项目。transform()项。矩形

stream.writeInt16(item.style)

溪流。写浮点型(项目。rotation())# add by杨荣东

app=QA应用程序(sys。argv)

form=MainForm()

rect=QApplication.desktop().可用几何法()

形式。resize(int(rect。width()* 0.6)、int(rect.height() * 0.9))

form.show()

app.exec_()

运行结果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: