1.    坐标系简介

Qt中每一个窗口都有自己的一个坐标系,默认窗口左上角为坐标原点(0,0),然后水平向右依次增大(X轴),垂直向下依次增大(Y轴)。例如:


void  MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );


paint.setBrush(Qt::green );


paint.drawRect(0, 0, 100, 100 );


paint.setBrush(Qt::red );


paint.drawRect(-50, -50, 100, 100 );


}

上例中,先在原点(0,0)绘制了一个长、宽都是100像素的绿色矩形,然后在点(-50,-50)绘制了一个同样大小(长、宽均为100像素)的红色矩形,只能看到红色矩形的一部分。

效果图如下:



这是因为在点(-50,-50)绘制的长、宽各100图形的其它3/4均被窗体遮挡了。


2.    坐标系变换。

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


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


void  MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );


paint.setBrush(Qt::green );


paint.drawRect(0, 0, 100, 100 );




paint.translate(100, 100 );


// 坐标变换,重新把点(100,100)作为原点


paint.setBrush(Qt::red );


paint.drawRect(0, 0, 100, 100 );




paint.translate(-100, -100 );


// 坐标变换,移动(-100,-100)恢复至原点(0,0)


paint.drawLine(0, 0, 50, 50 );


}

效果图如下:

这里将(100,100)点作为了原点,所以此时(100,100)就是(0,0)点,以前的(0,0)点就是(-100,-100)点。要想使原来的(0,0)点重新成为原点,就是将(-100,-100)设为原点。


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


void  MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );



paint.setBrush(Qt::green );


paint.drawRect(0, 0, 100, 100 );




paint.scale( 2, 2);


//paint放大两倍


paint.setBrush(Qt::red );


paint.drawRect(50, 50, 50, 50 );




paint.scale( 0.5,0.5 );


// paint缩小一半(恢复原来)


paint.setBrush(Qt::yellow );


paint.drawEllipse(0, 0, 100, 100 );


}

效果图如下:

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


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


void  MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );


paint.setBrush(Qt::green );


paint.drawRect(0, 0, 100, 100 );




paint.shear( 0, 1 );


// 纵向扭曲1倍


paint.setBrush(Qt::red );


paint.drawRect(0, 100, 100, 100 );




paint.shear( 0, -1);




// 恢复原状


paint.setBrush(Qt::yellow );


paint.drawEllipse(0, 0, 100, 100 );


}

效果图如下:

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


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


void  MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );


paint.drawLine(0, 0, 100, 0 );




paint.rotate( 30);


// 顺时针旋转30度


paint.drawLine(0, 0, 100, 0 );


paint.translate(100, 100 );


// 坐标变换, 原点(0,0)移至(100,100)点


paint.drawLine(0, 0, 100, 0 );


paint.rotate( 30);


// 顺时针旋转30度


paint.drawLine(0, 0, 100, 0 );


}

效果图如下:

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


void  MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );


paint.drawLine(0, 0, 100, 0 );




paint.rotate(30 );


// 顺时针旋转30度


paint.drawLine(0, 0, 100, 0 );


paint.rotate( -30 );


paint.translate(100, 100 );               // 坐标变换, 原点(0,0)移至(100,100)点


paint.drawLine(0, 0, 100, 0 );




paint.rotate(30 );


// 顺时针旋转30度


paint.drawLine(0, 0, 100, 0 );


}

效果图如下:


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


3.    坐标系状态的保护。

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

例如:


void MyDraw::paintEvent( QPaintEvent * )


{


QPainterpaint( this );




paint.save();


// 保存坐标状态


paint.translate(100, 100 );


paint.setBrush(Qt::green );


paint.drawRect(0, 0, 100, 100 );


paint.drawLine(0, 0, 50, 50 );


paint.restore();


// 恢复坐标状态


paint.setBrush(Qt::red );


paint.drawRect(0, 0, 100, 100 );


paint.drawLine(0, 0, 50, 50 );


}

效果图如下:

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



源代码如下:

/*******************************************************
* Qt coordinates and Painter
*
* Version: Qt 3.1.2 
* Author : yanggang2050@gmail.com
* Date   : 2011.06.28 23:08:12
*
*******************************************************/

