欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > QT图形/视图架构详解(二)

QT图形/视图架构详解(二)

2025/2/23 10:40:10 来源:https://blog.csdn.net/qq_46144191/article/details/144453178  浏览:    关键词:QT图形/视图架构详解(二)

上一章节示例程序仅演示了Graphics View 的基本结构和三个坐标系的概念,在本章程序中演示其更多的功能。

这个示例程序具有如下的功能:

● 可以创建矩形、椭圆、圆形、三角形、梯形、直线、文字等基本图形项。

● 每个图形项都可以被选择和拖动。

● 图形项或整个视图可以缩放和旋转。

● 图形项重叠时,可以调整前置或后置。

● 多个图形项可以组合,也可以解除组合。

● 可以删除选择的图形项。

● 鼠标在视图上移动时,会在状态栏显示视图坐标和场景坐标。

● 鼠标单击某个图形项时,会显示图形项的局部坐标,还会显示图形项的文字描述和编号。

● 双击某个图形项时,会根据图形项的类型调用颜色对话框或字体对话框,设置图形项的填充颜色、 线条颜色或文字的字体。

● 选中某个图形项时,可以进行按键操作,Delete 键删除图形项,PgUp 放大,PgDn 缩小,空格键旋转 90 度,上下左右光标键移动图形项。

● 鼠标右键长按拖拽场景,在视图小于场景的时候可以拖拽以显示感兴趣内容,而无需拖动滚动条

● 鼠标滚轮可以控制视图的缩放。

TGraphicsView类修改

首先重写TGraphicsView。修改实现的功能如下:

鼠标滚轮视图缩放

添加一个wheelEvent事件,用来获取鼠标滚轮量,正值表示滚轮远离,负值表示滚轮靠近,根据滚轮的正负值进行视图的缩放。

//添加对视图的缩放
void TGraphicsView::wheelEvent(QWheelEvent *event){// 滚轮的滚动量//在Qt 5中,delta() 函数用于获取滚轮的滚动量。但在Qt 6中,你应该使用 angleDelta() 函数来替代 delta() 函数。QPoint scrollAmount = event->angleDelta();// 正值表示滚轮远离使用者放大负值表示朝向使用者缩小scrollAmount.y() > 0 ? ZoomIn() : ZoomOut();
}//放大
void TGraphicsView::ZoomIn(){Zoom(1.1);
}//缩小
void TGraphicsView::ZoomOut(){Zoom(0.9);
}void TGraphicsView::Zoom(float scaleFactor){// 防止过小或过大qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();if (factor < 0.07 || factor > 100)return;scale(scaleFactor, scaleFactor);
}

Graphics View的transform函数可以对视图进行从常见的变换,包括平移、缩放、旋转等。setTransform方法可以设置视图的变换矩阵,也可以通过scale、rotate、translate等方法来实现对视图的变换。变换矩阵可以通过QTransform类来表示。QGraphicsView的变换可以对视图中的所有图形项生效,也可以对指定的图形项进行局部变换。

场景拖拽

当视图缩小比场景还小时,有些图形项会看不到,这时候可以通过鼠标右键来拖拽场景使其部分窗口显示在视图中。

设置一个变量m_isTranslate来跟踪鼠标右键状态,右键按下时设置为true,右键松开设置为false,然后在鼠标mouseMoveEvent事件中来拖拽场景。

