Qt图形视图框架

130 篇文章 4 订阅
24 篇文章 1 订阅

图形视图体系结构

Graphics View框架结构”三元素“:场景类(QGraphicsScene)、视图类(QGraphicsView)和图元类(QGraphicsItem)。场景类提供管理位于其中的图元容器,视图类显示场景中的图元,场景可以通过多个视图表现。

QGraphicsScene

放置图元的容器,本身不可见,通过关联视图类显示和操作。
QGraphicsScene::addItem()添加图元。
QGraphicsScene::items()返回与点、矩形、多边形或向量路径相交的所有图元。
QGraphicsScene::itemAt()返回指定点的顶层图元。
主要工作包括操作图元并传递事件、管理图元状态(选择和焦点处理)、无变换的绘制功能(如打印)。

场景事件发送给图元,同时管理图元间事件传播。场景收到某一点鼠标单击事件,场景会将事件传给这一点的图元。

管理图元事件。
QGraphicsScene::setSelectionArea()选择图元,选择区域任意形状,QPainterPath表示。
QGraphicsScene::selectedItems()获得当前选择图元列表。
QGraphicsScene::setFocusItem()或QGraphicsScene::setFocus()设置图元焦点。
QGraphicsScene::focusItem()获得当前焦点图元。
QGraphicsScene::render()在绘图设备上绘制场景。

场景坐标:
中心为原点,每个图元都有场景坐标和相应的包容框,等价于QPainter的逻辑坐标,一般以场景中心为原点。

场景还有背景层和前景层,QBrush指定,也可通过drawBackground()和drawForeground()自定义。

场景变化时发射QGraphicsScene::changed()信号,参数说场景的矩形列表,表示发生变化的矩形区。

QGraphicsScene主要函数:

//场景
void setSceneRect();

//分组
QGraphicsItemGroup * createItemGroup();
void destroyItemGroup();

//输入焦点
QGraphicsItem *focusItem();
void clearFocus();
bool hasFocus();

//图形项操作
void addItem();
void removeItem();
void clear();
QGraphicsItem* mouseGrabberItem();
QList<QGraphicsItem*> selectedItems();
void clearSelection();
QGraphicsItem* itemAt();
QList<QGraphicsItem*> items();

//添加图形项
QGraphicsEllipseItem* addEllipse();
QGraphicsLineItem* addLine();
QGraphicsPathItem* addPath();
QGraphicsPixmapItem* addPixmap();
QGraphicsPolygonItem* addPolygon();
QGraphicsRectItem* addRect();
QGraphicsSimpleTextItem* addSimpleText();
QGraphicsTextItem* addText();
QGraphicsProxyWidget* addWidget();

QGraphicsView

可视窗口,显示场景中图元。同一场景可以多个视图,相同数据集可以不同视图。
视图大于场景时,默认场景在视图的中间显示,也可通过视图的Alignment属性设置场景在视图中的显示位置;视图小于场景时,提供卷滚条显示。
可滚动窗口部件,QGraphicsView::setViewport()将视图设置为QGLWidget。
接收鼠标键盘输入,并翻译为场景事件(转换为场景坐标),然后传送给场景。
QGraphicsView::matrix()变换场景坐标,实现场景缩放和选择。
QGraphicsView::mapToScene()和QGraphicsView::mapFromScene()与场景坐标转换。

视图坐标:
窗口部件的坐标(设备坐标,物理坐标),单位是像素,左上角是(0,0)。
所有鼠标事件最开始都是使用视图坐标。

QGraphicsView主要函数:

//场景
void setScene();
void setSceneRect();

//外观
void setAlignment();
void setBackgroundBrush();
void setForegroundBrush();
void setRenderHints();

//交互
void setInteractive();
QRect rubberBandRect();
void setRubberBandSelectionMode();
QGraphicsItem * itemAt();
QList<QGraphicsItem*> items();

//坐标映射
QPoint mapFromScene();
QPointF mapToScene();

QGraphicsItem

直线(QGraphicsLineItem)、椭圆(QGraphicsEllipseItem)、文本图元(QGraphicsTextItem)、矩形(QGraphicsRectItem)等。
主要功能:
鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件
键盘输入事件
拖曳事件
分组(组合),可以是父子项关系组合,可可以通过QGraphicsItemGroup类组合
碰撞检测

QGraphicsItem::matrix()函数进行自身的交换,可以包含子图元。

图元坐标:
图元中心为原点(局部逻辑坐标),QGraphicsItem::paint()绘图基准。
QGraphicsItem::boundingRect()局部坐标。
QGraphicsItem:pos()返回图元在父坐标系中的坐标。
QGraphicsItem::scenePos()返回图元在场景中的坐标。
QGraphicsItem::sceneBoundingRect()返回图元在场景中的边界矩形。

QGraphicsItem主要函数:

//属性设置
void setFlags();
//setFlags(QGraphicsItem::ItemIsMovable
//	|GraphicsItem::ItemIsSelectable
//	|GraphicsItem::ItemIsFocusable);
void setOpacity();
void setSelected();
void setData();

//坐标
void setX();
void setY();
void setZValue(); //ZValue越大,越显示在前面
void setPos();
QPointF scenePos();

//坐标变换
void resetTransform();
void setRotation();
void setScale();

//坐标映射
QPointF mapToScene();
QPointF mapFromScene();
QPointF mapToParent();
QPointF mapFromParent();
QPointF mapToItem();
QPointF mapFromItem();

实例1 飞舞的蝴蝶

up.png
在这里插入图片描述
down.png
在这里插入图片描述

Butterfly.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Butterfly
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp \
    butterfly.cpp

HEADERS  += butterfly.h

main.cpp

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>

#include "butterfly.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    Butterfly *butterfly = new Butterfly;
    QGraphicsRectItem *item = new QGraphicsRectItem(-200, -200, 400, 400);

    QGraphicsScene *scene = new QGraphicsScene;
    scene->setSceneRect(QRectF(-200, -200, 400, 400));
    scene->addItem(butterfly);
    scene->addItem(item);

    QGraphicsView *view = new QGraphicsView;
    view->setScene(scene);
    view->resize(500, 500);
    view->show();

    return a.exec();
}

butterfly.h

#ifndef BUTTERFLY_H
#define BUTTERFLY_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QGraphicsScene>
#include <QGraphicsView>

class Butterfly : public QObject, public QGraphicsItem {
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)
public:
    explicit Butterfly(QObject *parent = 0);
    void timerEvent(QTimerEvent *);				//(a)
    QRectF boundingRect() const ;				//限定图元区域范围,继承自QGraphicsItem的类必须实现
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)  ;									//重绘函数
private:
    bool up;									//(c)
    QPixmap pix_up;      						//用于表示两幅蝴蝶的图片
    QPixmap pix_down;
    qreal angle;
};

#endif // BUTTERFLY_H

butterfly.cpp

#include "butterfly.h"
#include <math.h>

const static double PI = 3.1416;

Butterfly::Butterfly(QObject *parent) : QObject(parent) {
    up = true;					//给标志蝴蝶翅膀位置的变量赋初值
    pix_up.load("up.png");		//调用QPixmap的load()函数加载所用到的图片
    pix_down.load("down.png");
    startTimer(100);			//启动定时器,并设置时间间隔为100毫秒
}

//以图元自身坐标系为基础设定
QRectF Butterfly::boundingRect() const {
    qreal adjust = 2;
    return QRectF(-pix_up.width()/2-adjust, -pix_up.height()/2-adjust,
                  pix_up.width()+adjust*2, pix_up.height()+adjust*2);
}

void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) {
    painter->drawPixmap(boundingRect().topLeft(), up?pix_up:pix_down);
    up = !up;
}

