Qt Graphics View 绘图实例
Qt Graphics View 绘图实例
这个实例程序实现如下功能:
- 可以创建矩形、椭圆、三角形、梯形、直线、文字等基本图形。
- 每个图形项都可以被选择和移动。
- 图形项或整个视图可以缩放和旋转。
- 图形项重叠时,可以调整前置或后置。
- 多个图形项可以组合,也可以解散组合。
- 可以删除选择的图形项。
- 鼠标在视图上移动时,会在状态栏显示视图坐标和场景坐标。
- 鼠标单击某个图形是,会显示图形项的局部坐标,也会显示图形项的文字描述和编号。
- 双击某个图形项时,会显示图形项的类型调用颜色对话框,设置图形项的填充颜色、线条颜色或文字的字体。
- 选中某个图形项时,可以进行按键操作,Delete 键删除图形项,PageUp 放大, PageDn 缩小,空格键旋转90°,上下左右光标键移动图形项。
"QWGraphicsView.h" 头文件代码如下:
#pragma once
#include <QGraphicsView>
#include <QObject>
class QWGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
QWGraphicsView(QWidget *parent);
~QWGraphicsView();
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);//按键事件
};
QWGraphicsView 类的 4个事件的实现代码,在每个事件里发射相应的信号。在QWGraphicsView 类里,将鼠标和键盘事件转换为信号,就可以利用信号与槽机制,在主程序里设计槽函数相对应的鼠标和键盘操作进行响应。
鼠标移动事件、鼠标左键按下事件、鼠标双击事件、按键事件
"QWGraphicsView.cpp" 文件代码如下:
#include "QWGraphicsView.h"
#include <QMouseEvent>
#include <QPoint>
//解决QT中中文显示乱码问题
#pragma execution_character_set("utf-8")
QWGraphicsView::QWGraphicsView(QWidget *parent)
: QGraphicsView(parent)
{
}
QWGraphicsView::~QWGraphicsView()
{
}
//鼠标移动事件
void QWGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
//QPoint point;
QPoint point = event->pos();//QGraphicsView的坐标
emit mouseMovePoint(point); //释放信号
QGraphicsView::mouseMoveEvent(event);
}
//鼠标左键按下事件
void QWGraphicsView::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
//QPoint point;
QPoint point = event->pos();//QGraphicsView的坐标
emit mouseClicked(point);//释放信号
}
QGraphicsView::mousePressEvent(event);
}
//鼠标双击事件
void QWGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
//QPoint point;
QPoint point = event->pos(); //QGraphicsView的坐标
emit mouseDoubleClick(point);//释放信号
}
QGraphicsView::mouseDoubleClickEvent(event);
}
//按键事件
void QWGraphicsView::keyPressEvent(QKeyEvent *event)
{
emit keyPress(event);
QGraphicsView::keyPressEvent(event);
}
"sample8_5QGraphicsDraw.h" 头文件代码如下:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_sample8_5QGraphicsDraw.h"
#include <QLabel>
#include <QGraphicsScene>
class sample8_5QGraphicsDraw : public QMainWindow
{
Q_OBJECT
public:
sample8_5QGraphicsDraw(QWidget *parent = Q_NULLPTR);
private:
Ui::sample8_5QGraphicsDrawClass ui;
private:
static const int ItemId = 1;//绘图项自定义数据的key
static const int ItemDesciption = 2;//绘图项自定义数据的key
int seqNum = 0;
int backZ = 0;
int frontZ = 0;
QGraphicsScene *scene;
QLabel *labViewCord;
QLabel *labSceneCord;
QLabel *labItemCord;
QLabel *labItemInfo;
private slots:
void on_mouseMovePoint(QPoint point);//鼠标移动
void on_mouseClicked(QPoint point);//鼠标单击
void on_mouseDoubleClick(QPoint point);//鼠标双击
void on_keyPress(QKeyEvent *event);//按键
void on_actItem_Rect_triggered();
void on_actItem_Ellipse_triggered();
void on_actItem_Polygon_triggered();
void on_actEdit_Delete_triggered();
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_actItem_Line_triggered();
void on_actItem_Text_triggered();
void on_actGroup_triggered();
void on_actGroupBreak_triggered();
void on_actItem_Circle_triggered();
void on_actItem_Triangle_triggered();
};
#include "sample8_5QGraphicsDraw.h"
#include <QGraphicsRectItem>
#include <QInputDialog>
#include <QColorDialog>
#include <QFontDialog>
#include <QTime>
#include <QKeyEvent>
//解决QT中中文显示乱码问题
#pragma execution_character_set("utf-8")
//函数模板
template<class T> void setBrushColor(T *item)
{
QColor color = item->brush().color();
color = QColorDialog::getColor(color, NULL, "选择填充颜色");
if (color.isValid())
{
item->setBrush(QBrush(color));
}
}
sample8_5QGraphicsDraw::sample8_5QGraphicsDraw(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
labViewCord = new QLabel("View 坐标:"); //创建状态栏标签
labViewCord->setMinimumWidth(150);
ui.statusBar->addWidget(labViewCord);
labSceneCord = new QLabel("Scene 坐标:");
labSceneCord->setMinimumWidth(150);
ui.statusBar->addWidget(labSceneCord);
labItemCord = new QLabel("Item 坐标:");
labItemCord->setMinimumWidth(150);
ui.statusBar->addWidget(labItemCord);
labItemInfo = new QLabel("ItemInfo: ");
labItemInfo->setMinimumWidth(200);
ui.statusBar->addWidget(labItemInfo);
scene = new QGraphicsScene(-300, -200, 600, 200); //创建QGraphicsScene
ui.View->setScene(scene); //与view关联
//ui.View->setDragMode(QGraphicsView::RubberBandDrag);
ui.View->setCursor(Qt::CrossCursor); //设置鼠标
ui.View->setMouseTracking(true); //
ui.View->setDragMode(QGraphicsView::RubberBandDrag);
this->setCentralWidget(ui.View);
QObject::connect(ui.View, SIGNAL(mouseMovePoint(QPoint)),
this, SLOT(on_mouseMovePoint(QPoint)));
QObject::connect(ui.View, SIGNAL(mouseClicked(QPoint)),
this, SLOT(on_mouseClicked(QPoint)));
QObject::connect(ui.View, SIGNAL(mouseDoubleClick(QPoint)),
this, SLOT(on_mouseDoubleClick(QPoint)));
QObject::connect(ui.View, SIGNAL(keyPress(QKeyEvent*)),
this, SLOT(on_keyPress(QKeyEvent*)));
qsrand(QTime::currentTime().second());
}
鼠标移动事件,point是 GraphicsView的坐标,物理坐标
//鼠标移动事件,point是 GraphicsView的坐标,物理坐标
void sample8_5QGraphicsDraw::on_mouseMovePoint(QPoint point)
{
labViewCord->setText(QString::asprintf("View 坐标:%d,%d", point.x(), point.y()));
QPointF pointScene = ui.View->mapToScene(point); //转换到Scene坐标
labSceneCord->setText(QString::asprintf("Scene 坐标:%.0f,%.0f", pointScene.x(), pointScene.y()));
}
鼠标单击事件
//鼠标单击事件
void sample8_5QGraphicsDraw::on_mouseClicked(QPoint point)
{
QPointF pointScene = ui.View->mapToScene(point); //转换到Scene坐标
QGraphicsItem *item = NULL;
item = scene->itemAt(pointScene, ui.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());
}
}
鼠标双击事件,调用相应的对话框,设置填充颜色、线条颜色或字体
//鼠标双击事件,调用相应的对话框,设置填充颜色、线条颜色或字体
void sample8_5QGraphicsDraw::on_mouseDoubleClick(QPoint point)
{
QPointF pointScene = ui.View->mapToScene(point); //转换到Scene坐标
QGraphicsItem *item = NULL;
item = scene->itemAt(pointScene, ui.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;
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 = theItem->pen().color();
color = QColorDialog::getColor(color, this, "选择线条颜色");
if (color.isValid())
{
pen.setColor(color);
theItem->setPen(pen);
}
break;
}
case QGraphicsTextItem::Type: //文字,设置字体
{
QGraphicsTextItem *theItem = qgraphicsitem_cast<QGraphicsTextItem*>(item);
QFont font = theItem->font();
bool ok = false;
font = QFontDialog::getFont(&ok, font, this, "设置字体");
if (ok)
theItem->setFont(font);
break;
}
}
}
按键事件
//按键事件
void sample8_5QGraphicsDraw::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 sample8_5QGraphicsDraw::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, "矩形");
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
添加一个椭圆
//添加一个椭圆
void sample8_5QGraphicsDraw::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, "椭圆"); //自定义数据,ItemDesciption键
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
添加一个梯形
//添加一个梯形
void sample8_5QGraphicsDraw::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->setPos(-50 + (qrand() % 100), -50 + (qrand() % 100));
item->setFlags(QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsFocusable);
item->setBrush(QBrush(Qt::green));
item->setZValue(++frontZ);
item->setData(ItemId, ++seqNum);
item->setData(ItemDesciption, "梯形");
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
删除所有选中的绘图项
//删除所有选中的绘图项
void sample8_5QGraphicsDraw::on_actEdit_Delete_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt > 0)
for (int i = 0; i < cnt; i++)
{
QGraphicsItem* item = scene->selectedItems().at(0);
scene->removeItem(item); //删除绘图项
}
}
放大
//放大
void sample8_5QGraphicsDraw::on_actZoomIn_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt == 1)
{
QGraphicsItem *item;
item = scene->selectedItems().at(0);
item->setScale(0.1 + item->scale());
}
else
{
ui.View->scale(1.1, 1.1);
}
}
缩小
//缩小
void sample8_5QGraphicsDraw::on_actZoomOut_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt == 1)
{
QGraphicsItem *item;
item = scene->selectedItems().at(0);
item->setScale(item->scale() - 0.1);
}
else
{
ui.View->scale(0.9, 0.9);
}
}
取消所有变换
//取消所有变换
void sample8_5QGraphicsDraw::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
{
ui.View->resetTransform();
}
}
逆时针旋转、顺时针旋转
//逆时针旋转
void sample8_5QGraphicsDraw::on_actRotateLeft_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt == 1)
{
QGraphicsItem* item = scene->selectedItems().at(0);
item->setRotation(-30 + item->rotation());
}
else
{
ui.View->rotate(-30);
}
}
//顺时针旋转
void sample8_5QGraphicsDraw::on_actRotateRight_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt == 1)
{
QGraphicsItem* item = scene->selectedItems().at(0);
item->setRotation(+30 + item->rotation());
}
else
{
ui.View->rotate(+30);
}
}
前置、后置
//bring to front,前置
void sample8_5QGraphicsDraw::on_actEdit_Front_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt > 0)
{ //只处理选中的第1个绘图项
QGraphicsItem* item = scene->selectedItems().at(0);
item->setZValue(++frontZ);
}
}
//bring to back,后置
void sample8_5QGraphicsDraw::on_actEdit_Back_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt > 0)
{//只处理选中的第1个绘图项
QGraphicsItem* item = scene->selectedItems().at(0);
item->setZValue(--backZ);
}
}
添加直线
//添加直线
void sample8_5QGraphicsDraw::on_actItem_Line_triggered()
{
QGraphicsLineItem *item = new QGraphicsLineItem(-100, 0, 100, 0);//x,y 为左上角的图元局部坐标,图元中心点为0,0
item->setFlags(QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsFocusable);
QPen pen(Qt::red);
pen.setWidth(3);
item->setPen(pen);
item->setZValue(++frontZ);
item->setPos(-50 + (qrand() % 100), -50 + (qrand() % 100));
item->setData(ItemId, ++seqNum);
item->setData(ItemDesciption, "直线");
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
添加文字
//添加文字
void sample8_5QGraphicsDraw::on_actItem_Text_triggered()
{
QString str = QInputDialog::getText(this, "输入文字", "请输入文字");
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->setPos(-50 + (qrand() % 100), -50 + (qrand() % 100));
item->setZValue(++frontZ);
item->setData(ItemId, ++seqNum);
item->setData(ItemDesciption, "文字");
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
添加圆形、添加三角形
//添加圆形
void sample8_5QGraphicsDraw::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, "圆形");
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
//添加三角形
void sample8_5QGraphicsDraw::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->setPos(-50 + (qrand() % 100), -50 + (qrand() % 100));
item->setFlags(QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsFocusable);
item->setBrush(QBrush(Qt::magenta));
item->setZValue(++frontZ);
item->setData(ItemId, ++seqNum);
item->setData(ItemDesciption, "三角形");
scene->addItem(item);
scene->clearSelection();
item->setSelected(true);
}
组合、打散组合
//组合
void sample8_5QGraphicsDraw::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); //添加到组合
}
group->setFlags(QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsFocusable);
group->setZValue(++frontZ);
//group->clearFocus();
scene->clearSelection();
group->setSelected(true);
}
}
//break group,打散组合
void sample8_5QGraphicsDraw::on_actGroupBreak_triggered()
{
int cnt = scene->selectedItems().count();
if (cnt == 1)
{
QGraphicsItemGroup *group;
group = (QGraphicsItemGroup*)scene->selectedItems().at(0);
scene->destroyItemGroup(group);
}
}
《Qt5/6 C++开发指南》