QT-【转】2D编程

Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕上和绘图·设备上进行绘制,主要基于QPainter、QPainterDevice和QPainterEngine这3个类。

1、QPainter执行绘图操作,QPainter可以绘制一切简单的图形,从简单的一条直线到任何复杂的图形。QPainter类可以在一切继承QPainterDevice的子类上进行绘制操作。

2、QPainterDevice提供绘图设备,是一个二维空间的抽象,

3、QPainterEngine提供一些接口。

绘制简单图形

绘制直线

1
2
QPainter painter(this);
painter.drawLine(QPointF(0, 0), QPointF(100, 100));

QPen和QBrush

画刷与画笔是Qt绘图时,重要属性;前者用QBrush描述,用来填充,后者用QPen描述,来绘制轮廓线。

QBrush

1
2
3
4
5
6
7
8
9
10
QBrush ()
QBrush ( Qt::BrushStyle style )
QBrush ( const QColor & color, Qt::BrushStyle style = Qt::SolidPattern )
QBrush ( Qt::GlobalColor color, Qt::BrushStyle style = Qt::SolidPattern )
QBrush ( const QColor & color, const QPixmap & pixmap )
QBrush ( Qt::GlobalColor color, const QPixmap & pixmap )
QBrush ( const QPixmap & pixmap )
QBrush ( const QImage & image )
QBrush ( const QBrush & other )
QBrush ( const QGradient & gradient )

style定义了填充模式,通过枚举类型Qt::BrushStyle来实现,默认值是Qt::NoBrush,不进行任何填充;填充模式包括基本填充模式,渐变填充,和纹理填充模式,下图是不同的填充模式区别.

画刷的 gradient() 定义了渐变填充。这个属性只有在样式是 Qt::LinearGradientPattern、Qt::RadialGradientPattern 或者 Qt::ConicalGradientPattern 之一时才有效。渐变可以由 QGradient 对象表示。Qt 提供了三种渐变:QLinearGradient、QConicalGradient 和 QRadialGradient,它们都是 QGradient 的子类。

当画刷样式是 Qt::TexturePattern 时,texture() 定义了用于填充的纹理。注意,即使你没有设置样式为 Qt::TexturePattern,当你调用 setTexture() 函数时,QBrush 会自动将 style() 设置为 Qt::TexturePattern。

画刷的color定义了填充的颜色,这个颜色可以使用Qt预定义的颜色常量(Qt::GlobalColor),也可以使用QColor对象。


QPen

1
2
3
4
5
6
7
8
9
10
11
QPen ()
QPen ( Qt::PenStyle style )
QPen ( const QColor & color )
QPen ( const QBrush & brush, qreal width, Qt::PenStyle style = Qt::SolidLine, Qt::PenCapStyle cap = Qt::SquareCap, Qt::PenJoinStyle join = Qt::BevelJoin )
QPen ( const QPen & pen )
包含了画笔实用的画刷,线宽,画笔风格,画笔端点风格,画笔连接风格;也可以使用对应的函数进行设置,
void    setBrush ( const QBrush & brush )
void    setCapStyle ( Qt::PenCapStyle style )
void    setColor ( const QColor & color )
void    setJoinStyle ( Qt::PenJoinStyle style )
void    setWidth ( int width )
1
  
Pen Style: 用枚举类型Qt::PenStyle来定义


Cap Style:
The cap style defines how the end points of lines are drawn using QPainter. The cap style only apply to wide lines, i.e. when the width is 1 or greater.当线宽比较大时,才能看书画笔端点风格的差别。

Join Style:
The join style defines how joins between two connected lines can be drawn using QPainter. The join style only apply to wide lines, i.e. when the width is 1 or greater.当两个宽度大于1的线,端点连接时的风格;

绘制弧线

1
2
3
4
QRectF rectangle(10.0, 20.0, 80.0, 60.0); //位置矩形
int startAngle = 30 * 16;     //起始角度,角度被分成了十六分之一
int spanAngle = 120 * 16;   //跨越度数
QPainter painter(this);painter.drawArc(rectangle, startAngle, spanAngle);
1
  

渐变填充

1 线性渐变

