当前位置: 首页 > article >正文

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++开发指南》


http://www.kler.cn/a/415084.html

相关文章:

  • 《深入理解经典广度优先遍历算法》
  • 列表上移下移功能实现
  • 探索 Vue 3.0中Treeshaking特性?
  • Android获取内置卡、内置U盘和挂载U盘路径和内存大小
  • 格网法计算平面点云面积(matlab版本)
  • MFC 对话框中显示CScrollView实例
  • C0034.在Ubuntu中安装的Qt路径
  • 构建现代Web应用:FastAPI、SQLModel、Vue 3与Axios的结合使用
  • linux系统中常用文件日常使用命令记录
  • 架构第十四章:zabbix-4
  • C++条件编译指令
  • Unity ShaderLab 实现交互地毯
  • 【zookeeper04】消息队列与微服务之zookeeper客户端访问
  • Linux基础项目包含(DNS,FTP,Samba)
  • 华为IPD流程学习之——深入解读123页华为IPD流程体系设计方法论PPT
  • STM32-- 看门狗--介绍、使用场景、失效场景
  • 2024健康大数据与智能医疗(ICHIH 2024)
  • LLM*:路径规划的大型语言模型增强增量启发式搜索
  • 第一篇:Admin.Net前端项目启动
  • LSTM卫星轨道预测(一)
  • 【HarmonyOS开发模板/组件分享 – 用户隐私政策弹窗】
  • 贪心算法-Huffman树 不等式 推公式
  • iscsi服务器
  • [问题记录] Android裁剪Provision应用后无法打开开发者选项
  • 基于Linux操作系统的DNS服务器实验
  • python网络爬虫进阶