void TGraphicsView::mousePressEvent(QMouseEvent *event)
{ //鼠标左键按下事件if (event->button()==Qt::RightButton)     //右键键长按用于拖拽场景{m_isTranslate = true;   //按下标志m_lastMousePos = event->pos();this->setCursor(Qt::OpenHandCursor);}QGraphicsView::mousePressEvent(event);
}//鼠标释放事件
void TGraphicsView::mouseReleaseEvent(QMouseEvent *event){if (event->button() == Qt::RightButton){m_isTranslate = false;    //松开标志this->setCursor(Qt::CrossCursor);}QGraphicsView::mouseReleaseEvent(event);}void TGraphicsView::mouseMoveEvent(QMouseEvent *event)
{ //鼠标移动事件if(m_isTranslate){//获取QPointF mouseDelta = event->pos()-m_lastMousePos;   //获取移动的向量,方向指的是newpointTranslate(mouseDelta);}m_lastMousePos = event->pos();}void TGraphicsView::Translate(QPointF delta)
{int w = viewport()->rect().width();   //获取视图宽度int h = viewport()->rect().height();  //获取视图高度// (w / 2,h / 2)即为视图的中心QPoint newCenter(w / 2. - delta.x()+0.5,  h / 2. - delta.y()+0.5); //获取中心的偏移量centerOn(mapToScene(newCenter));   //反馈到场景当中,mapToScene将坐标转为场景坐标
}

代码中通过按下后当前点和上一次的点进行向量计算,得到拖拽的偏移量,然后转成中心点的偏移量,然后将中心坐标映射到场景中心,重新设置场景中心就相当于拖拽了场景。

完整的自定义Graphics View类代码如下所示:

/.h文件///
#ifndef TGRAPHICSVIEW_H
#define TGRAPHICSVIEW_H#include <QObject>
#include <QGraphicsView>class TGraphicsView : public QGraphicsView
{Q_OBJECTprotected:void mouseMoveEvent(QMouseEvent *event);void mousePressEvent(QMouseEvent *event);void mouseDoubleClickEvent(QMouseEvent *event);void keyPressEvent(QKeyEvent *event);void wheelEvent(QWheelEvent *event);void mouseReleaseEvent(QMouseEvent *event);public:TGraphicsView(QWidget *parent = nullptr);void ZoomIn();void ZoomOut();void Zoom(float scaleFactor);void Translate(QPointF delta);signals:void mouseMovePoint(QPoint point);      //鼠标移动void mouseClicked(QPoint point);        //鼠标单击void mouseDoubleClick(QPoint point);    //双击事件void keyPress(QKeyEvent *event);        //按键事件private:bool m_isTranslate;QPoint m_lastMousePos;};#endif // TGRAPHICSVIEW_H//.cpp文件
#include    "tgraphicsview.h"
#include    <QMouseEvent>
#include    <QPoint>void TGraphicsView::mouseMoveEvent(QMouseEvent *event)
{ //鼠标移动事件if(m_isTranslate){//获取QPointF mouseDelta = event->pos()-m_lastMousePos;   //获取移动的向量,方向指的是newpointTranslate(mouseDelta);}m_lastMousePos = event->pos();QPoint point=event->pos();      //QGraphicsView的坐标emit mouseMovePoint(point);     //发射信号QGraphicsView::mouseMoveEvent(event);   
}void TGraphicsView::mousePressEvent(QMouseEvent *event)
{ //鼠标左键按下事件if (event->button()==Qt::RightButton)     //右键键长按用于拖拽场景{m_isTranslate = true;   //按下标志m_lastMousePos = event->pos();this->setCursor(Qt::OpenHandCursor);}if(event->button()==Qt::LeftButton){    //左键长按用于移动图形项目QPoint point=event->pos();  //QGraphicsView的坐标emit mouseClicked(point);   //发射信号}QGraphicsView::mousePressEvent(event);
}void TGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
{ //鼠标双击事件if (event->button()==Qt::LeftButton){QPoint point=event->pos();      //QGraphicsView的坐标emit mouseDoubleClick(point);   //发射信号}QGraphicsView::mouseDoubleClickEvent(event);
}void TGraphicsView::keyPressEvent(QKeyEvent *event)
{ //按键事件emit keyPress(event);       //发射信号QGraphicsView::keyPressEvent(event);
}//鼠标释放事件
void TGraphicsView::mouseReleaseEvent(QMouseEvent *event){if (event->button() == Qt::RightButton){m_isTranslate = false;    //松开标志this->setCursor(Qt::CrossCursor);}QGraphicsView::mouseReleaseEvent(event);}//添加对视图的缩放
void TGraphicsView::wheelEvent(QWheelEvent *event){// 滚轮的滚动量//在Qt 5中,delta() 函数用于获取滚轮的滚动量。但在Qt 6中,你应该使用 angleDelta() 函数来替代 delta() 函数。QPoint scrollAmount = event->angleDelta();// 正值表示滚轮远离使用者放大负值表示朝向使用者缩小scrollAmount.y() > 0 ? ZoomIn() : ZoomOut();QGraphicsView::wheelEvent(event);
}//放大
void TGraphicsView::ZoomIn(){Zoom(1.1);
}//缩小
void TGraphicsView::ZoomOut(){Zoom(0.9);
}void TGraphicsView::Zoom(float scaleFactor){// 防止过小或过大qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();if (factor < 0.07 || factor > 100)return;scale(scaleFactor, scaleFactor);
}void TGraphicsView::Translate(QPointF delta)
{int w = viewport()->rect().width();   //获取视图宽度int h = viewport()->rect().height();  //获取视图高度// (w / 2,h / 2)即为视图的中心QPoint newCenter(w / 2. - delta.x()+0.5,  h / 2. - delta.y()+0.5); //获取中心的偏移量centerOn(mapToScene(newCenter));   //反馈到场景当中,mapToScene将坐标转为场景坐标
}TGraphicsView::TGraphicsView(QWidget *parent):QGraphicsView(parent)
{}

主界面窗口程序

主窗口类

头文件如下所示

///mainwindow.h///#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>#include    <QGraphicsScene>
#include    <QLabel>
#include    <QRandomGenerator>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTprivate:const   quint32 boundValue=100;     //随机数上限值//    QRandomGenerator* random;           //随机数发生器const int ItemId = 1;            //绘图项自定义数据的keyconst int ItemDesciption = 2;    //绘图项自定义数据的keyint seqNum=0;   //用于图形项的编号,每个图形项有一个编号int backZ=0;    //用于bring to frontint frontZ=0;   //用于bring to backQGraphicsScene  *scene;     //场景QLabel  *labViewCord;       //用于状态栏QLabel  *labSceneCord;QLabel  *labItemCord;QLabel  *labItemInfo;void    setItemProperty(QGraphicsItem* item, QString desciption);   //设置图形项的属性
public:MainWindow(QWidget *parent = nullptr);~MainWindow();
private slots://自定义槽函数void    do_mouseMovePoint(QPoint point);    //鼠标移动void    do_mouseClicked(QPoint point);      //鼠标单击void    do_mouseDoubleClick(QPoint point);  //鼠标双击void    do_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();//    void on_actBackBrush_triggered();void on_actHelp_triggered();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

● 常数 boundValue 用于设置随机数发生器产生随机数的数值上限值。

● 常数 ItemId 和 ItemDesciption 是用于设置图形项的自定义数据时用到的键。

● 变量 seqNum 用于给每个图形项编号,每个图形项有一个唯一编号。

● 变量 frontZ 用于设置图形项的叠放顺序,数值越大,越在前面显示。

● 变量 backZ 用于设置图形项的叠放顺序,数值越小,越在后面显示。

私有函数 setItemProperty()用于在场景图形项后,设置图形项的属性。

在主窗口构造函数中,为视图创建场景对象scene,并与界面上的组件关联,连接视图发送的鼠标和按键对应的响应槽函数。注意这些信号是视图中自动监听事件发生后传递给外界的,视图本生的事件函数处理的是对于视图自身的操作,而这些信号是发送给其他组件的,在这个例子中是mainwindow组件用于组件中的通信(这些信号也可以被视图自生使用,这里没有使用)

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{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,400);    //创建QGraphicsScene//    scene->setBackgroundBrush(QBrush(Qt::white));ui->view->setScene(scene);          //scene与view关联ui->view->setCursor(Qt::CrossCursor);   //设置鼠标光标// ui->view->setCursor(Qt::DragMoveCursor);   //设置鼠标光标ui->view->setMouseTracking(true);       //设置鼠标跟踪ui->view->setDragMode(QGraphicsView::RubberBandDrag);   //设置拖动模式this->setCentralWidget(ui->view);connect(ui->view,&TGraphicsView::mouseMovePoint,this, &MainWindow::do_mouseMovePoint);connect(ui->view,&TGraphicsView::mouseClicked,this, &MainWindow::do_mouseClicked);connect(ui->view,&TGraphicsView::keyPress, this, &MainWindow::do_keyPress);connect(ui->view,&TGraphicsView::mouseDoubleClick,this, &MainWindow::do_mouseDoubleClick);//	QObject::connect(ui->view,SIGNAL(mouseMovePoint(QPoint)), this, SLOT(do_mouseMovePoint(QPoint)));//	QObject::connect(ui->view,SIGNAL(mouseClicked(QPoint)),this, SLOT(do_mouseClicked(QPoint)));//	QObject::connect(ui->view,SIGNAL(mouseDoubleClick(QPoint)), this, SLOT(do_mouseDoubleClick(QPoint)));//	QObject::connect(ui->view,SIGNAL(keyPress(QKeyEvent*)),this, SLOT(do_keyPress(QKeyEvent*)));
}

鼠标与键盘信号槽函数

鼠标移动:鼠标在视图上移动时,在状态栏显示光标处的视图坐标和场景坐标。

鼠标左键单击:在视图上单击鼠标选中一个图形项时,程序会在状态栏上显示图形项的局部坐标,并提取其自定义信息并显示。获得的视图坐标 point 需要转换为场景中的坐标 pointScene,再利用 QGraphicsScene 的itemAt()函数获得光标处的图形项。利用 QGraphicsItem 的 mapFromScene()函数将 pointScene 转换为图形项的局部坐标 pointItem。用 data()函数提取图形项的自定义数据。

鼠标左键双击:当鼠标双击某个图形项时,当图形项是矩形、圆形、梯形等有填充色的对象时打开一个颜色选择对话框,设置其填充颜色;当图形项是直线时,设置其线条颜色;当图形项是文字时,打开一个字体对话框,设置其字体。

键盘按键操作:在选中一个图形项之后,我们可以通过键盘按键实现一些快捷操作,例如缩放、旋转、移动等。

这四个槽函数对应的定义如下所示:

//鼠标移动,point是视图的坐标,物理坐标
void MainWindow::do_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 MainWindow::do_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());}
}template<class T> void setBrushColor(T *item)
{QColor color=item->brush().color();color=QColorDialog::getColor(color,NULL,"选择填充颜色");if (color.isValid())item->setBrush(QBrush(color));
}//鼠标双击事件,调用相应的对话框,设置填充颜色、线条颜色或字体
void MainWindow::do_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的枚举值Type{QGraphicsRectItem *theItem =qgraphicsitem_cast<QGraphicsRectItem*>(item);setBrushColor(theItem);break;}case    QGraphicsEllipseItem::Type: //椭圆或圆{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=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 MainWindow::do_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());
}

图形项的创建

setItemProperty()函数用于设置图形项的属性,如是否可移动,可选中,可获得焦点、叠放顺序、在场景中的位置,图形项编号、描述;最后再将该图形项添加到场景中(场景是一个容器);

void MainWindow::setItemProperty(QGraphicsItem *item,QString desciption)
{item->setFlags(QGraphicsItem::ItemIsMovable         //可移动| QGraphicsItem::ItemIsSelectable    //可选中| QGraphicsItem::ItemIsFocusable);   //可以获得焦点item->setZValue(++frontZ);      //叠放顺序号quint32 v1=QRandomGenerator::global()->bounded(boundValue);quint32 v2=QRandomGenerator::global()->bounded(boundValue);item->setPos(v1,v2);    //在场景中的位置item->setData(ItemId,++seqNum);             //图形项编号item->setData(ItemDesciption,desciption);   //图形项描述scene->addItem(item);       //添加到场景scene->clearSelection();item->setSelected(true);
}

setZValue()函数设置图形项的 Z 值,Z 值控制叠放顺序,当有多个图形项叠放在一起时,Z 值最大

的显示在最前面。这里意思是越新创建的叠放是在最前面。

setPos(x, y)函数设置图形项的位置,如果图形项有父容器项,坐标(x, y)是父容器的坐标,否则就是图形场景的坐标。

程序中使用了全局的随机数发生器 QRandomGenerator::global(),使用函数 bounded() 产生限制范围的随机数。将随机数生成的值作为图形项的放置位置。。

setData()函数用于设置图形项的自定义数据,这个函数的原型定义如下:

void QGraphicsItem::setData(int key, const QVariant &value)

参数 key 是数据名称,value 是具体的数据内容,可以是任何类型。key 和 value 是一个键值对使 用 setData()一次可以设置一个键值对,可以为一个图形项设置多个自定义键值对。

创建矩形

void MainWindow::on_actItem_Rect_triggered()
{ //添加一个矩形//x,y 为左上角的图元局部坐标,图元中心点为0,0QGraphicsRectItem   *item=new QGraphicsRectItem(-50,-25,100,50);item->setBrush(QBrush(Qt::yellow));setItemProperty(item, "矩形");
}

创建椭圆

void MainWindow::on_actItem_Ellipse_triggered()
{ //添加一个椭圆QGraphicsEllipseItem   *item=new QGraphicsEllipseItem(-50,-30,100,60);item->setBrush(QBrush(Qt::blue));   //填充颜色setItemProperty(item, "椭圆");
}

创建梯形

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->setBrush(QBrush(Qt::green));setItemProperty(item,"梯形");
}

创建直线

void MainWindow::on_actItem_Line_triggered()
{//添加直线QGraphicsLineItem   *item=new QGraphicsLineItem(-100,0,100,0);QPen    pen(Qt::red);pen.setWidth(3);item->setPen(pen);setItemProperty(item,"直线");
}

创建文字

void MainWindow::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);    //设置字体setItemProperty(item,"文字");
}