void Butterfly::timerEvent(QTimerEvent *) {
    //边界控制
    //限定蝴蝶飞舞的右边界
    qreal edgeright = scene()->sceneRect().right()-boundingRect().width()/2;
    //限定蝴蝶飞舞的上边界
    qreal edgetop = scene()->sceneRect().top()+boundingRect().height()/2;
    //限定蝴蝶飞舞的下边界
    qreal edgebottom = scene()->sceneRect().bottom()-boundingRect().height()/2;

    if(pos().x() >= edgeright)  //若超过了右边界,则水平移回左边界处
        setPos(scene()->sceneRect().left()+boundingRect().width()/2, pos().y());

    if(pos().y() <= edgetop)    //若超过了上边界,则垂直移回下边界处
        setPos(pos().x(), scene()->sceneRect().bottom()-boundingRect().height()/2);
    else if(pos().y() >= edgebottom)    //若超过了下边界,则垂直移回上边界处
        setPos(pos().x(), scene()->sceneRect().top()+boundingRect().height()/2);

    angle += (qrand()%10)/20.0;
    qreal dx = fabs(sin(angle*PI)*10.0);
    qreal dy = (qrand()%20)-10.0;
    setPos(mapToParent(dx, dy));		//(a)
}

实例2 地图浏览器

maps.txt

Map.jpg 97.987060 19.217800 105.095210 15.220590

Map.jpg(http://bzdt.ch.mnr.gov.cn/index.html)
在这里插入图片描述

MapWidget.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = MapWidget
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp \
    mapwidget.cpp

HEADERS  +=  mapwidget.h

main.cpp

#include <QApplication>
#include "mapwidget.h"
#include <QFont>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QFont font("ARPL KaitiM GB", 12);

    font.setBold(true);
    a.setFont(font);

    MapWidget mapWidget;
    mapWidget.show();

    return a.exec();
}

mapwidget.h

#ifndef MAPWIDGET_H
#define MAPWIDGET_H

#include <QGraphicsView>
#include <QLabel>
#include <QMouseEvent>
#include <QSlider>
#include <QGridLayout>

class MapWidget : public QGraphicsView {
    Q_OBJECT
public:
    explicit MapWidget();
    void readMap();              		//读取地图信息
    QPointF mapToMap(QPointF p);  		//用于实现场景坐标系与地图坐标之间的映射,以获得某点的经纬度值
public slots:
    void slotZoom(int);
protected:
    void drawBackground(QPainter *painter, const QRectF &); 			    								//完成地图显示的功能
    void mouseMoveEvent(QMouseEvent *event);
private:
    QLabel *zoominLabel;
    QSlider *slider;
    QLabel *zoomoutLabel;
    QVBoxLayout *zoomLayout;
    QLabel *label1;
    QLabel *viewCoord;
    QLabel *label2;
    QLabel *sceneCoord;
    QLabel *label3;
    QLabel *mapCoord;
    QGridLayout *gridLayout;

    QFrame *coordFrame;

    QVBoxLayout *coordLayout;

    QHBoxLayout *mainLayout;

    QPixmap map;
    qreal zoom;
    double x1, y1;
    double x2, y2;
};

#endif // MAPWIDGET_H

mapwidget.cpp

#include "mapwidget.h"
#include <QFile>
#include <QTextStream>
#include <QGraphicsScene>
#include <math.h>

#include <QDebug>

MapWidget::MapWidget() {
    zoominLabel = new QLabel;
    zoominLabel->setScaledContents(true);
    zoominLabel->setPixmap(QPixmap("zoomin.png"));

    //用于地图缩放的滑动条
    slider = new QSlider;
    slider->setOrientation(Qt::Vertical);
    slider->setRange(1, 100);
    slider->setTickInterval(10);
    slider->setValue(50);
    connect(slider, SIGNAL(valueChanged(int)), this, SLOT(slotZoom(int)));

    zoomoutLabel = new QLabel;
    zoomoutLabel->setScaledContents(true);
    zoomoutLabel->setPixmap(QPixmap("zoomout.png"));

    //缩放控制子布局
    zoomLayout = new QVBoxLayout;
    zoomLayout->addWidget(zoominLabel);
    zoomLayout->addWidget(slider);
    zoomLayout->addWidget(zoomoutLabel);

    //坐标值显示区
    label1 = new QLabel(tr("GraphicsView:"));
    viewCoord = new QLabel;
    label2 = new QLabel(tr("GraphicsScene:"));
    sceneCoord = new QLabel;
    label3 = new QLabel(tr("map:"));
    mapCoord = new QLabel;

    gridLayout = new QGridLayout;
    gridLayout->addWidget(label1, 0, 0);
    gridLayout->addWidget(viewCoord, 0, 1);
    gridLayout->addWidget(label2, 1, 0);
    gridLayout->addWidget(sceneCoord, 1, 1);
    gridLayout->addWidget(label3, 2, 0);
    gridLayout->addWidget(mapCoord, 2, 1);
    gridLayout->setSizeConstraint(QLayout::SetFixedSize);

    coordFrame = new QFrame;
    coordFrame->setLayout(gridLayout);

    coordLayout = new QVBoxLayout;
    coordLayout->addWidget(coordFrame);
    coordLayout->addStretch();

    //主布局
    mainLayout = new QHBoxLayout(this);
    mainLayout->addLayout(zoomLayout);
    mainLayout->addLayout(coordLayout);
    mainLayout->addStretch();
    mainLayout->setMargin(30);
    mainLayout->setSpacing(10);

    zoom = 50;
    readMap(); //读取地图信息
    int width = map.width();
    int height = map.height();

    QGraphicsScene *scene = new QGraphicsScene(this);
    //限定场景的显示区域为地图的大小
    scene->setSceneRect(-width/2, -height/2, width, height);
    setScene(scene);
    setCacheMode(CacheBackground);

    setWindowTitle("Map Widget");
    setMinimumSize(600, 400);
}

//读取地图信息
void MapWidget::readMap() {
    QString mapName;
    QFile mapFile("maps.txt");
    int ok = mapFile.open(QIODevice::ReadOnly);
    if(ok){
        QTextStream ts(&mapFile); //分别读取地图的名称和四个经纬度信息
        if(!ts.atEnd()) {
            ts>>mapName;
            ts>>x1>>y1>>x2>>y2;
        }
    }
    map.load(mapName);    //将地图读取至私有变量map中
}

//地图缩放
void MapWidget::slotZoom(int value) {
    qreal s;
    if(value>zoom) {    //放大
        s = pow(1.01, (value-zoom));
    } else {     //缩小
        s = pow(1/1.01, (zoom-value));
    }
    scale(s, s);
    zoom = value;
}

void MapWidget::drawBackground(QPainter *painter, const QRectF &) {
    painter->drawPixmap(int(sceneRect().left()), int(sceneRect().top()), map);
}

void MapWidget::mouseMoveEvent(QMouseEvent *event) {
    //QGraphicsView 坐标
    QPoint viewPoint = event->pos();
    viewCoord->setText(QString::number(viewPoint.x())+", "+QString::number(viewPoint.y()));

    //QGraphicsScene 坐标
    QPointF scenePoint = mapToScene(viewPoint);
    sceneCoord->setText(QString::number(scenePoint.x())+", "+QString::number(scenePoint.y()));

    //地图坐标(经、纬度值)
    QPointF latLon = mapToMap(scenePoint);
    mapCoord->setText(QString::number(latLon.x())+", "+QString::number(latLon.y()));
}

QPointF MapWidget::mapToMap(QPointF p) {
    qreal w = sceneRect().width();
    qreal h = sceneRect().height();
    qreal lon = y1-((h/2+p.y())*abs(y1-y2)/h);
    qreal lat = x1+((w/2+p.x())*abs(x1-x2)/w);
    return QPointF(lat, lon);
}

实例3 图元的创建

star.png
在这里插入图片描述

image.png
在这里插入图片描述

GraphicsItem.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = GraphicsItem
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp \
    mainwindow.cpp \
    flashitem.cpp \
    startitem.cpp

HEADERS  += mainwindow.h \
    flashitem.h \
    startitem.h

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

flashitem.h

#ifndef FLASHITEM_H
#define FLASHITEM_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>

class FlashItem : public QObject, public QGraphicsItem {
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)
public:
    explicit FlashItem(QObject *parent = 0);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
    void timerEvent(QTimerEvent *);
private:
    bool flash;
};

#endif // FLASHITEM_H

flashitem.cpp

#include "flashitem.h"

FlashItem::FlashItem(QObject *parent) : QObject(parent) {
    flash = true;       //为颜色切换标识赋初值
    setFlag(ItemIsMovable);
    startTimer(1000);			//启动一个定时器,以1000毫秒为时间间隔
}

