QGraphicsView图形视图框架使用(二)图形交互

文章目录

    • 标准图元
    • 图元优化
    • 图元选择
    • 图元焦点
    • 图元层次

在开发基于图形视图框架QGraphicsView的应用的时候,其中很重要的一部分工作就是处理与框架中图元的交互。这也是最让人头疼的。这里就介绍一下与Item交互过程中那些常见的操作。

标准图元

在QGraphicsView图形视图框架中QT提供了很多标准的Item,通过组合使用各种基本图元,我们可以实现各种各样的复杂场景。充分的了解和熟悉标准图元,能避免在开发的过程中重复造轮子。QGraphicsView中标准图元如下表所示:

图元名称 说明
QGraphicsLineItem 用来绘制直线,可以通过setLine(const QLineF&)来添加。
QGraphicsRectItem 用来绘制矩形,通过setRect()来进行添加
QGraphicsEllipseItem 用来绘制椭圆,或者部分椭圆。通过设置setStartAngle(int)和setSpanAngle(int)可以绘制椭圆的一部分。设置的值是1度的1/16。
QGraphicsPolygonItem 用来绘制多边形,通过setPolygon()添加
QGraphicsPathItem 绘制一个路径,通过setPath()来进行添加
QGraphicsSimpleTextItem 绘制简单文本,除了可以设置字体以外,不支持其它的富文本样式
QGraphicsTextItem 绘制格式化的文本,可以通过setHtml()或者setDocument()设置html,还可以添加有交互内容的URL超链接。
QGraphicsPixmapItem 绘制图片,或者渲染一个图片
QGraphicsProxyWidget 绘制任意的QWdiget控件,视图框架允许我们与添加的控件进行交互。

在使用标准图元的时候有几点需要注意:
1.可以通过设置画笔(setPen())来修改边线的样式和颜色,可以通过设置画刷(setBrush())来修改填充的内容的颜色和样式。
2.QGraphicsTextItem不支持设置画刷和画笔,我们可以通过setDefaultTextColor()设置文本颜色,或者通过HTML样式来实现。
3.尽量使用QGraphicsSimpleTextItem而不是QGraphicsTextItem,因为为了支持HTML解析和渲染,QGraphicsTextItem引入了一个轻量级的HTML引擎,会对性能产生损耗。
标准控件的绘制调用方法如下:

#pragma execution_character_set("utf-8")
#include "mainwindow.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene;

    //在Scene中心添加一个十字坐标
    scene.addLine(-200, 0, 200, 0);
    scene.addLine(0, -200, 0, 200);

    //添加矩形图元
    QGraphicsRectItem* rect_item = scene.addRect(-50,-50,150,150);
    rect_item->setBrush(QBrush(QColor("#4D9CF8")));

    //添加椭圆图元
    QGraphicsEllipseItem* ellipseItem = scene.addEllipse(QRectF(QPointF(-50,100),QPointF(50,50)),QPen("#0000FF"),QBrush(QColor("#4D00F8")));
    ellipseItem->setZValue(10);

    //添加多边形
    QPolygonF polygon;
    polygon << QPointF(-30,-30) << QPointF(-30, 40) << QPointF(20, 30) << QPointF(0,0);
    scene.addPolygon(polygon,QPen(),QBrush(QColor("#FF0000")));

    //绘制文本
    QGraphicsTextItem* text_item = scene.addText(QString("测试文本ABC"),QFont("Micros"));
    text_item->setPos(-30,-100);

    //绘制路径
    QPainterPath path;
    path.moveTo(-300,-50);
    path.lineTo(0,-150);
    path.lineTo(200,0);
    QGraphicsPathItem* path_item = scene.addPath(path,QPen(QColor("#00FF00")));

    //绘制图片
    QGraphicsPixmapItem* pixmap_item = scene.addPixmap(QPixmap(":/demo.png"));
    pixmap_item->setPos(-300,-50);
    pixmap_item->setZValue(20);

    //添加自定义控件
    QPushButton* button = new QPushButton("按钮");
    QGraphicsProxyWidget* button_item = scene.addWidget(button);
    button_item->setPos(100,30);
    QGraphicsView view(&scene);
    view.show();

    return a.exec();

}