2
3
4
5
6
7
8
9
10
11
12
13
//线性渐变
QLinearGradient linearGradient(QPointF(40, 190), QPointF(70, 190));
//插入颜色
linearGradient.setColorAt(0, Qt::yellow);
linearGradient.setColorAt(0.5, Qt::red);
linearGradient.setColorAt(1, Qt::green);
//指定渐变区域以外的区域的扩散方式
linearGradient.setSpread(QGradient::RepeatSpread);
//使用渐变作为画刷
QPainter painter(this);
painter.setBrush(linearGradient);
painter.drawRect(10, 20, 90, 40);

线性渐变QLinearGradient::QLinearGradient ( const QPointF & start, constQPointF & finalStop )需要指定开始点start和结束点finalStop,然后将开始点和结束点之间的区域进行等分,开始点的位置为0.0,结束点的位置为1.0,而它们之间的位置按照距离比例进行设定,然后使用QGradient::setColorAt( qreal position, const QColor & color )函数在指定的位置position插入指定的颜色color,当然,这里的position的值要在0到1之间。

这里还可以使用setSpread()函数来设置填充的扩散方式,即指明在指定区域以外的区域怎样进行填充。扩散方式由QGradient::Spread枚举变量定义,它一共有三个值,分别是QGradient::PadSpread,使用最接近的颜色进行填充,这是默认值,如果我们不使用setSpread()指定扩散方式,那么就会默认使用这种方式;QGradient::RepeatSpread,在渐变区域以外的区域重复渐变;QGradient::ReflectSpread,在渐变区域以外将反射渐变。要使用渐变填充,可以直接在setBrush()中使用,这时画刷风格会自动设置为相对应的渐变填充。

2 辐射渐变

2
3
4
5
6
7
//辐射渐变
QRadialGradient radialGradient(QPointF(100, 190),50,QPointF(275,200));
radialGradient.setColorAt(0, QColor(255, 255, 100, 150));
radialGradient.setColorAt(1, QColor(0, 0, 0, 50));
painter.setBrush(radialGradient);
painter.drawEllipse(QPointF(100, 190), 50, 50);

辐射渐变QRadialGradient::QRadialGradient( const QPointF & center, qreal radius, const QPointF & focalPoint )需要指定圆心center和半径radius,这样就确定了一个圆,然后再指定一个焦点focalPoint。焦点的位置为0,圆环的位置为1,然后在焦点和圆环间插入颜色。辐射渐变也可以使用setSpread()函数设置渐变区域以外的区域的扩散方式

3 锥形渐变

2
3
4
5
6
7
//锥形渐变
QConicalGradient conicalGradient(QPointF(250, 190), 60);
conicalGradient.setColorAt(0.2, Qt::cyan);
conicalGradient.setColorAt(0.9, Qt::black);
painter.setBrush(conicalGradient);
painter.drawEllipse(QPointF(250, 190), 50, 50);

锥形渐变QConicalGradient::QConicalGradient ( const QPointF & center,qreal angle )需要指定中心点center和一个角度angle(其值在0到360之间),然后沿逆时针从给定的角度开始环绕中心点插入颜色。这里给定的角度沿逆时针方向开始的位置为0,旋转一圈后为1。setSpread()函数对于锥形渐变没有效果。

绘制文字

基本控制

2
3
QPainter painter(this);
painter.drawText(100, 100, "qter.org_yafeilinux");//在(100, 100)的位置绘制了一个字符串

控制文字位置

QPainter::drawText ( const QRectF &rectangle, int flags, const QString & text, QRectF * boundingRect = 0 )

第一个参数指定了绘制文字所在的矩形;

第二个参数指定了文字在矩形中的对齐方式,它由Qt::AlignmentFlag枚举变量进行定义,不同对齐方式也可以使用“|”操作符同时使用,这里还可以使用Qt::TextFlag定义的其他一些标志,比如自动换行等;

第三个参数就是所要绘制的文字,这里可以使用“\n”来实现换行;

第四个参数一般不用设置。

2
3
4
5
6
7
8
9
QPainter painter(this);
//设置一个矩形
QRectF rect(20, 20, 300, 200);
//为了更直观地看到字体的位置,我们绘制出这个矩形
//painter.drawRect(rect);
painter.setPen(QColor(Qt::red));
//我们这里先让字体水平居中
painter.drawText(rect, Qt::AlignHCenter, "yafeilinux");