QRectF FlashItem::boundingRect() const {
    qreal adjust = 2;
    return QRectF(-10-adjust, -10-adjust, 43+adjust, 43+adjust);
}

void FlashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) {
    painter->setPen(Qt::NoPen);         //闪烁图元的阴影区不绘制边线
    painter->setBrush(Qt::darkGray);    //闪烁图元的阴影区的阴影画刷颜色为深灰
    painter->drawEllipse(-7, -7, 40, 40);	//绘制阴影区
    painter->setPen(QPen(Qt::black, 0));
    //闪烁区的椭圆边线颜色为黑色、线宽为0
    painter->setBrush(flash?(Qt::red):(Qt::yellow));	//(a)
    painter->drawEllipse(-10, -10, 40, 40);				//(b)
}

void FlashItem::timerEvent(QTimerEvent *) {
    flash = !flash;
    update();
}

startitem.h

#ifndef STARTITEM_H
#define STARTITEM_H

#include <QGraphicsItem>
#include <QPainter>

class StartItem : public QGraphicsItem {
    Q_INTERFACES(QGraphicsItem)
public:
    StartItem();
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
private:
    QPixmap pix;
};

#endif // STARTITEM_H

startitem.cpp

#include "startitem.h"

StartItem::StartItem() {
    pix.load("star.png");
}

QRectF StartItem::boundingRect() const {
    return QRectF(-pix.width()/2, -pix.height()/2, pix.width(), pix.height());
}

void StartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) {
    painter->drawPixmap(boundingRect().topLeft(),pix);
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QMenuBar>
#include <QGraphicsEllipseItem>

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    void createActions();       			//创建主窗体的所有动作
    void createMenus();         			//创建主窗体的菜单栏
    void initScene();            			//初始化场景
public slots:
    void slotNew();              			//新建一个显示窗体
    void slotClear();           			//清除场景中所有的图元
    void slotAddEllipseItem();              //在场景中加入一个椭圆形图元
    void slotAddPolygonItem();      		//在场景中加入一个多边形图元
    void slotAddTextItem();         		//在场景中加入一个文字图元
    void slotAddRectItem();         		//在场景中加入一个长方形图元
    void slotAddAlphaItem();        		//在场景中加入一个透明蝴蝶图片
    void slotAddFlashItem();
    void slotAddAnimationItem();
private:
    QAction *newAct;
    QAction *clearAct;
    QAction *exitAct;
    QAction *addEllipseItemAct;
    QAction *addPolygonItemAct;
    QAction *addTextItemAct;
    QAction *addRectItemAct;
    QAction *addAlphaItemAct;
    QAction *addFlashItemAct;
    QAction *addAnimItemAct;
    QMenu *fileMenu;
    QMenu *itemsMenu;
    QGraphicsScene *scene;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "flashitem.h"
#include "startitem.h"
#include <QGraphicsItemAnimation>
#include <QTimeLine>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
    createActions();                    	//创建主窗体的所有动作
    createMenus();                       	//创建主窗体的菜单栏

    scene = new QGraphicsScene;
    scene->setSceneRect(-200, -200, 400, 400);
    initScene();                         	//初始化场景

    QGraphicsView *view = new QGraphicsView;
    view->setScene(scene);
    view->setMinimumSize(400, 400);
    view->show();

    setCentralWidget(view);
    resize(800, 600);
    setWindowTitle(tr("Graphics Items"));
}

void MainWindow::createActions() {
    newAct = new QAction(tr("新建"), this);
    clearAct = new QAction(tr("清除"), this);
    exitAct = new QAction(tr("退出"), this);
    addEllipseItemAct = new QAction(tr("加入椭圆"), this);
    addPolygonItemAct = new QAction(tr("加入多边形"), this);
    addTextItemAct = new QAction(tr("加入文字"), this);
    addRectItemAct = new QAction(tr("加入长方形"), this);
    addAlphaItemAct = new QAction(tr("加入透明图片"), this);
    addFlashItemAct = new QAction(tr("加入闪烁圆"), this);
    addAnimItemAct = new QAction(tr("加入星星"), this);

    connect(newAct, SIGNAL(triggered()), this,SLOT(slotNew()));
    connect(clearAct, SIGNAL(triggered()), this,SLOT(slotClear()));
    connect(exitAct, SIGNAL(triggered()), this,SLOT(close()));
    connect(addEllipseItemAct, SIGNAL(triggered()), this,SLOT (slotAddEllipseItem()));
    connect(addPolygonItemAct, SIGNAL(triggered()), this,SLOT (slotAddPolygonItem()));
    connect(addTextItemAct, SIGNAL(triggered()), this,SLOT (slotAddTextItem()));
    connect(addRectItemAct, SIGNAL(triggered()), this,SLOT (slotAddRectItem()));
    connect(addAlphaItemAct, SIGNAL(triggered()), this,SLOT (slotAddAlphaItem()));
    connect(addFlashItemAct, SIGNAL(triggered()), this,SLOT(slotAddFlashItem()));
    connect(addAnimItemAct, SIGNAL(triggered()), this,SLOT(slotAddAnimationItem()));
}

void MainWindow::createMenus() {
    fileMenu = menuBar()->addMenu(tr("文件"));
    fileMenu->addAction(newAct);
    fileMenu->addAction(clearAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);
    itemsMenu = menuBar()->addMenu(tr("元素"));
    itemsMenu->addAction(addEllipseItemAct);
    itemsMenu->addAction(addPolygonItemAct);
    itemsMenu->addAction(addTextItemAct);
    itemsMenu->addAction(addRectItemAct);
    itemsMenu->addAction(addAlphaItemAct);
    itemsMenu->addAction(addFlashItemAct);
    itemsMenu->addAction(addAnimItemAct);
}

void MainWindow::initScene() {
    int i;
    for(i=0; i<3; i++)
        slotAddEllipseItem();
    for(i=0; i<3; i++)
        slotAddPolygonItem();
    for(i=0; i<3; i++)
        slotAddTextItem();
    for(i=0; i<3; i++)
        slotAddRectItem();
    for(i=0; i<3; i++)
        slotAddAlphaItem();
    for(i=0; i<3; i++)
        slotAddFlashItem();
    for(i=0; i<3; i++)
        slotAddAnimationItem();
}

//新建一个显示窗体
void MainWindow::slotNew() {
    MainWindow *newWin = new MainWindow;
    newWin->show();
}

//清除场景中所有的图元
void MainWindow::slotClear() {
    QList<QGraphicsItem*> listItem = scene->items();
    while(!listItem.empty()) {
        scene->removeItem(listItem.at(0));
        listItem.removeAt(0);
    }
}

