实战PyQt5: 084-图形视图框架的关键特性
yuyutoo 2024-10-19 11:09 2 浏览 0 评论
缩放与旋转
QGraphicsView通过QGraphicsView.setMatrix()支持同QPainter相同的仿射变换,通过对一个视图应用变换,可以很容易地支持普通的导航功能(如缩放与旋转)。下面的例子演示了如何在QGraphicsView的子类中实现缩放和旋转。
class MyView(QGraphicsView):
def zoomIn(self):
self.scale(1.2, 1.2)
def zoomOut(self):
self.scale(1/1.2, 1/1.2)
def rotateLeft(self):
self.rotate(-10)
def rotateRight(self)
self.rotate(10)
这些槽函数可以在启用了autoRepeat的情况下连接到QToolButtons。当对视图进行变换时,QGraphicsView可使视图的中心对齐。
打印
图形视图通过其渲染函数QGraphicsScene.render()和QGraphicsView.render()提供单行打印。这些函数提供相同的API:通过将QPainter传递给任一渲染函数,可以使场景或视图将其全部或部分内容渲染到任何绘画设备中。下面示例说明如何使用QPrinter将整个场景打印成整页。
scene = QGraphicsScene()
printer = QPrinter()
scene.addRect(QRect(0,0,100,200), QPen(Qt.black), QBrush(Qt.green)
if QPrintDialog(printer).exec() == QDialog.Accepted:
painter = QPainter(printer)
painter.setRenderHint(QPainter.Antialiasing)
scene.render(painter)
del painter
场景和视图渲染功能之间的区别在于,一个在场景坐标中运行,另一个在视图坐标中运行。QGraphicsScene.render()通常是打印未变换的场景的整个片段(例如,绘制几何数据或打印文本文档)的首选。另一方面,QGraphicsView.render()适合截图,它的默认行为是使用提供的painter渲染视口的确切内容。
scene = QGraphsScene()
scene.addRect(QRectF(0,0,100, 200), QPen(Qt.black), QBrush(Qt.green))
pixmap = QPixmap()
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
scene.render(painter)
painter.end()
pixmap.save('scene.png')
当源区域和目标区域的大小不匹配时,将拉伸源内容以适合目标区域。通过将Qt.AspectRatioMode传递给正在使用的渲染函数,可以选择在拉伸内容时保持或忽略场景的宽高比。
拖放
由于QGraphicsView间接继承了QWidget,因此它也提供了与QWidget提供的拖放功能相同的功能。另外,为方便起见,图形视图框架为场景以及每个图元提供拖放支持。当视图接收到拖放事件时,它将拖放事件转换为QGraphicsSceneDragDropEvent,然后将其转发到场景。场景将接管此事件的调度,并将其发送到接受放置的鼠标光标下的第一个图元。
要从一个图元开始拖动,请创建QDrag对象,并传递到开始拖动的部件。可以同时通过多个视图观察图元,但是只有一个视图可以开始拖动。在大多数情况下,拖动是由于按下或移动鼠标而开始的,因此在mousePressEvent()或mouseMoveEvent()中,可以从事件中得到原始的窗口部件对象。例如:
def mousePressEvent(self, event):
data = QMimeData()
drag = QDrag(event.widget())
drag.setMimeData(data)
drag.exec()
为了在场景中拦截拖放事件,必须重新实现QGraphicsScene.dragEnterEvent()和在QGraphicsItem的子类里任何与特定场景需要的事件处理器。items也可以通过调用QGraphicsItem.setAcceptDrops()获得拖放支持,为了处理将进行的拖放事件,需要重新实现QGraphicsItem.dragEnterEvent(), QGraphicsItem.dragMoveEvent(), QGraphicsItem.dragLeaveEvent() 和QGraphicsItem.dropEvent()。
光标和工具信息提示
像QWidget一样,QGraphicsItem也支持光标(QgraphicsItem.setCursor)与工具信息提示(QGraphicsItem.setToolTip())。当光标进入到图元的区域,光标与工具信息提示被QGraphicsView激活(通过调用QGraphicsItem.contains()检测)。也可以通过调用QGraphicsView.setCursor()直接在视图上设置一个缺省光标。
动画
图形视图支持多个级别的动画。因此可以使用动画框架轻松地组装动画。图元只需要继承来自QGraphicsObject和QPropertyAnimation与之关联任何可以实施动画的QObject属性即可。
另一个选择是创建一个继承自QObject和QGraphicsItem的自定义项。该项目可以设置自己的计时器,并通过QObject.timerEvent()中的增量步骤控制动画。
第三个选项是通过调用QGraphicsScene.advance()来实施场景动画,QGraphicsScene.advance()会依次调用QGraphicsItem.advance()。
OpenGL渲染
要启用OpenGL渲染,只需调用QGraphicsView.setViewport()即可将新的QOpenGLWidget设置为QGraphicsView的视口。如果要让OpenGL提供抗锯齿功能,则需要使用QSurfaceFormat.setSamples()来设置所需的样本数。 例如:
view = QGraphics(scene)
gl = QOpenGLWidget()
format = QSurfaceFormat()
format.setSamples(4)
gl.setFormat(format)
view.setViewport(gl)
图元组(Item Group)
通过使一个图元成为另一个图元的子项,可以实现图元组的最基本特征:这些图元将一起移动,并且所有转换都从父图元传递到子图元。
另外,QGraphicsItemGroup是一个特殊项,它将子事件处理与一些接口相结合,用于在组中添加项或从组中删除图元。将图元添加到QGraphicsItemGroup中将保留该图元的原始位置和变换,而通常情况下新的父图元会导致子级图元相对于其新的父级图元而重新定位。方便起见,可以通过调用QGraphicsScene.createItemGroup()在整个场景中创建QGraphicsItemGroup。
部件和布局
Qt通过QGraphicsWidget引入了对几何形状和布局感知项的支持。这个特殊的基本图元类似于QWidget,但是与QWidget不同,它继承自QGraphicsItem不是继承自QPaintDevice继承。这允许我们可以编写带有事件,信号和插槽,大小提示和策略的完整窗口部件,还可以通过QGraphicsLinearLayout和QGraphicsGridLayout管理布局中的窗口部件。
QGraphicsWidget
基于QGraphicsItem,QGraphicsWidget提供了两全其美的功能:QWidget的其他功能,例如样式,字体,调色板,布局方向及其几何形状,以及QGraphicsItem的分辨率独立性和转换支持。由于图形视图使用实数坐标而不是整数,因此QGraphicsWidget的几何形状函数也可以在QRectF和QPointF上运行。这也适用于框架矩形,边距和间距。例如使用QGraphicsWidget,通常指定(0.5、0.5、0.5、0.5)的内容边距。可以创建子部件和“顶层”窗口。在某些情况下,可以将图形视图用于高级MDI应用程序。
QGraphicsWidget支持一些QWidget的属性(包括窗口标志和属性,但不是全部)。例如,可以通过将Qt.Window窗口标志传递给QGraphicsWidget的构造函数来创建和装饰窗口,但是图形视图当前不支持macOS上常见的Qt.Sheet和Qt.Drawer标志。
QGraphicsLayout
QGraphicsLayout是专门为QGraphicsWidget设计的布局框架的一部分。其API与QLayout非常相似。可以在QGraphicsLinearLayout和QGraphicsGridLayout内部管理部件和子布局。还可以通过自己子类化QGraphicsLayout轻松地编写自己的布局,或者通过编写QGraphicsLayoutItem的适配器子类将自己的QGraphicsItem项目添加到布局中。
支持部件嵌入
图形视图对将任何部件嵌入场景提供了无缝支持。可以嵌入简单的部件(例如QLineEdit或QPushButton),复杂的小部件(例如QTabWidget)甚至完整的主窗口。要将部件嵌入场景,只需调用QGraphicsScene.addWidget(),或创建QGraphicsProxyWidget的实例即可手动嵌入部件。
通过QGraphicsProxyWidget,图形视图能够集成客户端部件功能,包括其光标,工具提示,鼠标,平板电脑和键盘事件,子部件,动画,弹出窗口(例如QComboBox或QCompleter),以及小部件的输入焦点和激活。QGraphicsProxyWidget甚至集成了嵌入式窗口部件的选项卡顺序,以方便便在嵌入式窗口部件中移入和移出。甚至可以将新的QGraphicsView嵌入到场景中以提供复杂的嵌套场景。
转换嵌入式窗口部件时,“图形视图”会确保独立转换窗口部件的分辨率,从而在放大时使字体和样式保持清晰。(注意,分辨率独立性的影响取决于样式。)
样例代码
在测试代码中,我们使用QGraphicsItemGroup 构造了一个螺旋线,并将其设置到场景中,并使用菜单条和工具条,演示旋转和缩放这个螺旋线。完整代码如下:
import sys,math
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPen, QBrush, QFont, QTransform, QPainter, QIcon
from PyQt5.QtWidgets import (QApplication, QMainWindow, QGraphicsScene, QGraphicsView,
QMenuBar, QMenuBar, QAction, QToolBar, QDialog,
QGraphicsLineItem, QGraphicsItemGroup)
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter
import resource_rc
class DemoGvFeature(QMainWindow):
def __init__(self, parent=None):
super(DemoGvFeature, self).__init__(parent)
# 设置窗口标题
self.setWindowTitle('实战PyQt5: Graphics View 框架关键特征演示')
# 设置窗口大小
self.resize(600, 400)
self.initUi()
def initUi(self):
#菜单条
menuBar = self.menuBar()
menuFile = menuBar.addMenu('文件')
menuTrans = menuBar.addMenu('变换')
#文件
aPrint = QAction('打印', self)
aPrint.triggered.connect(self.onPrint)
aExit = QAction('退出', self)
aExit.triggered.connect(self.close)
menuFile.addAction(aPrint)
menuFile.addAction(aExit)
#变换
aZoomIn = QAction('放大', self)
aZoomIn.setIcon(QIcon(':/res/zoom_in.png'))
aZoomIn.triggered.connect(self.onZoomIn)
aZoomOut = QAction('缩小', self)
aZoomOut.setIcon(QIcon(':res/zoom_out.png'))
aZoomOut.triggered.connect(self.onZoomOut)
aRotateLeft = QAction('向左旋转', self)
aRotateLeft.setIcon(QIcon(':/res/rotate_ccw.png'))
aRotateLeft.triggered.connect(self.onRotateLeft)
aRotateRight = QAction('向右旋转', self)
aRotateRight.setIcon(QIcon(':/res/rotate_cw.png'))
aRotateRight.triggered.connect(self.onRotateRight)
menuTrans.addAction(aZoomIn)
menuTrans.addAction(aZoomOut)
menuTrans.addAction(aRotateLeft)
menuTrans.addAction(aRotateRight)
toolBar = self.addToolBar('')
toolBar.addAction(aZoomIn)
toolBar.addAction(aZoomOut)
toolBar.addAction(aRotateLeft)
toolBar.addAction(aRotateRight)
#场景部分
self.scene = QGraphicsScene()
self.setScene()
self.view = QGraphicsView()
self.view.setScene(self.scene)
self.setCentralWidget(self.view)
def setScene(self):
#self.scene.addText('Graphics View\nKey Feature', QFont(self.font().family(), 16))
grp = QGraphicsItemGroup()
#绘制螺旋线
colors=[Qt.red, Qt.darkMagenta, Qt.blue, Qt.green, Qt.yellow, Qt.darkCyan]
n = 5 #边数
#初始值
x0 = 0
y0 = 0
ratio = 0.35
deg = (360 / n - 1) * math.pi / 180
for i in range (360):
line = QGraphicsLineItem()
line.setPen(QPen(colors[i%n]))
x1 = x0 + i * ratio * math.cos(-i * deg)
y1 = y0 + i * ratio * math.sin(-i * deg)
line.setLine(x0, y0, x1, y1)
grp.addToGroup(line)
x0 = x1
y0 = y1
self.scene.addItem(grp)
def onPrint(self):
printer = QPrinter()
if QPrintDialog(printer).exec() == QDialog.Accepted:
painter = QPainter(printer)
painter.setRenderHints(QPainter.Antialiasing)
self.scene.render(painter)
del painter
def onZoomIn(self):
self.view.scale(1.2, 1.2)
def onZoomOut(self):
self.view.scale(1/1.2, 1/1.2)
def onRotateLeft(self):
self.view.rotate(-10)
def onRotateRight(self):
self.view.rotate(10)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = DemoGvFeature()
window.show()
sys.exit(app.exec())
运行结果如下图:
本文知识点
- Graphics View框架关键特性;
- 使用QGraphicsItemGroup构建成组图元;
- 加载资源文件;
- 使用菜单条和工具条。
喜欢本文内容就关注, 收藏,点赞,评论和转发。
相关推荐
- jQuery VS AngularJS 你更钟爱哪个?
-
在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...
- Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0
-
在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...
- 如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例
-
要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...
- 编程技巧:Jquery实时验证,指定长度的「负小数」
-
为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...
- 一篇文章带你用jquery mobile设计颜色拾取器
-
【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...
- 编程技巧:Jquery实时验证,指定长度的「正小数」
-
为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...
- jquery.validate检查数组全部验证
-
问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...
- Vue进阶(幺叁肆):npm查看包版本信息
-
第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...
- layui中使用lay-verify进行条件校验
-
一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...
- jQuery是什么?如何使用? jquery是什么功能组件
-
jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...
- django框架的表单form的理解和用法-9
-
表单呈现...
- jquery对上传文件的检测判断 jquery实现文件上传
-
总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...
- Nodejs之MEAN栈开发(四)-- form验证及图片上传
-
这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...
- 大数据开发基础之JAVA jquery 大数据java实战
-
上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...
- 推荐四个开源的jQuery可视化表单设计器
-
jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)