使用字体

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
QFont font("宋体", 15, QFont::Bold, true);
//设置下划线
font.setUnderline(true);
//设置上划线
font.setOverline(true);
//设置字母大小写
font.setCapitalization(QFont::SmallCaps);
//设置字符间的间距
font.setLetterSpacing(QFont::AbsoluteSpacing, 10);
//使用字体
painter.setFont(font);
painter.setPen(Qt::green);
painter.drawText(120, 80, tr("yafeilinux"));
painter.translate(50, 50);
painter.rotate(90);
painter.drawText(0, 0, tr("helloqt"));

这里创建了QFont字体对象,使用的构造函数为QFont::QFont ( const QString & family,int pointSize = -1, int weight = -1, bool italic = false ),第一个参数设置字体的family属性,这里使用的字体族为宋体,可以使用QFontDatabase类来获取所支持的所有字体;第二个参数是点大小,默认大小为12;第三个参数为weight属性,这里使用了粗体;最后一个属性设置是否使用斜体。然后我们又使用了其他几个函数来设置字体的格式,最后调用setFont()函数来使用该字体,并使用drawText()函数的另一种重载形式在点(120, 80)绘制了文字。后面又将坐标系统平移并旋转,然后再次绘制了文字。

绘制路径

简单使用路径

2
3
4
5
6
7
8
QPainterPath path;
path.addEllipse(100, 100, 50, 50);//添加椭圆
path.lineTo(200, 200);
QPainter painter(this);
painter.setPen(Qt::blue);
painter.setBrush(Qt::red);
painter.drawPath(path);

创建一个QPainterPath对象后,可以使用lineTo()、arcTo()、cubicTo()和quadTo()等函数将直线或者曲线添加到路径中。

复制图形

2
3
4
5
QPainterPath path2;
path2.addPath(path);//新建路径,并将path放在path2上。
path2.translate(100,0);//更改坐标
painter.drawPath(path2);

绘制图形时的当前位置

创建路径后,默认是从(0, 0)点开始绘制的。

绘制图片

简单绘制图片

2
3
4
5
QPainter painter(this);
QPixmap pix;
pix.load("../painter_2/logo.png");
painter.drawPixmap(0, 0, 129, 66, pix);

drawPixmap()函数在给定的矩形中来绘制图片,这里矩形的左上角顶点为(0, 0)点,宽129,高66,如果这个跟图片的大小不相同,默认会拉伸图片。

平移图片

2
3
painter.translate(100, 100); //将(100,100)设为坐标原点
painter.drawPixmap(0, 0, 129, 66, pix);

缩放图片

2
3
4
5
6
qreal width = pix.width(); //获得以前图片的宽和高
qreal height = pix.height();
//将图片的宽和高都扩大两倍,并且在给定的矩形内保持宽高的比值不变
pix = pix.scaled(width*2, height*2, Qt::KeepAspectRatio);//使用QPixmap类中的scaled()函数来实现图片的放大和缩小。
//Qt::IgnoreAspectRatio是不保持图片的宽高比,Qt::KeepAspectRatio是在给定的矩形中保持宽高比
2
painter.drawPixmap(70, 70,pix);

旋转图片

旋转使用的是QPainter类的rotate()函数,它默认是以原点为中心进行旋转的。

我们要改变旋转的中心,可以使用前面讲到的translate()函数完成。

必须先改变旋转中心,然后再旋转,然后再将原点复原,才能达到想要的效果。

2
3
4
5
painter.translate(64, 33); //让图片的中心作为旋转的中心
painter.rotate(90); //顺时针旋转90度
painter.translate(-64,-33); //使原点复原
painter.drawPixmap(100, 100, 129, 66, pix);

扭曲图片

使用的QPainter类的shear(qreal sh,qreal sv)函数,前面的参数实现横行变形,后面的参数实现纵向变形。当它们的值为0时,表示不扭曲。

2
3
painter.shear(0.5, 0); //横向扭曲
painter.drawPixmap(100, 0, 129, 66, pix);

坐标系统

