Qt_绘图框架_QGraphicsview实现缩放移动图片

文章目录

  • 1. 功能说明
  • 2. 实现原理说明
  • 3. 建工程
    • 3.1 界面
    • 3.2 文件
  • 4. 源码
  • 5. 参考文献

1. 功能说明

  1. LoadImage按钮加载图片
  2. 按住ctrl + 鼠标滚轮 实现以鼠标为中心点的位置缩放
  3. 按下DefaultSize按钮,恢复原始位置

2. 实现原理说明

  1. MyGraphicsView继承QGraphicsView,重写视口的鼠标滚轮事件,从而实现视口的缩放
  2. 需要设下如下两个视口大小转换以鼠标中心点为锚点
	setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
	setResizeAnchor(QGraphicsView::AnchorUnderMouse);
  1. 图片通过QGraphicsPixmapItem来保存图片,并在加载图片后,将该item缩放为适合视口大小比例(这里不是缩放视口,而是缩放图形项),并计算图片长宽相对视口多余空间的距离,通过该距离来移动图片位置来居中显示
  2. 移动图片只要通过使能图形项标志位位可移动即可
	QGraphicsRectItem *pRectItem = new QGraphicsRectItem(QRectF(0,0,20,20));
    pRectItem->setFlag(QGraphicsItem::ItemIsMovable,true);

3. 建工程

3.1 界面

Qt_绘图框架_QGraphicsview实现缩放移动图片_第1张图片

3.2 文件

Qt_绘图框架_QGraphicsview实现缩放移动图片_第2张图片

4. 源码

mygraphicsview.h头文件

#ifndef MYGRAPHICSVIEW_H
#define MYGRAPHICSVIEW_H
#include 
#include 

class MyGraphicsView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit MyGraphicsView(QWidget *parent = nullptr);
public:
    qreal GetScaledValue() const   //获取最新的放大倍数
    {
        return m_qrScaledNum;
    }
    void SetScaledDefaultValue()
    {
        this->m_qrScaledNum = 1;
    }
protected:
    void wheelEvent(QWheelEvent *ev);   //重写graphicsView的滚轮事件
    void mousePressEvent(QMouseEvent *ev);   //重写鼠标按下事件
private:
    qreal m_qrScaledNum;   //视口缩放倍数
};
#endif // MYGRAPHICSVIEW_H

mygraphicsview.cpp源文件

#include "mygraphicsview.h"
#include 
#include 
#include 
#define cout qDebug() << "["<< __FILE__ <<":" << __LINE__<<"]"

MyGraphicsView::MyGraphicsView(QWidget *parent) : QGraphicsView(parent)
{
    this->setMouseTracking(true);   //跟踪鼠标位置

    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    setResizeAnchor(QGraphicsView::AnchorUnderMouse);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);   //隐藏水平条
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);     //隐藏竖条

    m_qrScaledNum = 1; //初始化
}

//缩放
void MyGraphicsView::wheelEvent(QWheelEvent *ev)
{
    //cout << "MyGraphicsView::wheelEvent ";
    if(Qt::CTRL == ev->modifiers())   //键盘CTRL键
    {
        qreal qrTmp = 1.0;
        
        if(ev->delta() > 0)
        {
            qrTmp = 1.2;
            this->scale(qrTmp,qrTmp);
        }
        else
        {
            qrTmp = 1.0/1.2;
            this->scale(qrTmp,qrTmp);
        }
        m_qrScaledNum *= qrTmp;  //保存放大倍数
    }

}

void MyGraphicsView::mousePressEvent(QMouseEvent *ev)
{
    //视图坐标
    QPoint nViewPoint =  ev->pos();
    cout << "nViewPoint = " << nViewPoint;

    //场景坐标
    QPointF fScenePoint = this->mapToScene(nViewPoint);
    cout <<"fScenePoint = " << fScenePoint;

    //图形项坐标
    QGraphicsItem *pItem = this->scene()->itemAt(fScenePoint,QTransform());
    if(0 != pItem)
    {
         QPointF fItemPoint = pItem->mapFromScene(fScenePoint);   //获取图形项坐标
         cout <<"fItemPoint = " << fItemPoint;

         //cout <<" pItem->pos() = " << pItem->pos();
        //pItem->setPos(0,0);
    }
    //默认的鼠标按下事件
    QGraphicsView::mousePressEvent(ev);
}

mywidget.h头文件

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include 
#include 
#include 
#include "mygraphicsview.h"
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACE

//显示模式
enum DisplayModeEnum
{
    TOPLEFT = 0,            //左上角顶点
    XHorizontalMiddle,      //X水平轴居中
    YVerticalMiddle         //Y垂直轴居中
};

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    MyWidget(QWidget *parent = nullptr);
    ~MyWidget();

private slots:
    void on_pushBtnLoadImage_clicked();
    void on_pushButton_clicked();
    void ReleasedResourceSlot();

private:
    qreal GetDefaultRatio(const QPixmap &pix,DisplayModeEnum &displayMode);
    
private:
    Ui::MyWidget *ui;
    QGraphicsScene *m_pScene;   //场景
    MyGraphicsView *m_pView;    //视口

    qreal m_qrShrinkedRatio;        //视口缩放比例
    qreal m_qrDefaultShrinkedRatio; //图形项默认缩放比例
    int m_nViewWidth;
    int m_nViewHeight;
};
#endif // MYWIDGET_H

mywidget.cpp源文件

#include "mywidget.h"
#include "ui_mywidget.h"
#include 
#include 
#include 

