目录
官方解析
QGraphicsItem除了基于他的坐标pos()外,还支持投影变化。下面提供了几种变化item的方式。下面来说明下简单的转换,可以通过调用setRotation()或setScale(),或者调用setTransform(),这个方式是通过变化矩阵实现的。下面来说明下高级点的操作,可以通过调用setTransformations()选择几个被写好的transformations进行图像变化。
item的转变是从parent到child逐步累计的(这一点和OpenGL感觉有点差别,OpenGL是只对当前矩阵上的物体有影响),举个栗子,如果一个parentItem和childItem同时被设置旋转90度,那么childItem最后将旋转180读。同样的道理,如果一个parent item在他的原始尺寸上放大了2倍,那么他所有的child item都会被放大2倍。当一个item被转化成其他形态后他自己的坐标系将不受影响(这个功能牛逼,赞一下);所有的关于几何的函数(比如contains(),update(),所有的mapping函数)都将可以在他原坐标系进行操作。为了方便,QGraphicsItem提供了一个叫sceneTransform()的函数,这个函数返回这个Item的总变化矩阵(包括他的位置,和所有parent的坐标以及transformations)以及他在场景中的位置。调用resetTransform()可以重设他的变化矩阵。
在线性代数里面,矩阵是不具有交换率的,所以不同顺序的操作,会有不同的转变。举个栗子,放大后旋转和旋转后放大将造成不同的结果。但是在QgraphicsItem中却可以进行这样的骚操作,也就是有交换律;QGraphicsItem有着他固定的操作,顺序如下:
1.调用transform实现最基本的转换(transform);
2.item是按照transformatins列表进行的(transformations());
3.item的旋转依赖于他转换的源坐标(rotation(),transformOriginPoint());
4.item的放缩也依赖于他的源坐标(scale(),transformOriginPoint())。
博主小栗子
运行截图如下:
源码如下:
mygraphicsitem.h
#ifndef MYGRAPHICSITEM_H
#define MYGRAPHICSITEM_H
#include <QGraphicsItem>
class MyGraphicsItem:public QGraphicsItem
{
public:
MyGraphicsItem();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const;
};
#endif // MYGRAPHICSITEM_H
mygraphicsview.h
#ifndef MYGRAPHICSVIEW_H
#define MYGRAPHICSVIEW_H
#include <QGraphicsView>
QT_BEGIN_NAMESPACE
class QGraphicsScene;
class QGraphicsItem;
class QTimeLine;
QT_END_NAMESPACE
class MyGraphicsItem;
class MyGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit MyGraphicsView(QWidget *parent = 0);
public slots:
void updateStep(int value);
void finished();
signals:
void mousePos();
protected:
void mouseMoveEvent(QMouseEvent *event)Q_DECL_OVERRIDE;
private:
QGraphicsScene *m_scene;
QList<QGraphicsItem*> m_list;
QTimeLine *m_timeLine;
MyGraphicsItem *m_currentItem;
bool timeLineIsRun;
};
#endif // MYGRAPHICSVIEW_H
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void mouseMoveEvent();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
mygraphicsitem.cpp
#include "mygraphicsitem.h"
#include <QPainter>
MyGraphicsItem::MyGraphicsItem()
{
}
void MyGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->save();
painter->setPen(QPen(Qt::red,4));
painter->drawRect(0,0,50,50);
painter->restore();
}
QRectF MyGraphicsItem::boundingRect() const
{
return QRectF(0,0,50,50);
}
mygraphicsview.cpp
#include "mygraphicsview.h"
#include "mygraphicsitem.h"
#include <QGraphicsScene>
#include <QTransform>
#include <QMouseEvent>
#include <QTimeLine>
#include <QDebug>
MyGraphicsView::MyGraphicsView(QWidget *parent)
: QGraphicsView(parent)
{
MyGraphicsItem *item=new MyGraphicsItem;
m_scene=new QGraphicsScene;
this->setScene(m_scene);
m_scene->addItem(item);
m_list.append(item);
setMouseTracking(true);
m_timeLine=new QTimeLine;
m_timeLine->setFrameRange(0,500);
connect(m_timeLine,SIGNAL(frameChanged(int)),this,SLOT(updateStep(int)));
connect(m_timeLine,SIGNAL(finished()),this,SLOT(finished()));
m_currentItem=NULL;
timeLineIsRun=false;
}
void MyGraphicsView::updateStep(int value)
{
if(m_currentItem==NULL&&timeLineIsRun)
return;
// QPointF pt=m_currentItem->boundingRect().center();
// m_currentItem->setTransformOriginPoint(pt); //it only works for item. isn't QTransform
// m_currentItem->setRotation(value);
// QPointF pt=m_currentItem->boundingRect().center();
// qreal scaleX_Y=value/100.0;
// QTransform tran;
// tran.translate(pt.x(),pt.y()); //move to center
// tran.scale(scaleX_Y,scaleX_Y);
// m_currentItem->setTransform(tran);
// QTransform t;
// t.translate(-pt.x(), -pt.y()); //equal to reset
// m_currentItem->setTransform(t, true);
QPointF pt=m_currentItem->boundingRect().center();
qreal angle=value/2.0;
QTransform transform;
transform.translate(pt.x(),pt.y()); //move to center
transform.rotate(angle,Qt::XAxis);
m_currentItem->setTransform(transform);
QTransform t;
t.translate(-pt.x(), -pt.y()); //equal to reset
m_currentItem->setTransform(t, true);
update();
}
void MyGraphicsView::finished()
{
qDebug()<<"finished!";
timeLineIsRun=!timeLineIsRun;
m_currentItem->resetTransform();
m_currentItem=NULL;
}
void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
QGraphicsView::mouseMoveEvent(event);
QTransform transform;
QGraphicsItem *item=m_scene->itemAt(mapToScene(event->pos()),transform);
if(item&&!timeLineIsRun){
//makes item's view big or small
m_currentItem=static_cast<MyGraphicsItem*>(item);
m_timeLine->start();
timeLineIsRun=!timeLineIsRun;
}
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "mygraphicsitem.h"
#include <QGraphicsScene>
#include <QTransform>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}