Qt图形视图框架
图形视图体系结构
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);
}