`
bbsunchen
  • 浏览: 224746 次
  • 性别: Icon_minigender_1
  • 来自: 天朝帝都
社区版块
存档分类
最新评论

QT 2D绘图的坐标系统与图形显示

Qt 
阅读更多

这篇文章中,给出Qt坐标系统的详细介绍,在附件中,给出使用Qt制作的绘图程序,类似于windows中的画图程序。

整合了网络中可见的所有Qt绘图资源

一、坐标系简介。

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

例如:

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setBrush(Qt::red);
painter.drawRect(0,0,100,100);
painter.setBrush(Qt::yellow);
painter.drawRect(-50,-50,100,100);
}

我们先在原点(0,0)绘制了一个长宽都是100像素的红色矩形,又在(-50,-50)点绘制了一个同样大小的黄色矩形。可以看到,我们只能看到黄色矩形的一部分。效果如下图。

二、坐标系变换。

坐标系变换是利用变换矩阵来进行的,我们可以利用QTransform类来设置变换矩阵,因为一般我们不需要进行更改,所以这里不在涉及。下面我们只是对坐标系的平移,缩放,旋转,扭曲等应用进行介绍。

1.利用translate()函数进行平移变换。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setBrush(Qt::yellow);
painter.drawRect(0,0,50,50);

painter.translate(100,100); //将点(100,100)设为原点

painter.setBrush(Qt::red);
painter.drawRect(0,0,50,50);

painter.translate(-100,-100);

painter.drawLine(0,0,20,20);
}
效果如下。

这里将(100,100)点作为了原点,所以此时(100,100)就是(0,0)点,以前的(0,0)点就是

(-100,-100)点。要想使原来的(0,0)点重新成为原点,就是将(-100,-100)设为原点。

2.利用scale()函数进行比例变换,实现缩放效果。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setBrush(Qt::yellow);
painter.drawRect(0,0,100,100);

painter.scale(2,2); //放大两倍

painter.setBrush(Qt::red);
painter.drawRect(50,50,50,50);
}
效果如下。

可以看到,painter.scale(2,2),是将横纵坐标都扩大了两倍,现在的(50,50)点就相当于以前的

(100,100)点。

3.利用shear()函数就行扭曲变换。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setBrush(Qt::yellow);
painter.drawRect(0,0,50,50);

painter.shear(0,1); //纵向扭曲变形
painter.setBrush(Qt::red);
painter.drawRect(50,0,50,50);
}
效果如下。

这里,painter.shear(0,1),是对纵向进行扭曲,0表示不扭曲,当将第一个0更改时就会对横行进行扭曲,关于扭曲变换到底是什么效果,你观察一下是很容易发现的。

4.利用rotate()函数进行比例变换,实现缩放效果。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawLine(0,0,100,0);

painter.rotate(30); //以原点为中心,顺时针旋转30度
painter.drawLine(0,0,100,0);

painter.translate(100,100);
painter.rotate(30);
painter.drawLine(0,0,100,0);
}
效果如下。

因为默认的rotate()函数是以原点为中心进行顺时针旋转的,所以我们要想使其以其他点为中心进行旋转,就要先进行原点的变换。这里的painter.translate(100,100)将(100,100)设置为新的原点,想让直线以其为中心进行旋转,可是你已经发现效果并非如此。是什么原因呢?我们添加一条语句,如下:

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawLine(0,0,100,0);

painter.rotate(30); //以原点为中心,顺时针旋转30度
painter.drawLine(0,0,100,0);

painter.rotate(-30);

painter.translate(100,100);
painter.rotate(30);
painter.drawLine(0,0,100,0);
}

效果如下。

这时就是我们想要的效果了。我们加的一句代码为painter.rotate(-30),这是因为前面已经将坐标旋转了30度,我们需要将其再旋转回去,才能是以前正常的坐标系统。不光这个函数如此,这里介绍的这几个函数均如此,所以很容易出错。下面我们将利用两个函数来很好的解决这个问题。

三、坐标系状态的保护。

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

例如:

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.save(); //保存坐标系状态
painter.translate(100,100);
painter.drawLine(0,0,50,50);

painter.restore(); //恢复以前的坐标系状态
painter.drawLine(0,0,50,50);
}
效果如下。

利用好这两个函数,可以实现快速的坐标系切换,绘制出不同的图形。

_____________________________________________________________________________

为了更清楚地获得坐标信息,我们这里利用鼠标事件,让鼠标点击左键时输出该点的坐标信息。

1.在工程中的dialog.h文件中添加代码。

添加头文件: #include <QMouseEvent>

在public中添加函数声明:void mousePressEvent(QMouseEvent *);

然后到dialog.cpp文件中:

添加头文件: #include <QDebug>

定义函数:

void Dialog::mousePressEvent(QMouseEvent *event)
{
qDebug() << event->pos();
}

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

2.然后更改重绘事件函数。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawRect(0,0,50,50);

}

我们绘制了一个左上顶点为(0,0),宽和高都是50的矩形。

3.这时运行程序。并在绘制的矩形左上顶点点击一下鼠标左键。效果如下。(点击可看大图)


因为鼠标点的不够准确,所以输出的是(1,0),我们可以认为左上角就是原点(0,0)点。你可以再点击一下矩形的右下角,它的坐标应该是(50,50)。这个方法掌握了以后,我们就开始研究这些坐标了。

研究放大后的坐标

1.我们现在进行放大操作,然后查看其坐标的变化。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.scale(2,2); //横纵坐标都扩大2倍
painter.drawRect(0,0,50,50);
}

我们将横纵坐标都扩大2倍,然后运行程序,查看效果:


我们点击矩形右下顶点,是(100,100),比以前的(50,50)扩大了2倍。

研究QPixmap或QImage的坐标

对于QWidget,QPixmap或QImage等都是绘图设备,我们都可以在其上利用QPainter进行绘图。现在我们研究一下QPixmap的坐标(QImage与其效果相同)。

1.我们更改重绘事件函数如下。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pix(200,200);
pix.fill(Qt::red); //背景填充为红色
painter.drawPixmap(0,0,pix);
}

这里新建了一个宽、高都是200像素的QPixmap类对象,并将其背景颜色设置为红色,然后从窗口的原点(0,0)点添加该QPixmap类对象。为了表述方便,在下面我们将这个QPixmap类对象pix称为画布。

我们运行程序,并在画布的左上角和右下角分别点击一下,效果如下:

可以看到其左上角为(0,0)点,右下角为(200,200)点,是没有问题的。

2.我们再将函数更改如下。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pix(200,200);
pix.fill(Qt::red); //背景填充为红色
painter.drawPixmap(100,100,pix);
}

这时我们从窗口的(100,100)点添加该画布,那么此时我们再点击画布的右上角,其坐标会是多少呢?

可以看到,它是(100,100),没错,这是窗口上的坐标,那么这是不是画布上的坐标呢?

3.我们接着更改函数。

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pix(200,200);
pix.fill(Qt::red); //背景填充为红色
QPainter pp(&pix); //新建QPainter类对象,在pix上进行绘图
pp.drawLine(0,0,50,50); //在pix上的(0,0)点和(50,50)点之间绘制直线
painter.drawPixmap(100,100,pix);
}

这里我们又新建了一个QPainter类对象pp,其中pp(&pix)表明,pp所进行的绘图都是在画布pix上进行的。

现在先说明一下:

QPainter painter(this) ,this就表明了是在窗口上进行绘图,所以利用painter进行的绘图都是在窗口上的,painter进行的坐标变化,是变化的窗口的坐标系;而利用pp进行的绘图都是在画布上进行的,如果它进行坐标变化,就是变化的画布的坐标系。

我们在画布上的(0,0)点和(50,50)点之间绘制了一条直线。这时运行程序,点击这条直线的两端,看看其坐标值。

结果是直线的两端的坐标分别是(100,100),(150,150)。我们从中可以得出这样的结论:

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

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

下面我们继续研究:

4.比较下面两个例子。

例子一:

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pix(200,200);

qDebug() << pix.size(); //放大前输出pix的大小

pix.fill(Qt::red);
QPainter pp(&pix);
pp.scale(2,2); //pix的坐标扩大2倍
pp.drawLine(0,0,50,50); //在pix上的(0,0)点和(50,50)点之间绘制直线

qDebug() << pix.size(); //放大后输出pix的大小

painter.drawPixmap(0,0,pix);
}

例子二:

void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pix(200,200);

qDebug() << pix.size(); //放大前输出pix的大小

painter.scale(2,2); //窗口坐标扩大2倍

pix.fill(Qt::red);
QPainter pp(&pix);
pp.drawLine(0,0,50,50); //在pix上的(0,0)点和(50,50)点之间绘制直线

qDebug() << pix.size(); //放大后输出pix的大小

painter.drawPixmap(0,0,pix);
}

两个例子中都使直线的长度扩大了两倍,但是第一个例子是扩大的画布的坐标系,第二个例子是扩大的窗口的坐标系,你可以看一下它们的效果。

你仔细看一下输出,两个例子中画布的大小都没有变。

如果你看过了我写的那个绘图软件的教程链接过去),现在你就能明白我在其中讲“问题一”时说的意思了:虽然画布看起来是大了,但是其大小并没有变,其中坐标也没有变。变的是像素的大小或者说像素间的距离。

但是,有一点你一定要搞明白,这只是在QPixmap与QWidget结合时才出现的,是相对的说法。其实利用scale()函数是会让坐标变化的,我们在开始的例子已经证明了。

结论:

现在是不是已经很乱了,一会儿是窗口,一会儿是画布,一会儿坐标变化,一会儿又不变了,到底是怎么样呢?

其实只需记住一句话:

所有的绘图设备都有自己的坐标系统,它们互不影响。

<!-- end .entry -->

0
0
分享到:
评论

相关推荐

    【Qt】2D绘图之坐标系统.rar

    【Qt】2D绘图之坐标系统.rar

    QT经典教程_详细一步一步例子

    十七、Qt 2D绘图(七)Qt坐标系统深入 十八、Qt 2D绘图(八)涂鸦板 十九、Qt 2D绘图(九)双缓冲绘图简介 二十、Qt 2D绘图(十)图形视图框架简介 二十一、Qt数据库(一)简介 二十二、Qt数据库(二)添加MySQL...

    qt坐标系详细讲解

    qt 2d绘图的资料,里面包含了坐标机制,很详细

    Qt 2D绘图基础.rar_8DM1_QT_QT 2D绘图_mousewu3_绘图

    该文档为归纳基本的绘图知识点。 知识点包括绘图中的画笔,画刷填充设置;坐标系统;绘制文字,绘制路径,绘制图像等。

    QT creator 教程

    十七、Qt 2D绘图(七)Qt坐标系统深入 十八、Qt 2D绘图(八)涂鸦板 十九、 Q t 2D 绘图(九)双缓冲绘图简介 二十、Qt 2D绘图(十)图形视图框架简介 二十一、Qt数据库(一)简介 二十二、Qt数据库(二)添加MySQL...

    qt新的绘制2D图形框架

    qt新的绘制2D图形框架,取代QT3中的Canvas模块。GraphicsView框架实现了模型-视图结构的图形管理,能对大量图元进行管理,支持碰撞检测,坐标变换和图元组等多种方便的功能。

    QT 绘图函数

    前面一节我们讲解了图片的显示,其中很多都用到了坐标的变化,这一节我们简单讲一下Qt的坐标系统,其实也还是主要讲上一节的那几个函数。这里我们先讲解一下Qt的坐标系,然后讲解那几个函数,它们分别是: translate...

    精通qt4编程(源代码)

    \中级篇 第6章 2D绘图 蔡志明本章内容较多,包括Qt的绘图要素、图形变换与坐标系统、绘图设备、图像处理、图像打印等。最后讲解了Qt 4图形系统的模型视图框架——Graphics View框架。 152 \ 第7章 拖放操作与剪贴板 ...

    精通Qt4编程(第二版)源代码

    初 级 篇 \第1章 Qt初步实践 2 \1.1 第一个Qt程序 2 ...\中级篇 第6章 2D绘图 蔡志明本章内容较多,包括Qt的绘图要素、图形变换与坐标系统、绘图设备、图像处理、图像打印等。最后讲解了Qt 4图形系统的模型视图...

    Qt绘图控件QCustomPlot资源

    QCustomPlot是为了绘图和数据可视化而产生...这个控件关注于好看,高质量2D绘图,图形和图表,以及可视化应用程序实时的效率。此控件使用起来非常简单,不像QWT那样。也可以自己使用两个源文件编译生成库文件,非常方便。

    Qt画扇形方式实现模拟时钟

    使用QPainter的2D绘图画扇形方式实现一个模拟时钟,从中可以对Qt的坐标系有初步理解。同时学习如何画扇形。

    Qt Creator 的安装和hello world 程序+其他程序的编写--不是一般的好

    第二个按钮我们自己写了槽函数语句,其实图形的设计与直接写代码效果是 一样的。 这个程序里我们实现了两类窗口打开的方式,一个是自身消失而 后打开另一个窗口,一个是打开另一个窗口而自身不消失。可以看到他们...

    QCustomPlot source yuanma

    该绘图库专注于制作美观、出版物质量高的2D绘图、图形和图表,并为实时可视化应用程序提供高性能。 QCustomPlot官网下载:https://www.qcustomplot.com/index.php/download QCustomPlot 图表类:用于图表的显示和...

    图片缩放与旋转的资源代码

    图片的缩放与旋转是图像处理的常用功能。QMatrix类提供了坐标系统的2D转化功能,可以使窗体转化变形,经常在绘图程序中使用,QMatrix可以实现坐标系统的移动、缩放、变形以及旋转功能

    OpenGL实现鼠标移动方块

    注意:方块的绘图坐标系和世界坐标系是重合的,鼠标所在的坐标是以窗口的左上角为原点(0,0)的坐标系,窗口的左下角的世界坐标系为gluOrho2D(left, right, bottom, top)中的(left, bottom)。所以鼠标的坐标...

    matlab改变代码字体-MathGL.jl:MathGL库周围的包装器,用于数学和科学绘图

    []是世界一流的开源图形库,可处理1D,2D和3D数据阵列,总共支持50多种不同类型的图。 如文档的以下摘录所示,它还具有许多其他重要功能,例如: 任意曲线线性坐标系, 几种类型的透明度和平滑的照明 矢量字体和$ \ ...

Global site tag (gtag.js) - Google Analytics