Qt坐标系统

    Qt的坐标系统是由QPainter类控制的,而QPainter是在绘图设备上进行绘制的。一个绘图设备的默认坐标系统中,原点(0,0)在其左上角,x坐标向右增长,y坐标向下增长。

    QPainter的逻辑坐标与绘图设备的物理坐标之间的映射由QPainter的变换矩阵、视口和窗口处理。逻辑坐标和物理坐标默认是一致的。QPainter也支持坐标变换(比如旋转和缩放)。相关内容可在Qt帮助中输入Coordinate System关键字查看。


基本变换

     默认的,QPainter在相关设备的坐标系统上进行操作,但是它也完全支持仿射坐标变换。绘图时可以用QPainter::scale()函数缩放坐标系统,使用QPainter::rotate()函数顺时针旋转坐标系统,使用QPainter::translate()函数平移坐标系统,使用QPainter::shear()围绕原点扭曲坐标系统。

    坐标系统的2D变换由QTransform类实现,QTransform类对象可以存储多个变换操作,当同样的变换需要多次使用时,建议使用QTransform类对象。

QPainter的坐标变换方法的应用实例:

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    // 填充界面背景为白色
    painter.fillRect(rect(), Qt::white);
    painter.setPen(QPen(Qt::red, 11));
    // 绘制一条线段
    painter.drawLine(QPoint(5, 6), QPoint(100, 99));
    // 将坐标系统进行平移,使(200, 150)点作为原点
    painter.translate(200, 150);
    // 开启抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
    // 重新绘制相同的线段
    painter.drawLine(QPoint(5, 6), QPoint(100, 99));

    // 保存painter的状态
    painter.save();
    // 将坐标系统旋转90度
    painter.rotate(90);
    painter.setPen(Qt::cyan);
    // 重新绘制相同的线段
    painter.drawLine(QPoint(5, 6), QPoint(100, 99));
    // 恢复painter的状态
    painter.restore();

    painter.setBrush(Qt::darkGreen);
    // 绘制一个矩形
    painter.drawRect(-50, -50, 100, 50);
    painter.save();
    // 将坐标系统进行缩放
    painter.scale(0.5, 0.4);
    painter.setBrush(Qt::yellow);
    // 重新绘制相同的矩形
    painter.drawRect(-50, -50, 100, 50);
    painter.restore();

    painter.setPen(Qt::blue);
    painter.setBrush(Qt::darkYellow);
    // 绘制一个椭圆
    painter.drawEllipse(QRect(60, -100, 50, 50));
    // 将坐标系统进行扭曲
    painter.shear(1.5, -0.7);
    painter.setBrush(Qt::darkGray);
    // 重新绘制相同的椭圆
    painter.drawEllipse(QRect(60, -100, 50, 50));

}

结果:



QTransform类的应用实例

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setMouseTracking(true);

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000);
    angle = 0;

    this->resize(400,300);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    angle += 10;
    if(angle == 360)
        angle = 0;
    int side = qMin(width(), height());
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    QTransform transform;
    //Moves the coordinate system width()/2 along the x axis and height()/2 along the y axis, and returns a reference to the matrix.
    transform.translate(width()/2, height()/2);
    //Scales the coordinate system by side/300.0 horizontally and side/300.0 vertically, and returns a reference to the matrix.
    transform.scale(side/300.0, side/300.0);
    transform.rotate(angle);
    painter.setWorldTransform(transform);
    painter.drawEllipse(-120, -120, 240, 240);
    painter.drawLine(0, 0, 100, 0);
}

结果:



窗口-视口转换

    使用QPainter进行绘制时,会使用逻辑坐标进行绘制,然后再转换为绘图设备的物理坐标。逻辑坐标到物理坐标的映射由QPainter的worldTransform( )函数、QPainter的viewport( )以及window( )函数进行处理。其中,视口(viewport)表示物理坐标下指定的一个任意矩形,而窗口(window,与窗口部件的概念不同)表示逻辑坐标下的相同矩形。默认的,逻辑坐标和物理坐标是重合的,它们都相当于绘图设备上的矩形。

    使用窗口-视口转换可以使逻辑坐标系统适合应用要求,令绘图代码独立于绘图设备。如下代码可使逻辑坐标以(-50, -50)为原点,宽为100,高为100。

QPainter painter(this);
painter.setWindow(QRect(-50,-50,100,100));

    现在逻辑坐标的(-50, -50)对应绘图设备的物理坐标的(0,0)点。当设置窗口或者视口矩形时,实际上是执行了坐标的一个线性变换,窗口的4个角会映射到视口对应的4个角,反之亦然。因此,一个很好的一个办法是让视口和窗口维持相同的宽高比来防止形变。如果设置了逻辑坐标系统为一个正方形,那么也需要设置视口为一个正方形,如下代码将视口设置为适合绘图设备矩形的最大矩形:

int side = qMin(width(),height());
int x = (width()-side/2);
int y = (height()-side/2);
painter.setViewport(x,y,side,side);

一个应用实例:

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setMouseTracking(true);
    this->resize(400,300);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setWindow(-50, -50, 100, 100);
    painter.setBrush(Qt::green);
    painter.drawRect(0, 0, 20, 20);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    QString pos = QString("%1,%2").arg(event->pos().x()).arg(event->pos().y());
    QToolTip::showText(event->globalPos(), pos, this);    
}

    可以看出绘制的正方形发生了形变,成为了一个长方形。这是由于我们设置widget的宽为400,高为300,而我们设置逻辑坐标矩形为以(-50,-50)为起点,宽100,高100。按比例对应,在水平方向,逻辑坐标的一个单位对应物理坐标的4个单位;在垂直方向,逻辑坐标的一个单位对应物理坐标的3个单位。所以逻辑坐标中宽20、高20的矩形在物理坐标中就是宽80、高60的矩形。为了防止形变,需要将视口的宽和高的对应比例设置为相同值,即把视口也设置为一个正方形。更改paintEvent()函数如下:

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    int side = qMin(width(), height());
    int x = (width() / 2);
    int y = (height() / 2);
    // 设置视口
    painter.setViewport(x, y, side, side);
    painter.setWindow(0, 0, 100, 100);
    painter.setBrush(Qt::green);
    painter.drawRect(0, 0, 20, 20);
}

结果:

    
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值