显示效果如下:
QGraphicsView图形视图框架使用(二)图形交互_第1张图片

图元优化

默认配置下,图形视图框架是没有优化绘制的,绘制的图形和直线毛边非常严重,不顺滑。我们可以通过开启渲染的抗锯齿操作来优化渲染。对应的配置如下:

QGraphicsView view(&scene);
view.setRenderHint(QPainter::Antialiasing);
view.show();

开起了抗锯齿之后,渲染效果会好很多,显示效果如下:
QGraphicsView图形视图框架使用(二)图形交互_第2张图片
开启抗锯齿效果之后,有时候会出现一些非常诡异的现象,就是相同宽度的线有些线看上去比别的线粗一些。这是因为有的线位于两个图像像素之间,在开启抗锯齿进行插值的时候,相邻的两个线都被渲染了。我们可以通过偏移半个像素来解决这个问题:

QRectF rect(-width / 2, -height / 2, width, height);
rect.translate(0.5, 0.5);

除了偏移像素外,在绘制水平线和垂直线的时候,我们也可以通过关闭抗锯齿效果来解决这个问题。除了对整个视图进行抗锯齿操作之外,我们还可以单独对文字或者图片进行优化。对应的配置如下:

QGraphicsView view(&scene);
//抗锯齿效果
view.setRenderHint(QPainter::Antialiasing);
//绘制文本的时候抗锯齿
view.setRenderHint(QPainter::TextAntialiasing);
//平滑的图片变换
view.setRenderHint(QPainter::SmoothPixmapTransform);
view.show();

虽然抗锯齿效果能提升图像质量,但这都是以牺牲性能为代价的,在实际使用的时候还是要根据需要开启,不要盲目的使用,防止对性能产生损耗。

图元选择

添加到Scene中的Item,默认是不支持选择的,我们需要通过设置对应的标志位来开启选择属性。

item->setFlag(QGraphicsItem::ItemIsSelectable, true);

开启选择属性之后,我们可以通过鼠标左键来选择图元,同时配合Ctrl键我们可以同时选中多个图元。对应的调用方法如下:

#pragma execution_character_set("utf-8")
#include "mainwindow.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene;
    //添加矩形图元
    QGraphicsRectItem* rect_item = scene.addRect(-50,-50,100,100);
    rect_item->setBrush(QBrush(QColor("#4D9CF8")));
    rect_item->setFlag(QGraphicsItem::ItemIsSelectable, true);

    //通过渐变色填充图元
    QGraphicsRectItem* gradient_rect_item = scene.addRect(60,-50,100,100);
    QLinearGradient gradient(0, 0, 100, 100);
    gradient.setColorAt(0, Qt::yellow);
    gradient.setColorAt(0.5, Qt::red);
    gradient.setColorAt(1.0, Qt::magenta);
    QBrush brush = gradient;
    gradient_rect_item->setBrush(brush);
    gradient_rect_item->setFlag(QGraphicsItem::ItemIsSelectable, true);

    QGraphicsView view(&scene);
    //抗锯齿效果
    view.setRenderHint(QPainter::Antialiasing);
    view.show();
    return a.exec();
}

被选中的图元,边框线会变成虚线,效果如下:
QGraphicsView图形视图框架使用(二)图形交互_第3张图片
通过对视图View进行如下配置,可以开启视图的框选模式,框选模式可以通过鼠标进行范围选择。

view.setDragMode(QGraphicsView::RubberBandDrag);

显示效果如下:
QGraphicsView图形视图框架使用(二)图形交互_第4张图片
除了RubberBandDrag模式外,QGraphicsView还支持ScrollHandDrag,设置了该效果之后,我们可以通过鼠标左键对整个场景进行拖拽移动。