#define cout qDebug() << "["<< __FILE__ <<":" << __LINE__<<"]"
#define VIEW_MAX_WIDTH 800      //视口最大宽度
#define VIEW_MAX_HEIGHT 600     //视口最大高度


MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);

    //创建视图
    this->m_pView = new MyGraphicsView(this);
    m_pView->resize(VIEW_MAX_WIDTH,VIEW_MAX_HEIGHT);
    this->m_nViewWidth = m_pView->width();
    this->m_nViewHeight = m_pView->height();

    //创建场景
    this->m_pScene = new QGraphicsScene(this);
    //设置场景大小和左上角点坐标
    this->m_pScene->setSceneRect(0,0,VIEW_MAX_WIDTH,VIEW_MAX_HEIGHT);

    //窗口关闭释放资源
    connect(this,&MyWidget::destroyed,this,&MyWidget::ReleasedResourceSlot);
}

MyWidget::~MyWidget()
{
    if(nullptr != m_pView)
    {
        delete m_pView;
        m_pView = nullptr;
    }

    if(nullptr != m_pScene)
    {
        delete m_pScene;
        m_pScene = nullptr;
    }

    delete ui;
}

void MyWidget::on_pushBtnLoadImage_clicked()
{
     //位置还原
     on_pushButton_clicked();
     //清空场景中的图形项
     m_pScene->clear();

     //加载图片
     QString strFilePath = QFileDialog::getOpenFileName(this,tr("Load a Image!"),"C:/Users/zhengfei6/Desktop/testImage",tr("Images(*.png *.jpg *.bmp)"));
     if(NULL == strFilePath)
     {
         cout << "FilePath is Null";
         return;
     }

     //加载图片
     QPixmap pix;
     pix.load(strFilePath);
     //获取缩放比例
     DisplayModeEnum displayMode = DisplayModeEnum::TOPLEFT;  //默认左上顶点显示
     this->m_qrDefaultShrinkedRatio = GetDefaultRatio(pix,displayMode);

     QGraphicsPixmapItem *pPixItem = new QGraphicsPixmapItem(pix);
     pPixItem->setScale(1/this->m_qrDefaultShrinkedRatio);
     pPixItem->setFlag(QGraphicsItem::ItemIsMovable,true);

     QGraphicsRectItem *pRectItem = new QGraphicsRectItem(QRectF(0,0,20,20));
     pRectItem->setFlag(QGraphicsItem::ItemIsMovable,true);

     //图形项显示模式
     switch (displayMode)
     {
     case TOPLEFT:   //左上顶点显示
         pPixItem->setPos(0,0);
         break;
     case XHorizontalMiddle:    //水平居中显示
     {
         qreal qrXPos = ((qreal)VIEW_MAX_WIDTH-(qreal)pix.width()/m_qrDefaultShrinkedRatio)/2;
         cout << "qrXPox = "<<qrXPos;
         pPixItem->setPos(qrXPos,0);
     }
         break;
     case YVerticalMiddle:      //垂直居中显示
     {
         qreal qrYPos = ((qreal)VIEW_MAX_HEIGHT-(qreal)pPixItem->pixmap().height()/m_qrDefaultShrinkedRatio)/2;
         cout << "qrYPos = " << qrYPos;
         pPixItem->setPos(0,qrYPos);
     }
         break;
     default:
         break;
     }

     //添加图形项
     m_pScene->addItem(pPixItem);
     m_pScene->addItem(pRectItem);

     //设置场景
     m_pView->setScene(m_pScene);
     m_pView->show();
}

qreal MyWidget::GetDefaultRatio(const QPixmap &pix,DisplayModeEnum &displayMode)
{
    qreal dResRatio = 0;
    qreal qrWidthRatio = (qreal)pix.width()/(qreal)VIEW_MAX_WIDTH;
    qreal qrHeightRatio = (qreal)pix.height()/(qreal)VIEW_MAX_HEIGHT;
    // cout << "qrWidthRatio = "<< qrWidthRatio;
    qreal nMaxTmp = qMax(qrWidthRatio,qrHeightRatio);  //取宽宽比和高高比的大者

    //  cout << "nMaxTmp = "<< nMaxTmp;
    if(qrWidthRatio == nMaxTmp)
    {
        dResRatio = qrWidthRatio;
        displayMode = DisplayModeEnum::YVerticalMiddle;
    }
    else
    {
        dResRatio = qrHeightRatio;
        displayMode = DisplayModeEnum::XHorizontalMiddle;
    }
    //cout << "dResRatio = "<< dResRatio;
    return dResRatio;
}

//视口还原为原来的缩放比例
void MyWidget::on_pushButton_clicked()
{
    //获取view的缩放倍数
    qreal qrTmp = m_pView->GetScaledValue();
    m_pView->scale(1/qrTmp,1/qrTmp);

    //还原后,更新下view中的放大倍数为1
    m_pView->SetScaledDefaultValue();

    //图形项还原位置
    QList<QGraphicsItem*> pListItems = m_pScene->items();
    foreach(QGraphicsItem* pItem , pListItems)
    {
        pItem->setPos(0,0);
    }
}
void MyWidget::ReleasedResourceSlot()
{
#if 1
    if(nullptr != m_pView)
    {
        delete m_pView;
        m_pView = nullptr;
    }

    if(nullptr != m_pScene)
    {
        delete m_pScene;
        m_pScene = nullptr;
    }
#endif
    cout <<"close the widget";
}

main.cpp源文件

#include "mywidget.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWidget w;
    w.show();
    return a.exec();
}

5. 参考文献

《QT QGraphicsView 在鼠标点击处进行放大缩小》

你可能感兴趣的:(QT,qt,c++,开发语言)