坐标系统简介

Qt中每一个窗口都有一个坐标系统,默认的,窗口左上角为坐标原点,水平向右依次增大,水平向左依次减小,垂直向下依次增大,垂直向上依次减小。原点即为(0,0)点,以像素为单位增减。

坐标系统变换

默认的,QPainter在相关设备的坐标系统上进行绘制,在进行绘图时,

使用QPainter::scale()函数缩放坐标系统;

使用QPainter::rotate()函数顺时针旋转坐标系统;

使用QPainter::translate()函数平移坐标系统;

使用QPainter::shear()围绕原点来扭曲坐标系统。

也可以通过QTransform类实现。

坐标系统保存

利用save()函数来保存坐标系现在的状态,然后进行变换操作,操作完之后,再用restore()函数将以前的坐标系状态恢复,其实就是一个入栈和出栈的操作。

2
3
4
5
6
7
QPainter painter(this);
painter.save(); //保存坐标系状态
painter.translate(100,100);
painter.drawLine(0, 0, 50, 50);
painter.restore(); //恢复以前的坐标系状态
painter.drawLine(0, 0, 50, 50);

获取坐标信息

2
qDebug() << event->pos();

应用qDebug()函数,该函数可以在程序运行时将程序中的一些信息输出到控制面板,在QtCreator中会将信息输出到其下面的“应用程序输出”窗口。这个函数很有用,在进行简单的程序调试时,都可以利用该函数进行。我们这里利用它将鼠标指针的坐标值输出出来。

变换后的坐标系统

绘图设备的坐标系统

绘图设备:QWidget等窗口部件、QPixmap、QImage等。

2
3
4
5
QPainter painter(this);
QPixmap pix(200, 200);
pix.fill(Qt::red);   //背景填充为红色
painter.drawPixmap(0, 0, pix);

第一,QWidget和QPixmap各有一套坐标系统,它们互不影响。可以看到,无论画布在窗口的什么位置,它的坐标原点依然在左上角,为(0,0)点,没有变。

第二,我们所得到的鼠标指针的坐标值是窗口坐标系统的,不是画布的坐标。

涂鸦板

实现涂鸦板

实现放大功能

双缓冲绘图

绘制矩形

双缓冲绘图

双缓冲(double-buffers)绘图,就是在进行绘制时,先将所有内容都绘制到一个绘图设备(如QPixmap)上,然后再将整个图像绘制到部件上显示出来。使用双缓冲绘图可以避免显示时的闪烁现象。从Qt 4.0开始,QWidget部件的所有绘制都自动使用了双缓冲,所以一般没有必要在paintEvent()函数中使用双缓冲代码来避免闪烁。

图形视图框架

基本应用

2
3
4
5
6
7
QGraphicsScene *scene = new QGraphicsScene;  //场景
QGraphicsRectItem *item = new QGraphicsRectItem(100,100,50,50);  //矩形项
scene->addItem(item);  //项添加到场景
QGraphicsView *view = new QGraphicsView; //视图
view->setScene(scene);  //视图关联场景
view->show();  //显示视图

最简单的基于这个图形视图框架的程序:分别新建了一个场景,一个图形项和一个视图,并将图形项添加到场景中,将视图与场景关联,最后显示视图。

场景是管理图形项的,所有的图形项必须添加到一个场景中,但是场景本身无法可视化,我们要想看到场景上的内容,必须使用视图。

图形项

QGraphicsItem类是所有图形项的基类。

自定义图形项

基类设为QGraphicsItem。继承QGraphicsItem类实现自定义的图形项,必须先实现两个纯虚函数boundingRect()和paint(),前者用于定义Item的绘制范围,后者用于绘制图形项。

光标和提示

2
3
setToolTip("Click and drag me!");  //提示
setCursor(Qt::OpenHandCursor);   //改变光标形状

拖放

2
3
4
5
6
7
。。。
QDrag *drag = new QDrag(event->widget()); //为event所在窗口部件新建拖动对象
QMimeData *mime = new QMimeData; //新建QMimeData对象,它用来存储拖动的数据
drag->setMimeData(mime); //关联
mime->setColorData(color);  //放入颜色数据
。。。