//在场景中加入一个椭圆形图元
void MainWindow::slotAddEllipseItem() {
    QGraphicsEllipseItem *item = new QGraphicsEllipseItem(QRectF(0, 0, 80, 60));
    item->setPen(Qt::NoPen);
    item->setBrush(QColor(qrand()%256,qrand()%256,qrand()%256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    item->setPos((qrand()%int(scene->sceneRect().width()))-200, (qrand()%int(scene->sceneRect().height()))-200);
}

//在场景中加入一个多边形图元
void MainWindow::slotAddPolygonItem() {
    QVector<QPoint> v;
    v<<QPoint(30,-15)<<QPoint(0,-30)<<QPoint(-30,-15)
    <<QPoint(-30,15)<<QPoint(0,30)<<QPoint(30,15);

    QGraphicsPolygonItem *item = new QGraphicsPolygonItem(QPolygonF(v));
    item->setBrush(QColor(qrand()%256, qrand()%256, qrand()%256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    item->setPos((qrand()%int(scene->sceneRect().width()))-200, (qrand()%int(scene->sceneRect().height()))-200);
}

//在场景中加入一个文字图元
void MainWindow::slotAddTextItem() {
    QFont font("Times", 16);
    QGraphicsTextItem *item = new QGraphicsTextItem("Hello Qt");
    item->setFont(font);
    item->setFlag(QGraphicsItem::ItemIsMovable);
    item->setDefaultTextColor(QColor(qrand()%256, qrand()%256, qrand()%256));
    scene->addItem(item);
    item->setPos((qrand()%int(scene->sceneRect().width()))-200, (qrand()%int(scene->sceneRect().height()))-200);
}

//在场景中加入一个长方形图元
void MainWindow::slotAddRectItem() {
    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 60, 60));
    QPen pen;
    pen.setWidth(3);
    pen.setColor(QColor(qrand()%256, qrand()%256, qrand()%256));
    item->setPen(pen);
    item->setBrush(QColor(qrand()%256, qrand()%256, qrand()%256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    item->setPos((qrand()%int(scene->sceneRect().width()))-200, (qrand()%int(scene->sceneRect().height()))-200);
}

//在场景中加入一个透明蝴蝶图片
void MainWindow::slotAddAlphaItem() {
    QGraphicsPixmapItem *item = scene->addPixmap(QPixmap("image.png"));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    item->setPos((qrand()%int(scene->sceneRect().width()))-200, (qrand()%int(scene->sceneRect().height()))-200);
}

//在场景中加入一个闪烁图元
void MainWindow::slotAddFlashItem() {
    FlashItem *item = new FlashItem;
    scene->addItem(item);
    item->setPos((qrand()%int(scene->sceneRect().width()))-200, (qrand()%int(scene->sceneRect().height()))-200);
}

//在场景中加入一个动画星星
void MainWindow::slotAddAnimationItem() {
    StartItem *item = new StartItem;

    QTimeLine *timeLine = new QTimeLine(4000);
    timeLine->setCurveShape(QTimeLine::SineCurve);
    timeLine->setLoopCount(0);

    QGraphicsItemAnimation *anim = new QGraphicsItemAnimation;
    anim->setItem(item);
    anim->setTimeLine(timeLine);
    int y = (qrand()%400)-200;
    for(int i=0; i<400; i++) {
        anim->setPosAt(i/400.0, QPointF(i-200, y));
    }

    timeLine->start();

    scene->addItem(item);
}

实例4 视图的变换

image.png
在这里插入图片描述

itemWidget.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = ItemWidget
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp \
    mainwidget.cpp \
    pixitem.cpp

HEADERS  += mainwidget.h \
    pixitem.h

main.cpp

#include "mainwidget.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    MainWidget w;
    w.show();

    return a.exec();
}

pixitem.h

#ifndef PIXITEM_H
#define PIXITEM_H

#include <QGraphicsItem>
#include <QPixmap>
#include <QPainter>

class PixItem : public QGraphicsItem {
    Q_INTERFACES(QGraphicsItem)
public:
    PixItem(QPixmap *pixmap);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
private:
    QPixmap pix;     		//作为图元显示的图片
};

#endif // PIXITEM_H

pixitem.cpp

#include "pixitem.h"

PixItem::PixItem(QPixmap *pixmap) {
    pix = *pixmap;
}

QRectF PixItem::boundingRect() const {
    return QRectF(-pix.width()/2-2, -pix.height()/2-2, pix.width()+4, pix.height()+4);
}

void PixItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) {
    painter->drawPixmap(-pix.width()/2, -pix.height()/2, pix);
}

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFrame>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSlider>
#include <QGroupBox>
#include "pixitem.h"

class MainWidget : public QWidget {
    Q_OBJECT
public:
    explicit MainWidget(QWidget *parent = 0);
public slots:
    void slotRotate(int);
    void slotScale(int);
    void slotShear(int);
    void slotTranslate(int);
private:
    PixItem *pixItem;
    QFrame *ctrlFrame;
    QGraphicsView *view;

    QSlider *rotateSlider;
    QHBoxLayout *rotateLayout;
    QGroupBox *rotateGroup;

    QSlider *scaleSlider;
    QHBoxLayout *scaleLayout;
    QGroupBox *scaleGroup;

    QSlider *shearSlider;
    QHBoxLayout *shearLayout;
    QGroupBox *shearGroup;

    QSlider *translateSlider;
    QHBoxLayout *translateLayout;
    QGroupBox *translateGroup;
    QVBoxLayout *frameLayout;

    QHBoxLayout *mainLayout;

    int angleValue;
    qreal scaleValue;
    qreal shearValue;
    qreal translateValue;
};

#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include <math.h>
#include <QLabel>

#include <QDebug>

MainWidget::MainWidget(QWidget *parent) : QWidget(parent) {
    angleValue = 0;
    scaleValue = 5;
    shearValue = 5;
    translateValue = 50;

    QPixmap *pixmap = new  QPixmap("image.png");
    pixItem = new PixItem(pixmap);
    pixItem->setPos(0, 0);

    int width = pixmap->width();
    int height = pixmap->height();
    QGraphicsRectItem *item = new QGraphicsRectItem(-width/2, -height/2, width, height);

    QGraphicsScene *scene = new QGraphicsScene;
    scene->setSceneRect(-200, -200, 400, 400);
    scene->addItem(pixItem);
    scene->addItem(item);

    view = new QGraphicsView;			//新建一个视图对象
    view->setScene(scene);				//将视图对象与场景相连
    view->setMinimumSize(400, 400);		//设置视图的最小尺寸为(400,400)

    //旋转控制
    rotateGroup = new QGroupBox(tr("Rotate"));

    rotateSlider = new QSlider;
    rotateSlider->setOrientation(Qt::Horizontal);
    rotateSlider->setRange(0, 360);

    rotateLayout = new QHBoxLayout(rotateGroup);
    rotateLayout->addWidget(rotateSlider);

    //缩放控制
    scaleGroup = new QGroupBox(tr("Scale"));

    scaleSlider = new QSlider;
    scaleSlider->setOrientation(Qt::Horizontal);
    scaleSlider->setRange(0, 2*scaleValue);
    scaleSlider->setValue(scaleValue);

    scaleLayout = new QHBoxLayout(scaleGroup);
    scaleLayout->addWidget(scaleSlider);

    //切变控制
    shearGroup = new QGroupBox(tr("Shear"));

    shearSlider = new QSlider;
    shearSlider->setOrientation(Qt::Horizontal);
    shearSlider->setRange(0, 2*shearValue);
    shearSlider->setValue(shearValue);

    shearLayout = new QHBoxLayout(shearGroup);
    shearLayout->addWidget(shearSlider);

    //位移控制
    translateGroup = new QGroupBox(tr("Translate"));

    translateSlider = new QSlider;
    translateSlider->setOrientation(Qt::Horizontal);
    translateSlider->setRange(0, 2*translateValue);
    translateSlider->setValue(translateValue);

    translateLayout = new QHBoxLayout(translateGroup);
    translateLayout->addWidget(translateSlider);

    connect(rotateSlider, SIGNAL(valueChanged(int)), this, SLOT(slotRotate(int)));
    connect(scaleSlider, SIGNAL(valueChanged(int)), this, SLOT(slotScale(int)));
    connect(shearSlider, SIGNAL(valueChanged(int)), this, SLOT(slotShear(int)));
    connect(translateSlider, SIGNAL(valueChanged(int)), this, SLOT(slotTranslate(int)));

    //控制面板布局
    ctrlFrame = new QFrame;
    frameLayout = new QVBoxLayout(ctrlFrame);
    frameLayout->setMargin(10);
    frameLayout->setSpacing(20);
    frameLayout->addWidget(rotateGroup);
    frameLayout->addWidget(scaleGroup);
    frameLayout->addWidget(shearGroup);
    frameLayout->addWidget(translateGroup);

    //主窗口布局
    mainLayout = new QHBoxLayout(this);
    mainLayout->setMargin(10);
    mainLayout->setSpacing(20);
    mainLayout->addWidget(view, 1);
    mainLayout->addWidget(ctrlFrame);

    setWindowTitle(tr("Graphics Item Transformation"));

    //view中央添加固定的label
    QHBoxLayout *viewLayout = new QHBoxLayout(view);
    viewLayout->addStretch();
    viewLayout->addWidget(new QLabel(tr("center")));
    viewLayout->addStretch();
}

void MainWidget::slotRotate(int value) {
    view->rotate(value-angleValue);
    //view->rotate(value);
    angleValue = value;
}

void MainWidget::slotScale(int value) {
    qreal s;
    if(value>scaleValue)
        s=pow(1.1, (value-scaleValue));
    else
        s=pow(1/1.1, (scaleValue-value));
    view->scale(s, s);
    scaleValue = value;
}

void MainWidget::slotShear(int value) {
    view->shear((value-shearValue)/10.0, 0.0);
    shearValue = value;
}

void MainWidget::slotTranslate(int value) {
    //view平移没反应
    //view->translate((value-translateValue), 0);

    //设置图元在场景中坐标,等效于平移
    pixItem->setPos((value-translateValue), 0);

    //QPointF delta(value, value);
    //delta *= view->transform().m11();  //m11为缩放比
    //修改锚点,调用缩放方法
    //view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    //view->centerOn(view->mapToScene(QPoint(view->viewport()->rect().width()/2-delta.x(), view->viewport()->rect().height()/2-delta.y())));
    //view->setTransformationAnchor(QGraphicsView::NoAnchor);

    //translateValue = value;
}

实例5 基本结构和功能

GraphicsCooridate.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = GraphicsCooridate
TEMPLATE = app

SOURCES += main.cpp \
    mainwindow.cpp \
    qwgraphicsview.cpp

HEADERS  += mainwindow.h \
    qwgraphicsview.h

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QLabel>
#include <QGroupBox>
#include <QVBoxLayout>
#include "qwgraphicsview.h"

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    void iniGraphicsSystem(); //创建Graphics View的各项
protected:
    void resizeEvent(QResizeEvent *event);
private slots:
    void on_mouseMovePoint(QPoint point);
    void on_mouseClicked(QPoint point);
private:
    QGraphicsScene  *scene;

    QLabel  *labViewCord;
    QLabel  *labSceneCord;
    QLabel  *labItemCord;

    QWGraphicsView *View;
    QLabel *LabSceneRect;
    QLabel *labViewSize;
    QGroupBox *groupBox;
    QVBoxLayout *groupBoxLayout;
    QWidget *widget;
    QVBoxLayout *mainLayout;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include <QGraphicsEllipseItem>
#include <QStatusBar>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
    LabSceneRect = new QLabel;
    labViewSize = new QLabel;
    groupBox = new QGroupBox;
    groupBoxLayout = new QVBoxLayout(groupBox);
    groupBoxLayout->addWidget(LabSceneRect);
    groupBoxLayout->addWidget(labViewSize);
    View = new QWGraphicsView;
    widget = new QWidget;
    mainLayout = new QVBoxLayout(widget);
    mainLayout->addWidget(groupBox);
    mainLayout->addWidget(View);
    setCentralWidget(widget);

    labViewCord = new QLabel("View 坐标:");
    labViewCord->setMinimumWidth(150);
    statusBar()->addWidget(labViewCord);

    labSceneCord = new QLabel("Scene 坐标:");
    labSceneCord->setMinimumWidth(150);
    statusBar()->addWidget(labSceneCord);

    labItemCord = new QLabel("Item 坐标:");
    labItemCord->setMinimumWidth(150);
    statusBar()->addWidget(labItemCord);

    View->setCursor(Qt::CrossCursor);
    View->setMouseTracking(true);
    View->setDragMode(QGraphicsView::RubberBandDrag);

    connect(View, SIGNAL(mouseMovePoint(QPoint)), this, SLOT(on_mouseMovePoint(QPoint)));
    connect(View, SIGNAL(mouseClicked(QPoint)), this, SLOT(on_mouseClicked(QPoint)));

    iniGraphicsSystem();
}

void MainWindow::iniGraphicsSystem() { //构造Graphics View的各项
    QRectF rect(-200, -100, 400, 200);
    scene = new QGraphicsScene(rect); //scene逻辑坐标系定义
    View->setScene(scene);
    View->setDragMode(QGraphicsView::RubberBandDrag);

    //画一个矩形框,大小等于scene
    QGraphicsRectItem *item = new QGraphicsRectItem(rect); //矩形框正好等于scene的大小
    item->setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);  //可选,可以有焦点,但是不能移动
    QPen pen;
    pen.setWidth(2);
    item->setPen(pen);
    scene->addItem(item);

    //一个位于scene中心的椭圆,测试局部坐标
    QGraphicsEllipseItem *item2 = new QGraphicsEllipseItem(-100,-50,200,100); //矩形框内创建椭圆,绘图项的局部坐标,左上角(-100,-50),宽200,高100
    //item2->setPos(0, 0);//缺省位置在scene的(0,0)
    item2->setBrush(QBrush(Qt::blue));
    item2->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item2->setSelected(true);
    scene->addItem(item2);

    //一个圆,中心位于scene的边缘
    QGraphicsEllipseItem *item3 = new QGraphicsEllipseItem(-50,-50,100,100); //矩形框内创建椭圆,绘图项的局部坐标,左上角(-100,-50),宽200,高100
    item3->setPos(rect.right(), rect.bottom());
    item3->setBrush(QBrush(Qt::red));
    item3->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    scene->addItem(item3);

    scene->clearSelection();
}

