Qt Graphics入门小例以及实现场景中相关项拖拽功能总结.

源码之前了无秘密:<直接拷贝这段代码自己运行下就知道大致了>

相关开发中碰到问题代码中已有向导性开发解说,太深入的过程暂时没有时间研究,见谅,仅当入门小例.<下文附别人总结详细解说>

MyWidget.h文件
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QGraphicsScene>
#include <QGraphicsLineItem>
#include <QGraphicsPixmapItem>
#include <QGraphicsTextItem>
#include <QGraphicsPixmapItem>
#include <QGraphicsItemAnimation>
#include <QTimeLine>
#include <QPrintPreviewDialog>  // preview
#include <QPrintDialog>         // print
// display scene
#include <QGraphicsView>
#include <QTimer>
#include <QDateTime>
class MyWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = 0);
  //  void paintEvent(QPaintEvent *);
    QGraphicsScene* _scene;  // data model
    QGraphicsView* _view;   // show the data model
    void resizeEvent(QResizeEvent *);
    void mousePressEvent(QMouseEvent *event);
signals:
public slots:
   // void slotPaintRequested(QPrinter*);
};
#endif // MYWIDGET_H


MyWidget.cpp文件

#include "MyWidget.h"
#include <QApplication>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QDebug>
#include <QPrinter>
#include <qabstractitemview.h>
 
 // 主脉络开发过程:创建视图,视图设置场景setScene.场景进行相关项目添加选入.
 
MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent)
{
/*
    工程解说写在这里:
    主要利用MVC思想:场景,视图,控制.
    QGraphicsScene:场景
    QGraphicsView:视图
    QGraphicsLineItem\QGraphicsTextItem\QGraphicsPixmapItem:项目,被添加到文档中.
 
    QGraphicsScence本身没有可视的功能,它仅仅是能够管理items
    /*
    QGraphicsItem是场景中图形项的基类。
    图形视图提供了几个典型形状的标准项,
    如长方形QGraphicsRectItem,
    椭圆形QGraphicsEllipseItem和
    文本项QGraphicsTextItem
    但是,当你撰写客户化项时,QGraphicsItem的强大特性就体现出来了
    除此之外,QGraphicsItem还支持下面的特性:
    鼠标按压,移动,释放,双击事件,以及鼠标钩子事件(hover events),滚轮事件(wheel events),上下文事件(context menu events)
 
     键盘输入聚焦,特定键事件
 
     拖放:因为QGraphicsView间接继承了QWidget,它也同样提供QWidget提供的拖放功能。
        为了方便,图形视图架构给场景、每一个项提供了拖放支持。当视图收到一个拖动作,它将拖放事件发给QGraphicsSceneDragDropEvent,
        它再发给场景,场景对事件按时序排列,并发给光标下的第一个项来接受放置。
 
     成组(Grouping),通过父子关系或者用QGraphicsItemGroup
 
     碰撞侦测
*/
 
 
 
    QGraphicsLineItem* lineItem;
    QGraphicsTextItem* textItem;
    QGraphicsPixmapItem* pixmapItem;
 
/*
    QGraphicsScene* _scene;  // data model
    QGraphicsView* _view;   // show the data model
*/
 
    _view = new QGraphicsView();
 
   // _view->setViewport();
   // _view->setBackgroundBrush(Qt::red);
 
    _view->setScene(_scene = new QGraphicsScene);
 
    _scene->addItem(lineItem = new QGraphicsLineItem(QLineF(QPointF(0, 0), QPointF(100, 100))));
    _scene->addItem(textItem = new QGraphicsTextItem("Hello world"));
    _scene->addItem(pixmapItem = new QGraphicsPixmapItem(QPixmap("aaa.png")));
 
    /*妈蛋:加了这一句就能实现拖拽效果了,无语*/
    pixmapItem->setFlags(QGraphicsItem::ItemIsMovable);
    lineItem->setFlags(QGraphicsItem::ItemIsMovable);
 
    QTransform trans;
    trans.rotate(30);
    textItem->setPos(QPointF(200, 300));
    textItem->setTransform(trans);
    textItem->setFont(QFont("aaa", 50, 700, true));
 
    pixmapItem->setPos(100, 100);
 
 
}
 
 
void MyWidget::resizeEvent(QResizeEvent *)
{
    // set the size of _view = MyWidget::size
    _view->setGeometry(QRect(QPoint(0, 0), size()));
}
 
void MyWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->type() == QEvent::MouseButtonPress)
    {
        /*其实,这里这样写:仅是为了测试关系,并且view需要单独show才能显示,并不能updata主窗口引起传布重绘*/
        qDebug()<<"My is Downed";
        _view->setParent(this);
        _view->show();
        //update();
       // repaint();
    }
 
}
 
 
int main(int argc, char* argv[])
{
    QApplication app (argc,argv);
 
    MyWidget w;
    w.showMaximized();
    return app.exec();
}
 

以下文字转载自:http://blog.sina.com.cn/s/blog_4a33cfca01015ppv.html 写的很棒.

好久没有写任何关于编程方面的东西了。这阵子偶尔用Qt的Graphics模块,略有一点经验总结,简单写在这里,权当做自己的备忘录。


Qt Graphics模块用于显示二维的图形图像,所以三维的事情就不要找它了,应该去找Qt的OpenGL模块。主要由三部分组成,分别是View, Scene, Item。

QGraphicsView负责窗口显示,它继承自QWidget,因此是一个标准的Qt窗口类,Qt窗口类一般的操作QGraphicsView都支持。QGraphicsScene是一个视图,它不能够单独存在,必须关联到至少一个QGraphicsView。这两者的关系就和MVO架构中的文档和视图的关系类似,View是视图,负责显示;Scene是文档,负责存储数据。所以从这个角度出发,我们可以这样认为,一个Scene可以关联到多个View,就好比一份数据可以有多个视图去查看它一样。

Item则是具体要显示的东西。最基本的Qt类就是QGraphicsItem,一般如果要显示自定义的形状通常的做法是继承自QGraphicsItem,然后去实现它的两个纯虚函数boundingRect和paint,它们的形式化申明如下:
virtual QRectF boundingRect () const = 0
virtual void paint ( QPainter * painter, const QStyleOptionGraphicsItem  * option, QWidget * widget = 0 ) = 0
boundingRect就是返回该Item的包围盒,用于Graphics内部的碰撞检测以及选取等计算。paint则是用于Item的重绘。

除最基本的QGraphicsItem之外,Qt还定义了若干基本形状的Item,例如QGraphicsEllipseItem、QGraphicsLineItem、QGraphicsRectItem等等,具体可查Qt文档。如果想要绘制的Item形状和这些基本类型接近,不妨直接继承自这些类,然后在paint函数中稍加修改。

Qt之所以提供Graphics模块是为了对二维图形编程方面提供基本的常用的平台功能支持,例如拖动、选择、旋转、动画、缩放、碰撞检测等等。这些功能,简言之,如果我们要用,是不必像在MFC上那样大费周折的,Qt Graphics提供了很好的操作接口。例如,要使得Item能够被选择,只需要设置它的Flag:
setFlag (QGraphicsItem::ItemIsMovable);
即可。移动、是否能获取焦点等都类似。

Qt默认情况下,对于选中的Item,如果你是继承自特殊形状的子类,则会在Item的包围框上显示虚框。若要去掉该虚框,则在paint函数中加入如下代码:
QStyleOptionGraphicsItem  op(*option ); 
op. state = QStyle:: State_None;
然后调用父类的paint函数时,将op作为option传入即可。如果要使得选中的Item呈现不同的状态(颜色、大小等)也是在paint函数中加以修改。

QGraphicsView和QGraphicsScene以及QGraphicsItem都能够接受鼠标、键盘事件,那他们的关系又是如何呢?首先从消息流来看,先是View,然后是Scene,最后是Item。任何阶段若节流事件,则下一层就不会再接受到事件了。对于QGraphicsView和QGraphicsScene,我们应该在哪里处理鼠标或者键盘事件呢?其实两者都是可以的,具体看需求。联系之前所说的文档视图关系可以知道,若应用程序中只有一个View和一个Scene,那么其实在哪里实现都无所谓;当时如果一个Scene对应了多个View,则就有区别了。如果具体到一个视图的操作,应该在View类中实现;如果是Scene需要统一进行处理的,那么就应该在Scene中实现。

Scene更新的时候,尽可能将更新范围限制在最小内,毕竟update全局的话需要消耗较多的资源,尤其是显示内容比较大的时候,会不流畅。

获取鼠标下面的item方法是itemAt。若在View中调用此函数,注意它的参数坐标是View中的坐标,即不需要再做任何的转化。

GraphicsScene中可以内嵌入标准的QWidget,但是其行为和正常的widget略有不同。我发现的一点是:只有真正在Scene中显示的时候,其内部控件才是真正存在的,否则ui内的指针均无效。估计是为了节约资源考虑的吧。这点切记!

QGraphicsItemAnimation可以实现一些简单的动画操作,亲测效果还是不错的,较为平滑。
 
暂记这些,有问题可以讨论。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值