必须源图形项和目标图形项都进行相关设置。在源图形项的鼠标事件中新建并执行拖动,而在目标图形项中必须指定setAcceptDrops(true); 这个函数,这样才能接收拖放,然后需要实现拖放的几个事件处理函数。

键盘与鼠标事件

2
3
4
5
void MyItem::keyPressEvent(QKeyEvent*event)
{
   moveBy(0, 10);  //相对现在的位置移动
}

要想使图形项接收键盘事件,就必须使其可获得焦点。我们在构造函数里添加一行代码:

setFlag(QGraphicsItem::ItemIsFocusable);  //图形项可获得焦点

2
3
4
5
void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
   moveBy(10,0);
}

如果我们想让鼠标可以拖动小方块,那么我们可以重新实现mouseMoveEvent()函数,还有一种更简单的方法是,我们在构造函数中指明该图形项是可移动的:

setFlag(QGraphicsItem::ItemIsMovable);

碰撞检测

在QGraphicsItem类中有三个碰撞检测函数,分别是collidesWithItem()、collidesWithPath()和collidingItems()。

第一个是该图形项是否与指定的图形项碰撞,第二个是该图形项是否与指定的路径碰撞,第三个是返回所有与该图形项碰撞的图形项的列表。三个函数都有一个共同的参数Qt::ItemSelectionMode,它指明了怎样去检测碰撞。

2
3
4
5
6
Qt::ContainsItemShape:只有图形项的shape被完全包含时;
Qt::IntersectsItemShape:当图形项的shape被完全包含时,或者图形项与其边界相交;
Qt::ContainsItemBoundingRect: 只有图形项的bounding rectangle被完全包含时;
Qt::IntersectsItemBoundingRect:图形项的boundingrectangle被完全包含时,或者图形项与其边界相交。
如果我们不设置该参数,那么他默认使用Qt::IntersectsItemShape 。

移动

advance()槽函数,这个函数在QGraphicsScene和QGraphicsItem中都有,在图形项类中它的原型是advance(int phase)。它的实现流程是,我们利用QGraphicsScene类的对象调用QGraphicsScene的advance()函数,这时就会执行两次该场景中所有图形项的advance(int phase)函数,第一次phase为0,告诉所有图形项即将要移动;第二次phase的值为1,这时执行移动。

动画

使用了QGraphicsItemAnimation动画类和QTimeLine时间线类。

2
3
4
5
6
7
8
9
10
11
setFlag(QGraphicsItem::ItemIsFocusable); //图形项可获得焦点
setFlag(QGraphicsItem::ItemIsMovable); //图形项可移动
QGraphicsItemAnimation *anim = new QGraphicsItemAnimation; //新建动画类对象
anim->setItem(this);  //将该图形项加入动画类对象中
QTimeLine *timeLine = new QTimeLine(1000);  //新建长为1秒的时间线
timeLine->setLoopCount(0);  //动画循环次数为0,表示无限循环
anim->setTimeLine(timeLine); //将时间线加入动画类对象中
anim->setRotationAt(0.5,180); //在动画时间的一半时图形项旋转180度
anim->setRotationAt(1,360);  //在动画执行完时图形项旋转360度
timeLine->start();  //开始动画
2
  

右键菜单

2
3
4
5
QMenu menu;
QAction *action = menu.addAction("moveTo(0,0)");
connect(action,SIGNAL(triggered()),this,SLOT(moveTo()));
menu.exec(event->screenPos()); //在按下鼠标左键的地方弹出菜单

当按下该菜单时,图形项移动到(0,0)点。

场景

QGraphicsScene提供了图形视图框架的场景,它有以下功能:

  • 提供了一个管理大量图形项的快速接口
  • 向每个图形项传播事件
  • 管理图形项的状态,比如选择和焦点处理
  • 提供无转换的渲染功能,主要用于打印

场景层

场景分为三个层:图形项层(ItemLayer)、前景层(ForegroundLayer)和背景层(BackgroundLayer)。

场景的绘制总是从背景层开始,然后是图形项层,最后是前景层。

对于前景层,我们一般不进行设置,或者像上面这样设置为半透明的白色。