void MainWindow::resizeEvent(QResizeEvent *event) { //窗口变化大小时的事件
    Q_UNUSED(event);
    //Graphics View坐标,左上角总是(0,0),宽度=,长度=
    labViewSize->setText(QString::asprintf("Graphics View坐标,左上角总是(0,0),宽度=%d,高度=%d", View->width(),View->height()));

    QRectF rectF = View->sceneRect(); //Scene的矩形区
    LabSceneRect->setText(QString::asprintf("QGraphicsView::sceneRect=(Left, Top, Width, Height) = %.0f, %.0f, %.0f, %.0f",
                                            rectF.left(), rectF.top(), rectF.width(), rectF.height()));
}

void MainWindow::on_mouseMovePoint(QPoint point) {//鼠标移动事件,point是GraphicsView的坐标,物理坐标
    labViewCord->setText(QString::asprintf("View 坐标:%d, %d", point.x(), point.y()));
    QPointF pointScene = View->mapToScene(point); //转换到Scene坐标
    labSceneCord->setText(QString::asprintf("Scene 坐标:%.0f, %.0f", pointScene.x(), pointScene.y()));
}

void MainWindow::on_mouseClicked(QPoint point) {//鼠标单击事件
    QPointF pointScene = View->mapToScene(point); //转换到Scene坐标
    QGraphicsItem  *item = scene->itemAt(pointScene,View->transform()); //获取光标下的绘图项
    if(item != NULL) {//有绘图项
        QPointF pointItem = item->mapFromScene(pointScene); //转换为绘图项的局部坐标
        labItemCord->setText(QString::asprintf("Item 坐标:%.0f, %.0f", pointItem.x(), pointItem.y()));
    }
}

qwgraphicsview.h

#ifndef QWGRAPHICSVIEW_H
#define QWGRAPHICSVIEW_H

#include <QObject>
#include <QGraphicsView>

class QWGraphicsView : public QGraphicsView {
    Q_OBJECT
public:
    explicit QWGraphicsView(QWidget *parent = 0);
protected:
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
signals:
    void mouseMovePoint(QPoint point);
    void mouseClicked(QPoint point);
};

#endif // QWGRAPHICSVIEW_H

qwgraphicsview.cpp

#include "qwgraphicsview.h"
#include <QMouseEvent>
#include <QPoint>

QWGraphicsView::QWGraphicsView(QWidget *parent):QGraphicsView(parent) {

}

void QWGraphicsView::mouseMoveEvent(QMouseEvent *event) {//鼠标移动事件
    QPoint point = event->pos(); //QGraphicsView的坐标
    emit mouseMovePoint(point); //释放信号
    QGraphicsView::mouseMoveEvent(event);
}

void QWGraphicsView::mousePressEvent(QMouseEvent *event) { //鼠标左键按下事件
    if(event->button()==Qt::LeftButton) {
        QPoint point = event->pos(); //QGraphicsView的坐标
        emit mouseClicked(point);//释放信号
    }
    QGraphicsView::mousePressEvent(event);
}

实例6 绘图程序

image/zoomin.png
在这里插入图片描述

image/zoomout.png
在这里插入图片描述

image/restore.bmp
在这里插入图片描述

image/rotateleft.png
在这里插入图片描述

image/rotateright.png
在这里插入图片描述

image/front.bmp
在这里插入图片描述

image/back.bmp
在这里插入图片描述

image/break.bmp
在这里插入图片描述

image/delete.bmp
在这里插入图片描述

