《Qt学习笔记--图形视图框架.doc》由会员分享,可在线阅读,更多相关《Qt学习笔记--图形视图框架.doc(34页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、【精品文档】如有侵权,请联系网站删除,仅供学习与交流Qt学习笔记-图形视图框架.精品文档.Qt学习笔记-图形视图框架(一)2010-07-11 07:40优点:处理多个图元,单击,拖动,选择图元架构:一个场景,多个图元位于其中,通过视图显示主要应用: 绘图软件,显示地图软件当使用没有变换的视图观察场景时,场景中的一个单元对应屏幕上的一个像素图元坐标通常以图元中心为原点,X轴正方向为向右,Y轴正方向为向下场景坐标的原点在场景中心,X轴正方向为向右,Y轴正方向为向下视图坐标以左上角为原点,X轴正方向为向右,Y轴正方向为向下所有的鼠标事件最开始都是使用视图坐标场景:图元的容器1.提供管理很多图元的接
2、口2.传播事件到图元中3.管理图元状态,例如选择和焦点处理4.提供非转换的绘制功能,主要用于打印QGraphicsScene scene;QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100); / 添加图元QGraphicsItem *item = scene.itemAt(50, 50); / 查询图元/ item = rect;通过QGraphicsScene:setSelectionArea()可以选择场景的任一个图元,QGraphicsScene:setSelectedItems()返回被选择的图元设置焦点图元QG
3、raphicsScene:setFocusItem(), setFocus(),QGraphicsScene:focusItem(), 返回焦点图元视图:一个可视的子部件,可视化场景的内容多个视图可以显示同一个场景坐标转换:QGraphicsView:mapToScene(), QGraphicsView:mapFromScene()图元:支持鼠标事件,滚轮事件,上下文菜单事件支持键盘输入焦点,按键事件支持拖放支持分组冲突探测提供坐标转换,图元与场景,图元与图元之间利用QGraphicsItem:shape()和QGraphicsItem:collidesWith()实现冲突探测,这2个函数都
4、是虚函数相关类:QGraphicsScene, QGraphicsItem, QGraphicsViewQGraphicsItem子类:QGraphicsEllipseItem provides an ellipse itemQGraphicsLineItem provides a line itemQGraphicsPathItem provides an arbitrary path itemQGraphicsPixmapItem provides a pixmap itemQGraphicsPolygonItem provides a polygon itemQGraphicsRectI
5、tem provides a rectangular itemQGraphicsSimpleTextItem provides a simple text label itemQGraphicsTextItem provides an advanced text browser itemQGraphicsSvgItem provides a SVG file itemQGraphicsScene:拥有多个图元,包含三层:背景层,图元层,前景层背景层和前景层可以使用QBrush绘制,也可以使用drawBackground(),drawForeground()实现如果使用图片作为背景,可以用tex
6、ture QBrush(pixmap)实现前景层brush可以使用半透明的白色实现褪色效果,或者使用交叉模式实现网格重叠场景可以告诉我们,哪些图元发生冲突,哪些图元被选择,哪些图元位于一个特定的点或者区域每个图元可以是:1.顶级图元,场景是它的父亲;2.孩子,它的父亲是另一个图元,任何作用于父图元的转换都将自动应用于它的孩子2种分组方式:1.一个图元成为另一个图元的孩子; 2.使用QGraphicsItemGroup。使用分组,可以使位于同一个组的所有图元的操作都相同QGraphicsView:是一个Widget,用于显示一个场景,提供滚动条功能和转换功能,可以缩放和旋转场景。默认使用内建的2
7、D画图引擎,可以使用OpenGL:在构造后,调用setViewport()坐标系统:使用3种坐标系统:viewport, scene, itemviewport: 位于QGraphicsView内部scene: 逻辑坐标用于定位顶级图元item: 与图元相关,以图元的(0,0)为中心,移动图元时,它的坐标不会改变实践中,主要关注场景坐标(定位顶级图元)和图元坐标(定位子图元和绘制图元)在图元自己的坐标系统里面绘图意味着我们不用担心它在场景中的位置和应用于它的坐标转换Demo:/ 主要特点:/ 上下文菜单, 右键菜单/ copy-paste方法/diagram.proTEMPLATE = app
8、HEADERS = diagramwindow.h link.h node.h propertiesdialog.hSOURCES = diagramwindow.cpp link.cpp main.cpp node.cpp propertiesdialog.cppFORMS = propertiesdialog.uiRESOURCES = resources.qrc/link.h#ifndef LINK_H#define LINK_H#include class Node;class Link : public QGraphicsLineItem / 如果使用信号和槽,采用多继承public
9、 QObjectpublic:Link(Node *fromNode, Node *toNode);Link();Node *fromNode() const;Node *toNode() const;void setColor(const QColor &color);QColor color() const;void trackNodes(); / 节点移动时,跟踪节点private:Node *myFromNode; / 连线的2个节点Node *myToNode;#endif/link.cpp#include #include link.h#include node.hLink:Lin
10、k(Node *fromNode, Node *toNode)myFromNode = fromNode;myToNode = toNode;myFromNode-addLink(this); / 节点增加连线,每个节点有任意多个连线myToNode-addLink(this);setFlags(QGraphicsItem:ItemIsSelectable); / 连线可以被选择,然后删除setZValue(-1); / 在场景中显示的前后层次,因为连线是两个节点的中心,-1表示位于最后面,/ 节点覆盖了部分连线setColor(Qt:darkRed); / 设置线的颜色trackNodes(
11、);Link:Link()myFromNode-removeLink(this); / 删除连线时,将删除它在节点中的记录myToNode-removeLink(this);Node *Link:fromNode() constreturn myFromNode;Node *Link:toNode() constreturn myToNode;void Link:setColor(const QColor &color)setPen(QPen(color, 1.0);QColor Link:color() constreturn pen().color();void Link:trackNod
12、es()/ pos()返回节点在场景中或者父图元中的位置setLine(QLineF(myFromNode-pos(), myToNode-pos();/node.h#ifndef NODE_H#define NODE_H#include #include #include #include class Link;class Node : public QGraphicsItemQ_DECLARE_TR_FUNCTIONS(Node) / 在此类中增加tr()功能,直接使用,而不需要QObject:tr()了public:Node();Node();void setText(const QSt
13、ring &text);QString text() const;void setTextColor(const QColor &color);QColor textColor() const;void setOutlineColor(const QColor &color);QColor outlineColor() const;void setBackgroundColor(const QColor &color);QColor backgroundColor() const;void addLink(Link *link);void removeLink(Link *link);QRec
14、tF boundingRect() const; / 重新实现,决定一个图元是否需要绘制,必须的QPainterPath shape() const; / 重新实现,返回图元的精确形状,/ 决定一个点是否在图元内,或者2个图元是否发生冲突void paint(QPainter *painter, / 重新实现,画图, 必须的const QStyleOptionGraphicsItem *option, QWidget *widget);protected:void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); / 双击事件,修改
15、节点的文本QVariant itemChange(GraphicsItemChange change, / 重新实现,图元变化时,相关的连线发生变化const QVariant &value); / 没有使用mouseMoveEvent(), / 是因为程序可以改变节点位置private:QRectF outlineRect() const;int roundness(double size) const;QSet myLinks;QString myText;QColor myTextColor;QColor myBackgroundColor;QColor myOutlineColor;#
16、endif/link.cpp#include #include link.h#include node.hNode:Node()myTextColor = Qt:darkGreen;myOutlineColor = Qt:darkBlue;myBackgroundColor = Qt:white;setFlags(ItemIsMovable | ItemIsSelectable); / 节点可以移动,被选择Node:Node()foreach (Link *link, myLinks) / 删除所有的连线,防止边界效应,不使用aDeleteAll()delete link;void Node:
17、setText(const QString &text)prepareGeometryChange(); / 改变节点内的文本时,矩形可能会发生变化myText = text;update();QString Node:text() constreturn myText;void Node:setTextColor(const QColor &color)myTextColor = color;update();QColor Node:textColor() constreturn myTextColor;void Node:setOutlineColor(const QColor &colo
18、r)myOutlineColor = color;update();QColor Node:outlineColor() constreturn myOutlineColor;void Node:setBackgroundColor(const QColor &color)myBackgroundColor = color;update();QColor Node:backgroundColor() constreturn myBackgroundColor;void Node:addLink(Link *link)myLinks.insert(link); / 增加连线时,记录连线void
19、Node:removeLink(Link *link)myLinks.remove(link);QRectF Node:boundingRect() const / View决定是否绘制矩形const int Margin = 1;return outlineRect().adjusted(-Margin, -Margin, +Margin, +Margin);QPainterPath Node:shape() const / View用于冲突探测QRectF rect = outlineRect();QPainterPath path;path.addRoundRect(rect, roun
20、dness(rect.width(),roundness(rect.height();return path;/ 绘制图元void Node:paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget * /* widget */)QPen pen(myOutlineColor);if (option-state & QStyle:State_Selected) / 图元被选择pen.setStyle(Qt:DotLine);pen.setWidth(2);painter-setPen(pen);painter-
21、setBrush(myBackgroundColor);QRectF rect = outlineRect();painter-drawRoundRect(rect, roundness(rect.width(),roundness(rect.height();painter-setPen(myTextColor);painter-drawText(rect, Qt:AlignCenter, myText);/ 双击节点,弹出标准输入对话框void Node:mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)QString text =
22、 QInputDialog:getText(event-widget(),tr(Edit Text), tr(Enter new text:),QLineEdit:Normal, myText);if (!text.isEmpty()setText(text);/ 拖动节点时,调用此函数QVariant Node:itemChange(GraphicsItemChange change,const QVariant &value)if (change = ItemPositionHasChanged) foreach (Link *link, myLinks)link-trackNodes()
23、;return QGraphicsItem:itemChange(change, value);QRectF Node:outlineRect() constconst int Padding = 8;QFontMetricsF metrics = qApp-font();QRectF rect = metrics.boundingRect(myText);rect.adjust(-Padding, -Padding, +Padding, +Padding);rect.translate(-rect.center();return rect;int Node:roundness(double
24、size) constconst int Diameter = 12;return 100 * Diameter / int(size);/ diagramwindow.h#ifndef DIAGRAMWINDOW_H#define DIAGRAMWINDOW_H#include #include class QAction;class QGraphicsItem;class QGraphicsScene;class QGraphicsView;class Link;class Node;class DiagramWindow : public QMainWindowQ_OBJECTpubli
25、c:DiagramWindow();private slots:void addNode();void addLink();void del();void cut();void copy();void paste();void bringToFront();void sendToBack();void properties(); / 弹出属性设置对话框void updateActions(); / 更新菜单栏和工具栏的动作,哪些可用,哪些不可用private:typedef QPair NodePair;void createActions();void createMenus();void
26、createToolBars();void setZValue(int z);void setupNode(Node *node);Node *selectedNode() const;Link *selectedLink() const;NodePair selectedNodePair() const;QMenu *fileMenu;QMenu *editMenu;QToolBar *editToolBar;QAction *exitAction;QAction *addNodeAction;QAction *addLinkAction;QAction *deleteAction;QAct
27、ion *cutAction;QAction *copyAction;QAction *pasteAction;QAction *bringToFrontAction;QAction *sendToBackAction;QAction *propertiesAction;QGraphicsScene *scene;QGraphicsView *view;int minZ; / sendToBack(), bringToFront()使用int maxZ;int seqNumber; / 唯一标示一个节点的文本;#endif/digramwindow.cpp#include #include d
28、iagramwindow.h#include link.h#include node.h#include propertiesdialog.hDiagramWindow:DiagramWindow()scene = new QGraphicsScene(0, 0, 600, 500); / 创建场景,起始点为(0,0), 宽600,高500view = new QGraphicsView;view-setScene(scene); / 显示场景view-setDragMode(QGraphicsView:RubberBandDrag); / 选择多个节点方式:1.按ctrl;2.设置橡皮筋方式
29、view-setRenderHints(QPainter:Antialiasing| QPainter:TextAntialiasing);view-setContextMenuPolicy(Qt:ActionsContextMenu); / 右键菜单setCentralWidget(view);minZ = 0;maxZ = 0;seqNumber = 0;createActions();createMenus();createToolBars();connect(scene, SIGNAL(selectionChanged(),this, SLOT(updateActions();setW
30、indowTitle(tr(Diagram);updateActions();/ 增加一个节点void DiagramWindow:addNode()Node *node = new Node;node-setText(tr(Node %1).arg(seqNumber + 1);setupNode(node);void DiagramWindow:addLink()NodePair nodes = selectedNodePair();if (nodes = NodePair()return;Link *link = new Link(nodes.first, nodes.second);s
31、cene-addItem(link);/ 删除选择的图元:首先删除连线,然后删除节点,以防止多次删除同一个连线void DiagramWindow:del()QList items = scene-selectedItems();QMutableListIterator it(items);while (it.hasNext() Link *link = dynamic_cast(it.next();if (link) delete link;it.remove();qDeleteAll(items);/ 剪切操作:先复制,后删除void DiagramWindow:cut()Node *no
32、de = selectedNode();if (!node)return;copy();delete node;/ 拷贝操作:值得研究!void DiagramWindow:copy()Node *node = selectedNode();if (!node)return;QString str = QString(Node %1 %2 %3 %4).arg(node-textColor().name().arg(node-outlineColor().name().arg(node-backgroundColor().name().arg(node-text();QApplication:
33、clipboard()-setText(str);void DiagramWindow:paste()QString str = QApplication:clipboard()-text();QStringList parts = str.split( );if (parts.count() = 5 & parts.first() = Node) Node *node = new Node;node-setText(QStringList(parts.mid(4).join( ); / 连接字符串列表node-setTextColor(QColor(parts1);node-setOutli
34、neColor(QColor(parts2);node-setBackgroundColor(QColor(parts3);setupNode(node);void DiagramWindow:bringToFront()+maxZ;setZValue(maxZ); / 改变绘图顺序,首先绘制父图元,然后是子图元,根据子图元Z值的大小,/ 值最小,最先绘制,值最大,最后绘制void DiagramWindow:sendToBack()-minZ;setZValue(minZ);void DiagramWindow:properties()Node *node = selectedNode();
35、Link *link = selectedLink();if (node) PropertiesDialog dialog(node, this);dialog.exec(); else if (link) QColor color = QColorDialog:getColor(link-color(), this);if (color.isValid()link-setColor(color);/ 更新动作使能void DiagramWindow:updateActions()bool hasSelection = !scene-selectedItems().isEmpty();bool
36、 isNode = (selectedNode() != 0);bool isNodePair = (selectedNodePair() != NodePair();cutAction-setEnabled(isNode);copyAction-setEnabled(isNode);addLinkAction-setEnabled(isNodePair);deleteAction-setEnabled(hasSelection);bringToFrontAction-setEnabled(isNode);sendToBackAction-setEnabled(isNode);properti
37、esAction-setEnabled(isNode);foreach (QAction *action, view-actions()view-removeAction(action); / 删除右键菜单foreach (QAction *action, editMenu-actions() if (action-isEnabled()view-addAction(action); / 增加右键菜单void DiagramWindow:createActions()exitAction = new QAction(tr(E&xit), this);exitAction-setShortcut
38、(tr(Ctrl+Q);connect(exitAction, SIGNAL(triggered(), this, SLOT(close();addNodeAction = new QAction(tr(Add &Node), this);addNodeAction-setIcon(QIcon(:/images/node.png);addNodeAction-setShortcut(tr(Ctrl+N);connect(addNodeAction, SIGNAL(triggered(), this, SLOT(addNode();addLinkAction = new QAction(tr(A
39、dd &Link), this);addLinkAction-setIcon(QIcon(:/images/link.png);addLinkAction-setShortcut(tr(Ctrl+L);connect(addLinkAction, SIGNAL(triggered(), this, SLOT(addLink();deleteAction = new QAction(tr(&Delete), this);deleteAction-setIcon(QIcon(:/images/delete.png);deleteAction-setShortcut(tr(Del);connect(
40、deleteAction, SIGNAL(triggered(), this, SLOT(del();cutAction = new QAction(tr(Cu&t), this);cutAction-setIcon(QIcon(:/images/cut.png);cutAction-setShortcut(tr(Ctrl+X);connect(cutAction, SIGNAL(triggered(), this, SLOT(cut();copyAction = new QAction(tr(&Copy), this);copyAction-setIcon(QIcon(:/images/co
41、py.png);copyAction-setShortcut(tr(Ctrl+C);connect(copyAction, SIGNAL(triggered(), this, SLOT(copy();pasteAction = new QAction(tr(&Paste), this);pasteAction-setIcon(QIcon(:/images/paste.png);pasteAction-setShortcut(tr(Ctrl+V);connect(pasteAction, SIGNAL(triggered(), this, SLOT(paste();bringToFrontAct
42、ion = new QAction(tr(Bring to &Front), this);bringToFrontAction-setIcon(QIcon(:/images/bringtofront.png);connect(bringToFrontAction, SIGNAL(triggered(),this, SLOT(bringToFront();sendToBackAction = new QAction(tr(&Send to Back), this);sendToBackAction-setIcon(QIcon(:/images/sendtoback.png);connect(sendToBackAction, SIGNAL(triggered(),this, SLOT(sendToBack();propertiesAction = new QAction(tr(P&roperties.), this);connect(propertiesAction, SIGNAL(triggered(),this, SLOT(properties();void DiagramWindow:createMenus()fileMenu = menuBar