2
3
scene.setForegroundBrush(QColor(255,255,255,100));
scene.setBackgroundBrush(Qt::green);
2
//scene.setBackgroundBrush(QPixmap("../graphicsView03/yafeilinux.jpg"));

索引算法

索引算法,是指在场景中进行图形项查找的算法。

QGraphicsScene中提供了两种选择,它们在一个枚举变量QGraphicsScene::ItemIndexMethod中,分别是:

  • QGraphicsSecne::BspTreeIndex :应用Binary Space Partition tree,适合于大量的静态图形项。这个是默认值。
  • QGraphicsScene::NoIndex :不用索引,搜索场景中所有的图形项,适合于经常进行图形项的添加、移动和删除等操作的情况。

我们可以使用setItemIndexMethod()函数进行索引算法的更改。

边界矩形

图形项可以放到场景的任何位置,场景的大小默认是没有限制的。而场景的边界矩形仅用于场景内部进行索引的维护。因为如果没有边界矩形,场景就要搜索所有的图形项,然后确定出其边界,这是十分费时的。所以如果要操作一个较大的场景,我们应该给出它的边界矩形。设置边界矩形,可以使用setSceneRect()函数。

图形项查找

场景最大的优势之一就是可以快速的锁定图形项的位置,即使有上百万个图形项,items()函数也能在数毫秒的时间内锁定一个图形项的位置。items()函数有几个重载函数来方便的进行图形项的查找。但是有时在场景的一个点可能重叠着几个图形项,这时我们可以使用itemAt()函数返回最上面的一个图形项。

事件处理和传播

场景可以传播来自视图的事件,将事件传播给该点最顶层的图形项。但是就像我们在讲图形项时所说的那样,如果一个图形项要接收键盘事件,那么它必须获得焦点。而且,如果我们在场景中重写了事件处理函数,那么在该函数的最后,必须调用场景默认的事件处理函数,只有这样,图形项才能接收到该事件。

打印

视图

QGraphicsView 提供了视图窗口部件,它使场景的内容可视化。你可以给一个场景关联多个视图,从而给一个数据集提供多个视口。视图部件是一个滚动区域,就是说,它可以提供一个滚动条来显示大型的场景。如果要使用OpenGL,你可以使用QGraphicsView::setViewport()函数来添加QGLWidget 。

缩放与旋转

场景边框与场景对齐方式