image/quit.bmp
在这里插入图片描述

image/rect.bmp
在这里插入图片描述

image/ellipse.bmp
在这里插入图片描述

image/triangle.ico
在这里插入图片描述

image/polygon.bmp
在这里插入图片描述

image/line.bmp
在这里插入图片描述

image/text.bmp
在这里插入图片描述

GraphicsDraw.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = GraphicsDraw
TEMPLATE = app

SOURCES += main.cpp \
    mainwindow.cpp \
    qwgraphicsview.cpp

HEADERS  += mainwindow.h \
    qwgraphicsview.h

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QAction>
#include <QToolBar>

#include <QGraphicsScene>
#include <QLabel>

#include "qwgraphicsview.h"

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
private slots:
    void on_mouseMovePoint(QPoint point); //鼠标移动
    void on_mouseClicked(QPoint point); //鼠标单击
    void on_mouseDoubleClick(QPoint point); //鼠标双击
    void on_keyPress(QKeyEvent *event); //按键

    void on_actZoomIn_triggered();
    void on_actZoomOut_triggered();
    void on_actRestore_triggered();
    void on_actRotateLeft_triggered();
    void on_actRotateRight_triggered();
    void on_actEdit_Front_triggered();
    void on_actEdit_Back_triggered();
    void on_actGroup_triggered();
    void on_actGroupBreak_triggered();
    void on_actEdit_Delete_triggered();

    void on_actItem_Rect_triggered();
    void on_actItem_Ellipse_triggered();
    void on_actItem_Circle_triggered();
    void on_actItem_Triangle_triggered();
    void on_actItem_Polygon_triggered();
    void on_actItem_Line_triggered();
    void on_actItem_Text_triggered();
private:
    void initAction();
    void initToolBar();
    void initStatusBar();
    void initUI();
    void initSignalSlot();
private:
    QAction *actZoomIn;
    QAction *actZoomOut;
    QAction *actRestore;

    QAction *actRotateLeft;
    QAction *actRotateRight;
    QAction *actEdit_Front;
    QAction *actEdit_Back;
    QAction *actGroup;
    QAction *actGroupBreak;
    QAction *actEdit_Delete;

    QAction *actQuit;
    QToolBar *mainToolBar;

    QAction *actItem_Rect;
    QAction *actItem_Ellipse;
    QAction *actItem_Circle;
    QAction *actItem_Triangle;
    QAction *actItem_Polygon;
    QAction *actItem_Line;
    QAction *actItem_Text;
    QToolBar *toolBar;

    QLabel  *labViewCord;
    QLabel  *labSceneCord;
    QLabel  *labItemCord;
    QLabel  *labItemInfo;

    QGraphicsScene  *scene;
    QWGraphicsView *View;

    static const int ItemId = 1;   //绘图项自定义数据的key
    static const int ItemDesciption = 2;   //绘图项自定义数据的key

    int seqNum=0;
    int backZ=0;
    int frontZ=0;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

#include <QGraphicsRectItem>
#include <QInputDialog>
#include <QColorDialog>
#include <QFontDialog>
#include <QTime>
#include <QKeyEvent>
#include <QIcon>
#include <QStatusBar>

template<class T> void setBrushColor(T *item) {//函数模板
    QColor color = QColorDialog::getColor(item->brush().color(), NULL, QObject::tr("选择填充颜色"));
    if(color.isValid())
        item->setBrush(QBrush(color));
}

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
    initAction();
    initToolBar();
    initStatusBar();
    initUI();
    initSignalSlot();
}

void MainWindow::initAction() {
    actZoomIn = new QAction(QIcon("image/zoomin.png"), tr("放大"), this);
    actZoomOut = new QAction(QIcon("image/zoomout.png"), tr("缩小"));
    actRestore = new QAction(QIcon("image/restore.bmp"), tr("恢复"));
    actRotateLeft = new QAction(QIcon("image/rotateleft.png"), tr("左旋转"));
    actRotateRight = new QAction(QIcon("image/rotateright.png"), tr("右旋转"));
    actEdit_Front = new QAction(QIcon("image/front.bmp"), tr("前置"));
    actEdit_Back = new QAction(QIcon("image/back.bmp"), tr("后置"));
    actGroup = new QAction(QIcon("image/group.bmp"), tr("组合"));
    actGroupBreak = new QAction(QIcon("image/break.bmp"), tr("打散"));
    actEdit_Delete = new QAction(QIcon("image/delete.bmp"), tr("删除"));
    actQuit = new QAction(QIcon("image/quit.bmp"), tr("退出"));

    actItem_Rect = new QAction(QIcon("image/rect.bmp"), tr("矩形"));
    actItem_Ellipse = new QAction(QIcon("image/ellipse.bmp"), tr("椭圆"));
    actItem_Circle = new QAction(QIcon("image/circle.jpg"), tr("圆形"));
    actItem_Triangle = new QAction(QIcon("image/triangle.ico"), tr("三角形"));
    actItem_Polygon = new QAction(QIcon("image/polygon.bmp"), tr("梯形"));
    actItem_Line = new QAction(QIcon("image/line.bmp"), tr("直线"));
    actItem_Text = new QAction(QIcon("image/text.bmp"), tr("文字"));
}

void MainWindow::initToolBar() {
    mainToolBar = new QToolBar;
    mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    mainToolBar->addAction(actZoomIn);
    mainToolBar->addAction(actZoomOut);
    mainToolBar->addAction(actRestore);
    mainToolBar->addSeparator();
    mainToolBar->addAction(actRotateLeft);
    mainToolBar->addAction(actRotateRight);
    mainToolBar->addAction(actEdit_Front);
    mainToolBar->addAction(actEdit_Back);
    mainToolBar->addAction(actGroup);
    mainToolBar->addAction(actGroupBreak);
    mainToolBar->addAction(actEdit_Delete);
    mainToolBar->addSeparator();
    mainToolBar->addAction(actQuit);
    addToolBar(mainToolBar);

    toolBar = new QToolBar;
    toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    toolBar->addAction(actItem_Rect);
    toolBar->addAction(actItem_Ellipse);
    toolBar->addAction(actItem_Circle);
    toolBar->addAction(actItem_Triangle);
    toolBar->addAction(actItem_Polygon);
    toolBar->addAction(actItem_Line);
    toolBar->addAction(actItem_Text);
    addToolBar(Qt::LeftToolBarArea, toolBar);
}

void MainWindow::initStatusBar() {
    labViewCord = new QLabel(tr("View 坐标:")); //创建状态栏标签
    labViewCord->setMinimumWidth(150);
    statusBar()->addWidget(labViewCord);

    labSceneCord = new QLabel(tr("Scene 坐标:"));
    labSceneCord->setMinimumWidth(150);
    statusBar()->addWidget(labSceneCord);

    labItemCord = new QLabel(tr("Item 坐标:"));
    labItemCord->setMinimumWidth(150);
    statusBar()->addWidget(labItemCord);

    labItemInfo = new QLabel(tr("ItemInfo: "));
    labItemInfo->setMinimumWidth(200);
    statusBar()->addWidget(labItemInfo);
}

void MainWindow::initUI() {
    scene = new QGraphicsScene(-300, -200, 600, 200); //创建QGraphicsScene

    View = new QWGraphicsView;
    View->setScene(scene); //与view关联
    View->setCursor(Qt::CrossCursor); //设置鼠标
    View->setMouseTracking(true); //
    View->setDragMode(QGraphicsView::RubberBandDrag);
    setCentralWidget(View);

    qsrand(QTime::currentTime().second());
}