view.setDragMode(QGraphicsView::ScrollHandDrag);

显示效果如下所示:
QGraphicsView图形视图框架使用(二)图形交互_第5张图片
除了上面的选择方式之外,图形视图框架中还提供了一些与选择图元有关的函数接口。我们可以通过调用对应的接口选中/取消选中某些图元。

//选中或取消选中某个图元
QGraphicsItem::setSelected(true/false)
//判断某个图元是否被选中了
QGraphicsItem::isSelected()
//设定选中范围,范围内的图元都会被选中
QGraphicsScene::setSelectionArea()
//取消Scene中选中的图元
QGraphicsScene::clearSelection()
//获取Scene中被选择图元的列表
QGraphicsScene::selectedItems()

除了选择属性之外,默认添加的图元也是不支持移动的,我们也可以通过配置对应的属性开启图元的移动属性,对应的配置如下:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene;
    //添加矩形图元
    QGraphicsRectItem* rect_item = scene.addRect(-50,-50,100,100);
    rect_item->setBrush(QBrush(QColor("#4D9CF8")));
    //添加移动属性
    rect_item->setFlag(QGraphicsItem::ItemIsMovable,true);
    QGraphicsView view(&scene);
    //抗锯齿效果
    view.setRenderHint(QPainter::Antialiasing);
    view.show();
    return a.exec();
}

开启了移动开关之后,我们就可以自由的拖动添加的图元了对应的效果如下:
QGraphicsView图形视图框架使用(二)图形交互_第6张图片

图元焦点

为了让图元响应键盘事件,我们需要对图元的焦点进行处理。Scene中某一时刻只允许一个Item有焦点,接受到的键盘事件会被发送到对应有焦点的Item。为了让图元响应焦点事件,我们需要开启图元的焦点属性,对应的设置如下:

item1->setFlag(QGraphicsItem::ItemIsFocusable, true);

和图元的选择一样,针对焦点图元的处理,图形框架也提供了一系列的接口,如下:

//设置图元焦点(鼠标点击也可以)
QGraphicsItem::setFocus()
//判断某个图元是否有焦点
QGraphicsItem::hasFocus()
//清除某个图元的焦点(也可以通过点击Scene背景实现)
QGraphicsItem::clearFocus()

//让某个图元获得焦点
QGraphicsScene::setFocusItem()
//获得有焦点的图元
QGraphicsScene::focusItem()
//设置了StickyFocus之后便不可以通过点击Scene背景来取消焦点了
QGraphicsScene::setStickyFocus(true);

图元层次

默认添加的图元的Z值都是相同的都是0,这时候的前后显示关系跟添加的先后顺序有关,后添加的图元显示在之前添加的图元的前面。我们可以通过设置图元的Z值,来调整图元的层次关系,z值越大显示的层次越高,z值越小显示的层次越低,对应的使用方法如下:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene;
    QGraphicsEllipseItem *item1 = scene.addEllipse(0, 0, 100, 50);
    item1->setBrush(Qt::red);
    item1->setZValue(-20);
    
    QGraphicsEllipseItem *item2 = scene.addEllipse(50, 0, 100, 50);
    item2->setBrush(Qt::green);
    item2->setZValue(10);
    
    QGraphicsEllipseItem *item3 = scene.addEllipse(0, 25, 100, 50);
    item3->setBrush(Qt::blue);
    item3->setZValue(-40);
    
    QGraphicsEllipseItem *item4 = scene.addEllipse(50, 25, 100, 50);
    item4->setBrush(Qt::gray);
    item4->setZValue(20);

    QGraphicsView view(&scene);
    //抗锯齿效果
    view.setRenderHint(QPainter::Antialiasing);
    view.show();
    return a.exec();
}

显示效果如下:
QGraphicsView图形视图框架使用(二)图形交互_第7张图片
对包含子元素的组合对象来说,子对象的层次关系,由父对象确定,如果一个父对象显示在另个图元的前面,它的子对象也显示在另一个图元的前面。

你可能感兴趣的