场景边框(SceneRect:视图是可以提供滚动条的,但是,这只是在视图窗口小于场景时才自动出现的。如果我们不定义场景边框,那么当场景中的图形项移动到视图可视窗口以外的地方时,视图就会自动出现滚动条,但是即使是图形项再次回到可视区域,滚动条也不会消失。为了解决这个问题,我们可以为场景设置边框,这样,当图形项移动到场景边框以外时,视图是不会提供额外的滚动区域的。

而当整个场景都可视时,也就是说视图没有滚动条时,我们可以通过setAlignment()函数来设置场景在视图中的对齐方式,如左对齐Qt::AlignLeft ,向上对齐Qt::AlignTop ,中心对齐Qt::AlignCenter。更多的对齐方式,可以查看帮助中Qt::Alignment 关键字。默认的对齐方式是Qt::AlignCenter 。而且几种对齐方式可以通过“按位或”操作一起使用。

拖动模式

在QGraphicView中提供了三种拖动模式,分别是:

  • QGraphicsView::NoDrag :忽略鼠标事件,不可以拖动。
  • QGraphicsView::ScrollHandDrag :光标变为手型,可以拖动场景进行移动。
  • QGraphicsView::RubberBandDrag :使用橡皮筋效果,进行区域选择,可以选中一个区域内的所有图形项。

我们可以利用setDragMode()函数进行相应设置。

事件传递

在图形视图框架中,鼠标键盘等事件是从视图进入的,视图将它们传递给场景,场景再将事件传递给该点的图形项,如果该点有多个图形项,那么就传给最上面的图形项。所以要想使这个事件能一直传播下去,我们就需要在重新实现事件处理函数时,在其最后将event参数传给默认的事件处理函数。

背景缓冲

如果场景的背景需要大量耗时的渲染,可以利用CacheBackground来缓存背景,当下次需要渲染背景时,可以快速进行渲染。它的原理就是,把整个视口先绘制到一个pixmap上。但是这个只适合较小的视口,也就是说,如果视图窗口很大,而且有滚动条,那么就不再适合缓存背景。我们可以使用setCacheMode(QGraphicsView::CacheBackground);来设置背景缓存。默认设置是没有缓存QGraphicsView::CacheNone。

OpenGL渲染

QGraphicsView默认使用一个QWidget作为视口部件,如果我们要使用OpenGL进行渲染,可以使用setViewport()函数来添加一个QGLWidget对象。

.pro中加入

QT += opengl

说明要使用OpenGL模块

然后在.cpp文件中添加头文件:

#include <QtOpenGL>

最后在构造函数中加入代码:

QGLWidget *widget =new QGLWidget(this);

setViewport(widget);

这样便使用OpenGL进行渲染了。

图形项查找与图形项组

2
3
4
5
QGraphicsItemGroup *group = newQGraphicsItemGroup;  //新建图形项组
group->addToGroup(item1);
group->addToGroup(item2);
scene->addItem(group);
2
  
2
3
4
5
qDebug() << items();  //输出场景中所有的图形项
items().at(0)->setPos(100,0);
items().at(1)->setPos(0,100);
QGraphicsView::keyPressEvent(event); //执行默认的事件处理
2
  

打印

图形视图框架提供了两个打印函数render(),一个是在QGraphicsScene中,一个是在QGraphicsView中,并且它们的函数原型是一模一样的。不过它们实现的效果稍有不同。

2
3
4
5
6
7
rotate(90); //视图旋转顺时针90度
QPixmap pixmap(400,400);  //必须指定大小
QPainter painter(&pixmap);
render(&painter,QRectF(0,0,400,400),QRect(0,0,400,400));  //打印视图指定区域内容
pixmap.save("../graphicsView04/save.png");
QGraphicsView::mousePressEvent(event);

视图的render()函数,其中的QRectF参数是指设备的区域,这里是指pixmap。而QRect参数是指视图上要打印的区域。

使用场景的打印函数

2
scene()->render(&painter,QRectF(0,0,400,400),QRect(0,0,400,400));//打印场景内容

区别:

视图的打印函数是依据视图的坐标系进行打印的,我们看到的就是打印出来后的效果,它可以看做是程序窗口的截屏。

而场景的打印函数,是依据场景的坐标系的,无论视图怎么转换,只要场景坐标系没有变换,它打印出来的图片都是一样的。


第11篇 2D绘图(一)绘制简单图形

第12篇 2D绘图(二)渐变填充

第13篇 2D绘图(三)绘制文字

第14篇 2D绘图(四)绘制路径

第15篇 2D绘图(五)绘制图片

第16篇 2D绘图(六)坐标系统

第17篇 2D绘图(七)涂鸦板

第18篇 2D绘图(八)双缓冲绘图

第19篇 2D绘图(九)图形视图框架(上)

第20篇 2D绘图(十)图形视图框架(下)

作者:Lucas Hsueh
文章部分是自己的学习体会、代码等,还有收集和整理其他技术牛人的文章。

QT-2D编程的更多相关文章

  1. 赠书:HTML5 Canvas 2d 编程必读的两本经典

    赠书:HTML5 Canvas 2d 编程必读的两本经典 这两年多一直在和HTML5 Canvas 打交道,也带领团队开发了世界首款基于HTML5 Canvas 的演示文档工具---AxeSlide( ...

  2. QT核心编程之调试技术 (g)

    Qt应用程序的调试可以通过DDD进行跟踪调试和打印各种调试或警告信息.DDD(Data Display Debugger)是使用gdb调试工具的图形工具,它安装在Linux操作系统中,使用方法可参考D ...

  3. CC++初学者编程教程(9) Windows8.1安装VS2013并捆绑QT与编程助手

    我们在Windows8.1安装VS2013并捆绑QT与编程助手需要下列文件. 2. 在虚拟机中开启Windows8.1 3.然后选择VS2013的安装镜像. 4.将镜像复制到虚拟机. 5.我们装载这个 ...

  4. CC++刚開始学习的人编程教程(9) Windows8.1安装VS2013并捆绑QT与编程助手

    我们在Windows8.1安装VS2013并捆绑QT与编程助手须要下列文件. 2. 在虚拟机中开启Windows8.1 3.然后选择VS2013的安装镜像. 4.将镜像拷贝到虚拟机. 5.我们装载这个 ...

  5. QT5入门之23 -QT串口编程(转)

    QT5入门之23 -QT串口编程   QT5有专门的串口类: QSerialPort:提供访问串口的功能 QSerialPortInfo:提供系统中存在的串口的信息 具体使用方法: 1.在pro文件中 ...

  6. Qt网络编程QTcpServer和QTcpSocket的理解

    前一段时间通过调试Qt源码,大致了解了Qt的事件机制.信号槽机制.毕竟能力和时间有限.有些地方理解的并不是很清楚. 开发环境:Linux((fedora 17),Qt版本(qt-everywhere- ...

  7. Qt界面编程基本操作

    Qt界面编程基本操作 了解基本代码构成 类widget的头文件widget.h如下: #ifndef WIDGET_H #define WIDGET_H #include <QWidget> ...

  8. Qt的编程风格与规范

    Qt的编程风格与规范 来源: http://blog.csdn.net/qq_35488967/article/details/70055490 参考资料: https://wiki.qt.io/Qt ...

  9. Quartz 2D编程指南(1) - 概览

    Quartz 2D编程指南是论坛会员德鲁伊翻译的国外的Quartz 2D一系列学习资料,供大家参考 Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境.我们可以使用Quar ...

  10. Qt 2D绘图之二:抗锯齿渲染和坐标系统

    一.抗锯齿渲染 1.1 逻辑绘图 图形基元的大小(宽度和高度)始终与其数学模型相对应,下图示意了忽略其渲染时使用的画笔的宽度的样子. 1.2 物理绘图(默认情况) 在默认的情况下,绘制会产生锯齿,并且 ...

随机推荐

  1. CSS(层叠样式表)基础知识

     CSS 指层叠样式表 (Cascading Style Sheets).样式定义怎样显示 HTML 元素.它通常存储在样式表中,把样式加入到 HTML 4.0 中,解决内容与表现分离的问题. 当同一 ...

  2. the longest distance of a binary tree

    版权声明:欢迎查看本博客.希望对你有有所帮助 https://blog.csdn.net/cqs_2012/article/details/24880735 the longest distance ...

  3. 「CF741DArpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths」

    题目 这题目名字怎么这么长 zky学长讲过的题 非常显然,就是重排之后能形成回文串的话,最多只能有一个字母出现奇数次 又发现这个字符集大小只有\(22\),于是套路的使用状压,把每一条边转化成一个二进 ...

  4. 【[SDOI2008]Sandy的卡片】

    被\(mhr\)的暴力干翻了 这道题做法还是非常好想的 先做一遍差分,在每个串的某尾插入一个特殊字符,再将所有的串拼接在一起 现在的问题就转化为找到一个最长的公共子串使得其出现了\(n\)次,但是在一 ...

  5. P2585 [ZJOI2006]三色二叉树

    题目描述 输入输出格式 输入格式: 输入文件名:TRO.IN 输入文件仅有一行,不超过500000个字符,表示一个二叉树序列. 输出格式: 输出文件名:TRO.OUT 输出文件也只有一行,包含两个数, ...

  6. 【node.js】REPL(交互式解释器)

    Node 自带了交互式解释器,可以执行以下任务: 读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中. 执行 - 执行输入的数据结构 打印 - 输出结果 循环 - 循环操作 ...

  7. [Python 练习爬虫] XPATH基础语法

    XPATH语法: // 定位根标签 / 往下层寻找 /text() 提取文本内容 /@xxx 提取属性内容 Sample: import requests from lxml import etree ...

  8. git相关命令

    查看分支:git branch创建分支:git branch <name>切换分支:git checkout <name>创建+切换分支:git checkout -b < ...

  9. mac终端输入python默认打开python3

    *** 1. 终端打开.bash_profile文件 ***open ~/.bash_profile *** 2. .bash_profile文件内容 ***# Setting PATH for Py ...

  10. 剑指Offer_编程题之用两个栈实现队列

    题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型.