void MainWindow::initSignalSlot() {
    connect(actZoomIn, SIGNAL(triggered()), this, SLOT(on_actZoomIn_triggered()));
    connect(actZoomOut, SIGNAL(triggered()), this, SLOT(on_actZoomOut_triggered()));
    connect(actRestore, SIGNAL(triggered()), this, SLOT(on_actRestore_triggered()));
    connect(actRotateLeft, SIGNAL(triggered()), this, SLOT(on_actRotateLeft_triggered()));
    connect(actRotateRight, SIGNAL(triggered()), this, SLOT(on_actRotateRight_triggered()));
    connect(actEdit_Front, SIGNAL(triggered()), this, SLOT(on_actEdit_Front_triggered()));
    connect(actEdit_Back, SIGNAL(triggered()), this, SLOT(on_actEdit_Back_triggered()));
    connect(actGroup, SIGNAL(triggered()), this, SLOT(on_actGroup_triggered()));
    connect(actGroupBreak, SIGNAL(triggered()), this, SLOT(on_actGroupBreak_triggered()));
    connect(actEdit_Delete, SIGNAL(triggered()), this, SLOT(on_actEdit_Delete_triggered()));
    connect(actQuit, SIGNAL(triggered()), this, SLOT(close()));

    connect(actItem_Rect, SIGNAL(triggered()), this, SLOT(on_actItem_Rect_triggered()));
    connect(actItem_Ellipse, SIGNAL(triggered()), this, SLOT(on_actItem_Ellipse_triggered()));
    connect(actItem_Circle, SIGNAL(triggered()), this, SLOT(on_actItem_Circle_triggered()));
    connect(actItem_Triangle, SIGNAL(triggered()), this, SLOT(on_actItem_Triangle_triggered()));
    connect(actItem_Polygon, SIGNAL(triggered()), this, SLOT(on_actItem_Polygon_triggered()));
    connect(actItem_Line, SIGNAL(triggered()), this, SLOT(on_actItem_Line_triggered()));
    connect(actItem_Text, SIGNAL(triggered()), this, SLOT(on_actItem_Text_triggered()));

    connect(View, SIGNAL(mouseMovePoint(QPoint)), this, SLOT(on_mouseMovePoint(QPoint)));
    connect(View, SIGNAL(mouseClicked(QPoint)), this, SLOT(on_mouseClicked(QPoint)));
    connect(View, SIGNAL(mouseDoubleClick(QPoint)), this, SLOT(on_mouseDoubleClick(QPoint)));
    connect(View, SIGNAL(keyPress(QKeyEvent*)), this, SLOT(on_keyPress(QKeyEvent*)));
}

void MainWindow::on_mouseMovePoint(QPoint point){//鼠标移动事件,point是 GraphicsView的坐标,物理坐标
    labViewCord->setText(tr("View 坐标:%1, %2").arg(point.x()).arg(point.y()));
    QPointF pointScene = View->mapToScene(point); //转换到Scene坐标
    labSceneCord->setText(tr("Scene 坐标:%1, %2").arg(QString::number(pointScene.x(), 'f', 2)).arg(QString::number(pointScene.y(), 'f', 2)));
}

void MainWindow::on_mouseClicked(QPoint point){//鼠标单击事件
    QPointF pointScene = View->mapToScene(point); //转换到Scene坐标
    QGraphicsItem *item = scene->itemAt(pointScene ,View->transform()); //获取光标下的绘图项
    if(item != NULL) { //有绘图项
        QPointF pointItem = item->mapFromScene(pointScene); //转换为绘图项的局部坐标
        labItemCord->setText(QString::asprintf("Item 坐标:%.0f, %.0f", pointItem.x(), pointItem.y()));
        labItemInfo->setText(item->data(ItemDesciption).toString()+", ItemId="+ item->data(ItemId).toString());
        item->setZValue(++frontZ);
    }
}

void MainWindow::on_mouseDoubleClick(QPoint point){//鼠标双击事件,调用相应的对话框,设置填充颜色、线条颜色或字体
    QPointF pointScene = View->mapToScene(point); //转换到Scene坐标
    QGraphicsItem *item = scene->itemAt(pointScene, View->transform()); //获取光标下的绘图项

    if (item == NULL) //没有绘图项
        return;

    switch (item->type()) {  //绘图项的类型
    case    QGraphicsRectItem::Type: //矩形框
    { //强制类型转换
        QGraphicsRectItem *theItem = qgraphicsitem_cast<QGraphicsRectItem*>(item);
        setBrushColor(theItem);
        break;
    }
    case    QGraphicsEllipseItem::Type: //椭圆和圆都是 QGraphicsEllipseItem
    {
        QGraphicsEllipseItem *theItem = qgraphicsitem_cast<QGraphicsEllipseItem*>(item);
        setBrushColor(theItem);
        break;
    }

    case    QGraphicsPolygonItem::Type: //梯形和三角形
    {
        QGraphicsPolygonItem *theItem = qgraphicsitem_cast<QGraphicsPolygonItem*>(item);
        setBrushColor(theItem);
        break;
    }
    case    QGraphicsLineItem::Type: //直线,设置线条颜色
    {
        QGraphicsLineItem *theItem = qgraphicsitem_cast<QGraphicsLineItem*>(item);
        QPen pen = theItem->pen();
        QColor color = QColorDialog::getColor(pen.color(), this, tr("选择线条颜色"));
        if (color.isValid()){
            pen.setColor(color);
            theItem->setPen(pen);
        }
        break;
    }
    case QGraphicsTextItem::Type: //文字,设置字体
    {
        QGraphicsTextItem *theItem = qgraphicsitem_cast<QGraphicsTextItem*>(item);
        bool ok;
        QFont font = QFontDialog::getFont(&ok, theItem->font(), this, tr("设置字体"));
        if(ok)
            theItem->setFont(font);
        break;
    }
    }
}

void MainWindow::on_keyPress(QKeyEvent *event){ //按键事件
    if(scene->selectedItems().count()!=1)
        return; //没有选中的绘图项,或选中的多于1个

    QGraphicsItem *item = scene->selectedItems().at(0);

    if (event->key()==Qt::Key_Delete)//删除
        scene->removeItem(item);
    else if (event->key()==Qt::Key_Space) //顺时针旋转90度
        item->setRotation(90+item->rotation());
    else if (event->key()==Qt::Key_PageUp)//放大
        item->setScale(0.1+item->scale());
    else if (event->key()==Qt::Key_PageDown) //缩小
        item->setScale(-0.1+item->scale());
    else if (event->key()==Qt::Key_Left)  //左移
        item->setX(-1+item->x());
    else if (event->key()==Qt::Key_Right) //右移
        item->setX(1+item->x());
    else if (event->key()==Qt::Key_Up) //上移
        item->setY(-1+item->y());
    else if (event->key()==Qt::Key_Down) //下移
        item->setY(1+item->y());
}

void MainWindow::on_actZoomIn_triggered(){ //放大
    /*
    int cnt = scene->selectedItems().count();
    if(cnt==1){
        QGraphicsItem   *item = scene->selectedItems().at(0);
        item->setScale(0.1+item->scale());
    } else
        View->scale(1.1, 1.1);
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
        item->setScale(0.1+item->scale());
    }
}

void MainWindow::on_actZoomOut_triggered() {//缩小
    /*
    int cnt=scene->selectedItems().count();
    if(cnt==1) {
        QGraphicsItem *item = scene->selectedItems().at(0);
        item->setScale(item->scale()-0.1);
    } else
        View->scale(0.9, 0.9);
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
        if(item->scale()-0.1>0.0)
            item->setScale(item->scale()-0.1);
    }
}

void MainWindow::on_actRestore_triggered() {//取消所有变换
    /*
    int cnt = scene->selectedItems().count();
    if(cnt==1) {
        QGraphicsItem* item = scene->selectedItems().at(0);
        //        item->resetTransform();   //不起作用
        item->setRotation(0);
        item->setScale(1.0);
    } else
        View->resetTransform();
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
       //item->resetTransform();//失效
       item->setRotation(0.0);
       item->setScale(1.0);
    }
}

void MainWindow::on_actRotateLeft_triggered() {//逆时针旋转
    /*
    int cnt = scene->selectedItems().count();
    if(cnt==1) {
        QGraphicsItem* item = scene->selectedItems().at(0);
        item->setRotation(-30+item->rotation());
    } else
        View->rotate(-30);
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
       item->setRotation(item->rotation()-30.0);
    }
}

void MainWindow::on_actRotateRight_triggered() {//顺时针旋转
    /*
    int cnt=scene->selectedItems().count();
    if(cnt==1){
        QGraphicsItem* item = scene->selectedItems().at(0);
        item->setRotation(+30+item->rotation());
    } else
        View->rotate(+30);
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
       item->setRotation(item->rotation()+30.0);
    }
}

void MainWindow::on_actEdit_Front_triggered(){ //bring to front,前置
    int cnt = scene->selectedItems().count();
    if(cnt>0) { //只处理选中的第1个绘图项
        QGraphicsItem* item = scene->selectedItems().at(0);
        item->setZValue(++frontZ);
    }
}

void MainWindow::on_actEdit_Back_triggered() {//bring to back,后置
    int cnt = scene->selectedItems().count();
    if(cnt>0) {//只处理选中的第1个绘图项
        QGraphicsItem* item = scene->selectedItems().at(0);
        item->setZValue(--backZ);
    }
}

void MainWindow::on_actGroup_triggered() { //组合
    int cnt = scene->selectedItems().count();
    if(cnt>1){
        QGraphicsItemGroup* group = new QGraphicsItemGroup; //创建组合
        scene->addItem(group); //组合添加到场景中
        /*
        for(int i=0; i<cnt;i++){
            QGraphicsItem* item = scene->selectedItems().at(0);
            item->setSelected(false); //清除选择虚线框
            item->clearFocus();
            group->addToGroup(item); //添加到组合
        }
        */
        foreach(QGraphicsItem *item, scene->selectedItems()){
            item->setSelected(false); //清除选择虚线框
            item->clearFocus();
            group->addToGroup(item); //添加到组合
        }

        group->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
        group->setZValue(++frontZ);
        scene->clearSelection();
        group->setSelected(true);
    }
}

