Qt QPainter中坐标系变换问题

44 篇文章 4 订阅

一、坐标系简介。

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);
}
效果如下。


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

转载自:http://blog.sina.com.cn/s/blog_67cf08270100ww0p.html

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
本资源为Qt绘图基础,世界坐标系转换为逻辑坐标系。世界坐标系原点在视图左上角,本例子通过世界坐标转换,将坐标原点定位在视图央,Y轴向上,X轴向右,并绘制坐标轴,基于逻辑坐标系下的绘图,可将转换关系函数取消生效,对比世界坐标系下的绘图。 重写PainterEvent函数: void QtPixPainter::paintEvent(QPaintEvent* event) { QPainter painter(this); // 反走样 painter.setRenderHint(QPainter::Antialiasing, true); //物理坐标系与逻辑坐标系的转换,如果不转换,下面的绘图都是在世界坐标系下 setWorldTransform(painter); // 其他一些绘制矩形,多边形的例子,经过上面转换,都是在逻辑坐标系下 drawRectScale(painter); //draw_shearRect(painter); //利用rotate()函数进行比例变换,实现缩放效果 //draw_rotate_act(painter); //draw_by_save_restore(painter); //transform_draw_SinX(painter); transform_draw(painter); local_drawConvexPolygon(painter); } // 将世界坐标(原点左上角)转换为逻辑坐标(原点在屏幕间) QPointF QtPixPainter::mapToScene(const QPointF& point) { QTransform transMatrix = _transform.inverted(); //翻转矩阵? return transMatrix.map(point); //将点piont映射到transMatrix定义的坐标系来 } // 将鼠标的逻辑位置返回并以标签形式展示 void QtPixPainter::mouseMoveEvent(QMouseEvent* event) { QString msg; QPointF mouse_po = mapToScene(event->pos()); //总是返回屏幕物理坐标系 double x = mouse_po.x(); // 总是返回屏幕物理坐标系 double y = mouse_po.y(); QString str = "(" + QString::number(x) + "," + QString::number(y) + ")"; //qDebug()<<"world x = "<pos().x()<<",world y = "<pos().y(); m_mouse_lable->setText(str); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值