创建圆形

void MainWindow::on_actItem_Circle_triggered()
{ //添加圆形QGraphicsEllipseItem   *item=new QGraphicsEllipseItem(-50,-50,100,100);item->setBrush(QBrush(Qt::cyan));setItemProperty(item,"圆形");
}

创建三角形

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));//    points.append(QPointF(0,0));  //添加顶点坐标//    points.append(QPointF(50,0));//    points.append(QPointF(0,50));item->setPolygon(points);       //三角形就是一种多边形item->setBrush(QBrush(Qt::magenta));setItemProperty(item,"三角形");
}

图形项的操作

主窗口上水平工具栏上的一些按钮实现图形项的缩放、旋转、组合等操作。

缩放

图形项的缩放使用 QGraphicsItem 的 setScale()函数,参数大于 1 是放大,小于 1 是缩小。下面是放大和缩小按钮关联的槽函数代码:

void MainWindow::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 MainWindow::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);
}

QGraphicsScene 的 selectedItems()函数返回场景中选中的图形项的列表。如果只有一个图形项被选 中,就用 QGraphicsItem 的 setScale()函数对图形项进行缩放;如果选中的图形项个数大于 1个,或没有图形项被选中,就用 QGraphicsView 的 scale()函数对绘图视图进行缩放。