void MainWindow::on_actGroupBreak_triggered() { //break group,打散组合
    /*
    int cnt = scene->selectedItems().count();
    if(cnt==1){
        QGraphicsItemGroup  *group = (QGraphicsItemGroup*)scene->selectedItems().at(0);
        scene->destroyItemGroup(group);
    }
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
        QGraphicsItemGroup  *group = (QGraphicsItemGroup*)item;
        scene->destroyItemGroup(group);
    }
}

void MainWindow::on_actEdit_Delete_triggered() { //删除所有选中的绘图项
    /*
    int cnt = scene->selectedItems().count();
    for (int i=0; i<cnt; i++){
        QGraphicsItem*  item = scene->selectedItems().at(0);
        scene->removeItem(item); //删除绘图项
    }
    */
    foreach(QGraphicsItem *item, scene->selectedItems()){
       scene->removeItem(item); //删除绘图项
    }
}

void MainWindow::on_actItem_Rect_triggered() { //添加一个矩形
    QGraphicsRectItem *item = new QGraphicsRectItem(-50, -25, 100, 50);//x,y为左上角的图元局部坐标,图元中心点为0,0
    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setBrush(QBrush(Qt::yellow));
    item->setZValue(++frontZ);
    item->setPos(-50+(qrand()%100), -50+(qrand()%100));

    item->setData(ItemId, ++seqNum);
    item->setData(ItemDesciption, tr("矩形"));

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

void MainWindow::on_actItem_Ellipse_triggered() { //添加一个椭圆
    QGraphicsEllipseItem *item = new QGraphicsEllipseItem(-50, -30, 100, 60);
    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setBrush(QBrush(Qt::blue)); //填充颜色
    item->setZValue(++frontZ); //用于叠放顺序
    item->setPos(-50+(qrand()%100), -50+(qrand()%100)); //初始位置

    item->setData(ItemId, ++seqNum);  //自定义数据,ItemId键
    item->setData(ItemDesciption, tr("椭圆")); //自定义数据,ItemDesciption键

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

void MainWindow::on_actItem_Circle_triggered() { //添加圆形
    QGraphicsEllipseItem *item = new QGraphicsEllipseItem(-50, -50, 100, 100);
    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setBrush(QBrush(Qt::cyan));
    item->setZValue(++frontZ);
    item->setPos(-50+(qrand()%100), -50+(qrand()%100));

    item->setData(ItemId, ++seqNum);
    item->setData(ItemDesciption, tr("圆形"));

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

void MainWindow::on_actItem_Triangle_triggered() { //添加三角形
    QGraphicsPolygonItem *item = new QGraphicsPolygonItem;
    QPolygonF points;
    points.append(QPointF(0, -40));
    points.append(QPointF(60, 40));
    points.append(QPointF(-60, 40));
    item->setPolygon(points);

    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setBrush(QBrush(Qt::magenta));
    item->setZValue(++frontZ);
    item->setPos(-50+(qrand()%100), -50+(qrand()%100));

    item->setData(ItemId, ++seqNum);
    item->setData(ItemDesciption, tr("三角形"));

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

void MainWindow::on_actItem_Polygon_triggered() { //添加一个梯形
    QGraphicsPolygonItem *item = new QGraphicsPolygonItem;
    QPolygonF points;
    points.append(QPointF(-40, -40));
    points.append(QPointF(40, -40));
    points.append(QPointF(100, 40));
    points.append(QPointF(-100, 40));
    item->setPolygon(points);

    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setBrush(QBrush(Qt::green));
    item->setZValue(++frontZ);
    item->setPos(-50+(qrand()%100), -50+(qrand()%100));

    item->setData(ItemId, ++seqNum);
    item->setData(ItemDesciption, tr("梯形"));

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

void MainWindow::on_actItem_Line_triggered() {//添加直线
    QGraphicsLineItem *item = new QGraphicsLineItem(-100, 0, 100, 0);//x,y为左上角的图元局部坐标,图元中心点为0,0
    QPen pen(Qt::red);
    pen.setWidth(3);
    item->setPen(pen);

    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setZValue(++frontZ);
    item->setPos(-50+(qrand()%100), -50+(qrand()%100));

    item->setData(ItemId, ++seqNum);
    item->setData(ItemDesciption, tr("直线"));

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

void MainWindow::on_actItem_Text_triggered() { //添加文字
    QString str = QInputDialog::getText(this, tr("输入文字"), tr("请输入文字"));
    if(str.isEmpty())
        return;

    QGraphicsTextItem *item = new QGraphicsTextItem(str);
    QFont font = this->font();
    font.setPointSize(20);
    font.setBold(true);
    item->setFont(font);

    item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    item->setZValue(++frontZ);
    item->setPos(-50+(qrand()%100), -50+(qrand()%100));

    item->setData(ItemId, ++seqNum);
    item->setData(ItemDesciption, tr("文字"));

    scene->addItem(item);
    scene->clearSelection();
    item->setSelected(true);
}

qwgraphicsview.h

#ifndef QWGRAPHICSVIEW_H
#define QWGRAPHICSVIEW_H

#include <QGraphicsView>

class QWGraphicsView : public QGraphicsView {
    Q_OBJECT
public:
    explicit QWGraphicsView(QWidget *parent = 0);
protected:
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);
    void keyPressEvent(QKeyEvent *event);
signals:
    void mouseMovePoint(QPoint point); //鼠标移动
    void mouseClicked(QPoint point); //鼠标单击
    void mouseDoubleClick(QPoint point); //双击事件
    void keyPress(QKeyEvent *event); //按键事件
};

#endif // QWGRAPHICSVIEW_H

qwgraphicsview.cpp

#include "qwgraphicsview.h"
#include <QMouseEvent>
#include <QPoint>

QWGraphicsView::QWGraphicsView(QWidget *parent):QGraphicsView(parent) {

}

void QWGraphicsView::mouseMoveEvent(QMouseEvent *event) {//鼠标移动事件
    QPoint point = event->pos(); //QGraphicsView的坐标
    emit mouseMovePoint(point); //释放信号
    QGraphicsView::mouseMoveEvent(event);
}

void QWGraphicsView::mousePressEvent(QMouseEvent *event) { //鼠标左键按下事件
    if(event->button()==Qt::LeftButton) {
        QPoint point = event->pos(); //QGraphicsView的坐标
        emit mouseClicked(point);//释放信号
    }
    QGraphicsView::mousePressEvent(event);
}

void QWGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) { //鼠标双击事件
    if (event->buttons()&Qt::LeftButton) {
        QPoint point = event->pos(); //QGraphicsView的坐标
        emit mouseDoubleClick(point);//释放信号
    }
    QGraphicsView::mouseDoubleClickEvent(event);
}

void QWGraphicsView::keyPressEvent(QKeyEvent *event) { //按键事件
    emit keyPress(event);
    QGraphicsView::keyPressEvent(event);
}
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值