#include <qapplication.h>
#include <qwidget.h>

#include <qpainter.h>
#include <qmessagebox.h>

class MyDraw : public QWidget
{

public:
	void paintEvent( QPaintEvent * );		// 绘制图形
	void mousePressEvent( QMouseEvent * );	// 获取鼠标位置
};

///////////////////////////////////////////////
//   绘制图形(以下paintEvent一次使用一个)   ///
///////////////////////////////////////////////

/******* 1 paint *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.setBrush( Qt::green );
	paint.drawRect( 0, 0, 100, 100 );
	paint.setBrush( Qt::red );
	paint.drawRect( -50, -50, 100, 100 );
}

/******* 2.1 translate *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.setBrush( Qt::green );
	paint.drawRect( 0, 0, 100, 100 );

	paint.translate( 100, 100 );	// 坐标变换,重新把点(100,100)作为原点

	paint.setBrush( Qt::red );
	paint.drawRect( 0, 0, 100, 100 );

	paint.translate( -100, -100 );	// 坐标变换,移动(-100,-100)恢复至原点(0,0)

	paint.drawLine( 0, 0, 50, 50 );
}


/******* 2.2 scale *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.setBrush( Qt::green );
	paint.drawRect( 0, 0, 100, 100 );

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

	paint.setBrush( Qt::red );
	paint.drawRect( 50, 50, 50, 50 );

	paint.scale( 0.5, 0.5 );	// paint缩小一半(恢复原来)

	paint.setBrush( Qt::yellow );
	paint.drawEllipse( 0, 0, 100, 100 );
}

/******* 2.3 shear *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.setBrush( Qt::green );
	paint.drawRect( 0, 0, 100, 100 );

	paint.shear( 0, 1 );	// 纵向扭曲1倍

	paint.setBrush( Qt::red );
	paint.drawRect( 0, 100, 100, 100 );

	paint.shear( 0, -1 );	// 恢复原状

	paint.setBrush( Qt::yellow );
	paint.drawEllipse( 0, 0, 100, 100 );
}

/******* 2.4 rotate *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.drawLine( 0, 0, 100, 0 );

	paint.rotate( 30 );				// 顺时针旋转30度
	paint.drawLine( 0, 0, 100, 0 );

	paint.translate( 100, 100 );	// 坐标变换, 原点(0,0)移至(100,100)点
	paint.drawLine( 0, 0, 100, 0 );

	paint.rotate( 30 );				// 顺时针旋转30度
	paint.drawLine( 0, 0, 100, 0 );
}

/******* 2.4-2 rotate *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.drawLine( 0, 0, 100, 0 );

	paint.rotate( 30 );				// 顺时针旋转30度
	paint.drawLine( 0, 0, 100, 0 );

	paint.rotate( -30 );
	paint.translate( 100, 100 );	// 坐标变换, 原点(0,0)移至(100,100)点
	paint.drawLine( 0, 0, 100, 0 );

	paint.rotate( 30 );				// 顺时针旋转30度
	paint.drawLine( 0, 0, 100, 0 );
}


/******* 3 save - restore *******/
void MyDraw::paintEvent( QPaintEvent * )
{
	QPainter paint( this );

	paint.save();		// 保存坐标状态
	paint.translate( 100, 100 );
	paint.setBrush( Qt::green );
	paint.drawRect( 0, 0, 100, 100 );
	paint.drawLine( 0, 0, 50, 50 );

	paint.restore();	// 恢复坐标状态
	paint.setBrush( Qt::red );
	paint.drawRect( 0, 0, 100, 100 );
	paint.drawLine( 0, 0, 50, 50 );
}



// 获取鼠标位置
void MyDraw::mousePressEvent( QMouseEvent * e)
{
	QString mousePos = "X = " + QString::number( e->pos().x() ) + " " 
				   + "Y = " + QString::number( e->pos().y() );

	QMessageBox::information( this, tr("获取鼠标点击位置"), mousePos );
}

// 主函数
int main(int argc, char **argv)
{
	QApplication app(argc, argv);

	MyDraw draw;
	app.setMainWidget( &draw );
	draw.show();

	return app.exec();
}



原文: Qt坐标绘图