旋转

图形项的旋转使用 QGraphicsItem 的 setRotation()函数,参数为角度值,正值表示顺时针旋转,负值表示逆时针旋转。下面是左旋转和右旋转按钮关联的槽函数代码:

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        //视图旋转ui->view->rotate(+30);
}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);}
}

恢复坐标变换

缩放和旋转都是坐标变换,要取消所有变换恢复初始状态,调用 QGraphicsItem 或QGraphicsView 的 resetTransform()函数。下面是“恢复”按钮关联的槽函数代码:

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        //针对视图ui->view->resetTransform();
}

改变叠放顺序

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);}}

frontZ 和 backZ 是在 MainWindow 类中定义的私有变量,专门用于存储叠放次序的编号。frontZ只

增加,所以每增加一次都是最大值,设置该值的图形项就可以显示在最前面;backZ 只减少,所以每减小一次都是最小值,设置该值的图形项就可以显示在最后面。

图形项组合与拆解

可以将多个图形项组合为一个图形项,当做一个整体进行操作,如同 PowerPoint 软件里图形组合 功能一样。使用 QGraphicsItemGroup 类实现多个图形项的组合,QGraphicsItemGroup 是QGraphicsItem 的子类,所以,实质上也是一个图形项。

当有多个图形项被选择时,程序创建一个QGraphicsItemGroup类型的对象group,并添加到场景中,然后将选中的图形项逐一添加到 group 中。这样创建的 group 就是场景中的一个图形项,可以对其进行缩放、旋转等操作。

一个组合对象也可以被打散,使用 QGraphicsScene 的 destroyItemGroup()函数可以打散一个组合对象。这个函数打散组合,删除组合对象,但是不删除原来组合里的图形项。

组合与拆解的槽函数如下所示:

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);     //添加到组合}setItemProperty(group, "组合");   //设置特性}
}void MainWindow::on_actGroupBreak_triggered()
{ //break group,打散组合int cnt=scene->selectedItems().count();if (cnt==1){QGraphicsItemGroup  *group;group=(QGraphicsItemGroup*)scene->selectedItems().at(0);scene->destroyItemGroup(group); //打散组合}
}

图形项的删除

使用 QGraphicsScene 的 removeItem()函数从场景中移除某个图形项,函数如下:


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);    //移除图形项delete item;    //删除对象,释放内存}
}

注意此处scene->removeItem(item);只是从场景中移除了图形项,表示场景不再管理该图形项,但是其占据的内存依然存在,因此需要使用delete来彻底消除。添加到场景中的图形项最后无需手工删除,在场景被删除时,其中的图形项也会自动被删除。

额外技巧:在设计好一款软件后,需要为该软件写一个使用说明文档,可以通过点击界面的按钮来触发打开相应的文档。示例代码如下:

void MainWindow::on_actHelp_triggered()
{QString   helpFile=QCoreApplication::applicationDirPath()+"/说明文档.pdf";QDesktopServices::openUrl(QUrl::fromLocalFile(helpFile));
}

参考

Qt 6 C++开发指南

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词