QT笔记(5)——Qt图形视图框架实例

Qt的图形视图框架很强大,同时也很复杂,这里做了一个简单的练习,对图片加载,并移动放缩,的一个图片查看器;需要继承图元类;

下面直接贴源码了:

新建一个widget应用,然后添加如下:

pixitem.h:

#ifndef PIXITEM_H
#define PIXITEM_H
#include <QGraphicsItem>
#include <QPixmap>
#include <QPainter>
#include <QRectF>
#include <QMouseEvent>
#include <QPointF>
#include <QDragEnterEvent>
#include <QGraphicsSceneWheelEvent>
#include <QGraphicsObject>

//枚举方便传递
enum Enum_ZoomState{
    NO_STATE,
    RESET,
    ZOOM_IN,
    ZOOM_OUT
};

//放大缩小值范围
enum Enum_ZoomTimes{
    ZOOM_IN_TIMES = 50,
    ZOOM_OUT_TIMES = -50,
};

//直接继承QGraphicsObject,这样有信号和槽QGraphicsItem没有信号和槽功能
class PixItem :public QGraphicsObject//public QGraphicsItem
//继承自图元类,实现自定义的图元,qt预置的有直线,椭圆,文本图元,矩形图元等
{
public:
    PixItem(QPixmap *pixmap);     //构造函数初始化了变量pix
    QRectF boundingRect() const;
    //实现自己的boundingRect 图元边界方法,继承QGraphicsItem必须要初始化话的虚函数
    //完成以图元坐标系为基础增加两个像素点的冗余的工作

    void paint(QPainter *painter,
               const QStyleOptionGraphicsItem *option,
               QWidget *widget); //重画图形函数

    void wheelEvent(QGraphicsSceneWheelEvent *event);//滚轮放大缩小
    void setZoomState(const int &zoomState);//设置图像恢复原始
    void mousePressEvent(QGraphicsSceneMouseEvent *event);//用于移动图像
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);//用于移动图像
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);//用于移动图像
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);//双击恢复图像
    int getScaleValue() const;//获取当前图元放缩值
    void setScaleValue(const int &);//返回放放缩值
    void setValue(const QPointF &);//返回窗口大小值
    int widx;
    int widy;

signals:


private:
    qreal m_scaleValue;   //缩放值
    QPixmap pix;    //作为图元显示的图片
    int m_zoomState;
    bool m_isMove;
    QPointF m_startPos;
};

#endif // PIXITEM_H

pixitem.cpp:

#include "pixitem.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QPointF>
#include <QGraphicsSceneDragDropEvent>
#include <QDrag>
#include <math.h>
#include <QMessageBox>
#include <QGraphicsObject>
#include "widget.h"

//构造函数初始化了变量pix
PixItem::PixItem(QPixmap *pixmap)
{
    pix = *pixmap;
    setAcceptDrops(true); //设置可拖拽
    m_scaleValue = 0;//放缩值初始化
    m_isMove = false;//不可移动
    widx=0;
    widy=0;
}

//实现自己的图元边界函数
QRectF PixItem::boundingRect() const
{
    return QRectF(-pix.width()/2, -pix.height()/2,
                  pix.width(), pix.height());//需要对应图元,不然出现残影
}

//只需QPainter的drawPixmap()函数将图元图片绘出即可
void PixItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
                    QWidget *)
{
    painter->drawPixmap(-pix.width()/2, -pix.height()/2, pix);//需要对应边界函数
}

//鼠标点击事件
void PixItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    m_startPos = event->pos();
    m_isMove = true;//图元是否可以移动
//下面测试代码
//    QPointF m_center;
//    m_center=mapToScene(0,0);//坐标映射,图元坐标映射到窗口
//    double a =m_center.x();
//    QString str=QString::number(a,10,0); // 这是你的变量
//    QMessageBox mesg;
//    mesg.about(NULL,QString::fromLocal8Bit("图片大小") , str);
}

void PixItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{

//    if(sceneBoundingRect().width()<widx&&sceneBoundingRect().height()<widy)
//    {
//        m_isMove = false;//小于窗口时候不可以移动
//    }
//    if(sceneBoundingRect().width()>widx-20||sceneBoundingRect().height()>widy-20)
//    {
//        QPointF m_center;
//        m_center=mapToScene(0,0);//图元中心坐标
//        QPointF points = event->pos()- m_startPos;
//        int wx,wy;
//        wx=sceneBoundingRect().width()-widx;
//        wy=sceneBoundingRect().height()-widy;
//        if(pow(1.1,wx/2)>pow(1.1,m_center.x())||pow(1.1,wy/2)>pow(1.1,m_center.y()))
//        {
//            moveBy(points.x(),points.y());
//        }
//        m_isMove = false;
//    }


    if(m_isMove)
    {
        QPointF point =mapToScene(event->pos())-mapToScene(m_startPos);
        moveBy(point.x(),point.y());
        // 鼠标点击后并移动则图元相应移动,进行了图元坐标映射,映射到窗口中
    }  
}

void PixItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
{
    m_isMove = false;
}


//双击复位
void PixItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{

    //    int ag=sceneBoundingRect().width();
    //    int bg=sceneBoundingRect().height();
    //    QString strag=QString::number(ag,10,0); // 这是你的变量
    //    QString strbg=QString::number(bg,10,0); // 这是你的变量
    //    QString  strg = QString::fromLocal8Bit("图片宽度:%1,图片高度:%2").arg(strag).arg(strbg);
    //    QMessageBox mesgg;
    //    mesgg.about(NULL,QString::fromLocal8Bit("图片信息") ,strg);

    setPos(0,0);
    m_scaleValue = 0;
    setScale(1);
    setTransformOriginPoint(0, 0);

    //做了坐标映射,将图片回复到窗口中心
    QPointF m_center;
    m_center=mapToScene(0,0);
    if(m_center.x()!=0||m_center.y()!=0)
    {
        if(m_center.x()>0&&m_center.y()>0) moveBy(-m_center.x(), -m_center.y());
        if(m_center.x()<0&&m_center.y()<0) moveBy(m_center.x(), m_center.y());
        if(m_center.x()>0&&m_center.y()<0) moveBy(-m_center.x(), m_center.y());
        if(m_center.x()<0&&m_center.y()>0) moveBy(m_center.x(), -m_center.y());
    }

}

//使用滚轮整体缩放
void PixItem::wheelEvent(QGraphicsSceneWheelEvent *event)
{
    setZoomState(NO_STATE);
    int scaleValue = m_scaleValue;
    if(event->delta() > 0)  //delta()为正,滚轮向上滚
    {
        scaleValue++;       
    }
    else
    {
        scaleValue--;
    }

    /测试代码以下
    //    if(scaleValue<=0)//小于窗口时候自动回中央
    //    {
    //        setPos(0,0);
    //        QPointF m_center;
    //        m_center=mapToScene(0,0);
    //        if(m_center.x()!=0||m_center.y()!=0)
    //        {
    //            if(m_center.x()>0&&m_center.y()>0) moveBy(-m_center.x(), -m_center.y());
    //            if(m_center.x()<0&&m_center.y()<0) moveBy(m_center.x(), m_center.y());
    //            if(m_center.x()>0&&m_center.y()<0) moveBy(-m_center.x(), m_center.y());
    //            if(m_center.x()<0&&m_center.y()>0) moveBy(m_center.x(), -m_center.y());
    //        }
    //    }
    //*************以上

    if (scaleValue > ZOOM_IN_TIMES || scaleValue < ZOOM_OUT_TIMES)
        return;

    m_scaleValue = scaleValue;
    qreal s;
    if(m_scaleValue > 0)
    {
        s = pow(1.1, m_scaleValue);        //放大 计算x的y方次 参数都是double类型
    }
    else
    {
        s = pow(1 / 1.1, -m_scaleValue);      //缩小
    }
    setScale(s);//setScale设置比例放缩,内置的处理图像放缩的方法
    if(sceneBoundingRect().width()>=widx||sceneBoundingRect().height()>=widy)
    {
        //  m_isMove = false;
        setTransformOriginPoint(event->pos());//基于图元坐标内鼠标指针变换中心
    }

    //    QPointF m_center;
    //    m_center=mapToScene(event->pos().x(),event->pos().y());//转换至窗口后指针变换中心
    //    setTransformOriginPoint(m_center);
  }

//从widget获取的缩放值,用于同步滚轮和按键
void PixItem::setScaleValue(const int &scaleValue)
{
    if (scaleValue > ZOOM_IN_TIMES || scaleValue < ZOOM_OUT_TIMES)
        return;

    m_scaleValue = scaleValue;

*******测试代码以下
//    if(scaleValue<=0)//小于窗口时候自动回中央
//    {
//        setPos(0,0);
//        QPointF m_center;
//        m_center=mapToScene(0,0);
//        if(m_center.x()!=0||m_center.y()!=0)
//        {
//            if(m_center.x()>0&&m_center.y()>0) moveBy(-m_center.x(), -m_center.y());
//            if(m_center.x()<0&&m_center.y()<0) moveBy(m_center.x(), m_center.y());
//            if(m_center.x()>0&&m_center.y()<0) moveBy(-m_center.x(), m_center.y());
//            if(m_center.x()<0&&m_center.y()>0) moveBy(m_center.x(), -m_center.y());
//        }
//    }

    qreal s;
    if(m_scaleValue > 0)
    {
        s = pow(1.1, m_scaleValue);     //放大 计算x的y方次 参数都是double类型,去除正负数
    }
    else
    {
        s = pow(1 / 1.1, -m_scaleValue); //缩小
    }
    setScale(s);
}

//复原图像
void PixItem::setZoomState(const int &zoomState)
{
    m_zoomState = zoomState;
    if (m_zoomState == RESET)
    {
        m_scaleValue = 0;
        setScale(1);
        setTransformOriginPoint(0, 0);
    }
}

//获取放缩值
int PixItem::getScaleValue() const
{
    return m_scaleValue;
}

//返回窗口值
void  PixItem::setValue(const QPointF &pointxy)
{
    QPointF p;
    p=pointxy;
    widx=p.x();
    widy=p.y();
}

在widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include"pixitem.h"
#include <QGraphicsView>    //视图类
#include <QGraphicsScene>   //场景类
#include <QGraphicsItem>    //图元类
#include <math.h>
#include <QWheelEvent>

namespace Ui {
class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
protected:
    void mousePressEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
    void mouseDoubleClickEvent(QMouseEvent *e);
    void wheelEvent(QWheelEvent *event);
private slots:
    void my_change();//用于接收放缩值变化
    void on_spinBox_valueChanged(int arg1);//系统自动生成槽函数,检测对应控件值
    void resetzoom();//恢复图像
    void on_B_OpenFile_clicked();//打开文件按钮
    void on_B_Boost_clicked();//放大按钮
    void on_B_Reduce_clicked();//缩小按钮
private:
    Ui::Widget *ui;
    QPoint last; //点
    PixItem *pixItem;       //自定义的图元类
    QGraphicsScene *m_graphicsScene;  //场景
    QGraphicsView *m_graphicsView;
    int wt;
    int ht;
};
#endif // WIDGET_H

在widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QFileDialog>
#include <QPolygon>
#include <QMouseEvent>
#include <QMessageBox>
#include <QGraphicsObject>
#include "pixitem.h"

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

    //    this->setWindowFlags(Qt::FramelessWindowHint |
    //                         Qt::WindowSystemMenuHint |
    //                         Qt::WindowMinimizeButtonHint);//隐藏窗口标题栏和外框
    //this->setAttribute(Qt::WA_TranslucentBackground);//设置背景透明

    pixItem = new PixItem(new QPixmap("D:/1.jpg"));
    //将该图元对象添加到场景中,并设置此图元在场景中的位置为中心(0,0)

    m_graphicsScene = new QGraphicsScene;  //new 一个新的场景对象
    ui->graphicsView->setSceneRect(-10/2,-10/2,10,10);
    //设置开启滚动条范围,不然即使隐藏了滚动条后还是有滚动效果
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隐藏横向滚动条
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隐藏纵向滚动条
    ui->graphicsView->setScene(m_graphicsScene);//添加场景
    m_graphicsScene->addItem(pixItem);//将图元添加到场景中
    pixItem->setPos(0,0);//中心位置

    QObject::connect(pixItem,SIGNAL(scaleChanged()),
                     this,SLOT(my_change()));//自定义信号和槽获取scale值反馈出来

    QObject::connect(ui->spinBox,SIGNAL(valueChanged(int)),
                     ui->horizontalSlider,SLOT(setValue(int)));//spinBox值与滑条对应

    QObject::connect(ui->horizontalSlider,SIGNAL(valueChanged(int)),
                     ui->spinBox,SLOT(setValue(int)));//滑条与spinBox值对应

    ui->horizontalSlider->setValue(0);//滑条初始值,范围值在窗口设计器里设置了

    QObject::connect(ui->B_ReZoom,SIGNAL(clicked(bool)),
                     this,SLOT(resetzoom()));//复位按钮

}

Widget::~Widget()
{
    delete ui;
}

//下面代码可以不添加//
******接下*******/
void Widget::mousePressEvent(QMouseEvent *e)
{ 
    last = e->globalPos(); //鼠标点击点位
    wt=width();//获取窗口大小
    ht=height();//同上
    //下面注释的代码为了检测值用
    //    int a=wt;
    //    int b=ht;
    //    QString stra=QString::number(a,10,0); // 这是你的变量
    //    QString strb=QString::number(b,10,0); // 这是你的变量
    //    QString  str = QString::fromLocal8Bit("窗口宽度:%1,窗口高度:%2").arg(stra).arg(strb);
    //    QMessageBox mesg;
    //    mesg.about(NULL,QString::fromLocal8Bit("窗口信息") ,str);
     QPointF p(wt,ht);//定义为点
     pixItem->setValue(p);//传到pixitem类
}

void Widget::mouseMoveEvent(QMouseEvent *e)
{
   //下面代码是移动窗口用,在无标题和窗口外框情况下用
    int dx = e->globalX() - last.x();
    int dy = e->globalY() - last.y();
    last = e->globalPos();
    move(x()+dx, y()+dy);
}

void Widget::mouseReleaseEvent(QMouseEvent *e)
{
    //下面代码是移动窗口用,在无标题和窗口外框情况下用
    int dx = e->globalX() - last.x();
    int dy = e->globalY() - last.y();
    move(x()+dx, y()+dy);
}

///*********接上*************///

//双击恢复图像
void Widget::mouseDoubleClickEvent(QMouseEvent *e)
{


    ***********图片复原代码**************/
    pixItem->setPos(0,0);
    pixItem->setScaleValue(1);
    pixItem->setZoomState(NO_STATE);
    ui->horizontalSlider->setValue(0);

    //**********下面注释为测试用***********
    //    int ag=pixItem->sceneBoundingRect().width();//图元边缘
    //    int bg=pixItem->sceneBoundingRect().height();
    //    QString strag=QString::number(ag,10,0); // 这是你的变量
    //    QString strbg=QString::number(bg,10,0); // 这是你的变量
    //    QString  strg = QString::fromLocal8Bit("图片宽度:%1,图片高度:%2").arg(strag).arg(strbg);
    //    QMessageBox mesgg;
    //    mesgg.about(NULL,QString::fromLocal8Bit("图片信息") ,strg);

    //    int ap=pixItem->boundingRect().width();//图片边缘
    //    int bp=pixItem->boundingRect().height();
    //    QString strap=QString::number(ap,10,0); // 这是你的变量
    //    QString strbp=QString::number(bp,10,0); // 这是你的变量
    //    QString  strp = QString::fromLocal8Bit("图片宽度:%1,图片高度:%2").arg(strap).arg(strbp);
    //    QMessageBox mesgp;
    //    mesgp.about(NULL,QString::fromLocal8Bit("图片信息") ,strp);


    //    wt=width();//窗口大小
    //    ht=height();
    //    int a=wt;
    //    int b=ht;
    //    QString stra=QString::number(a,10,0); // 这是你的变量
    //    QString strb=QString::number(b,10,0); // 这是你的变量
    //    QString  str = QString::fromLocal8Bit("窗口宽度:%1,窗口高度:%2").arg(stra).arg(strb);
    //    QMessageBox mesg;
    //    mesg.about(NULL,QString::fromLocal8Bit("窗口信息") ,str);
}

//滚轮滚动图片缩小放大
void Widget::wheelEvent(QWheelEvent *event)
{
    pixItem->setZoomState(NO_STATE);//枚举,对应pixitem类中
    int scaleValue=pixItem->getScaleValue();//获取ScaleValue值(放大缩小值)
    if(event->delta() > 0)  //delta()为正,滚轮向上滚
    {
        scaleValue++;
        ui->horizontalSlider->setValue(scaleValue);//同步滑条
    }
    else
    {
        scaleValue--;
        ui->horizontalSlider->setValue(scaleValue);//同步滑条
    }
    pixItem->setScaleValue(scaleValue);//重新设置ScaleValue值(放大缩小值)
}

//自定义槽函数接受pixitem类放大缩小值
void Widget::my_change()
{
    ui->horizontalSlider->setValue(pixItem->getScaleValue());//获取图元的放大缩小值
}


//系统内置spinBox槽函数,在设计窗口选中控件,右键添加valueChanged,当值改变时候自动启动
void Widget::on_spinBox_valueChanged(int arg1)
{
    pixItem->setZoomState(NO_STATE);//对应图元类中放大缩小原始枚举项
    pixItem->setScaleValue(arg1); //获取控件改变的值
    wt=width();
    ht=height();
    QPointF p(wt,ht);
    pixItem->setValue(p);//将窗口值传给pixitem类
    //测试代码
    //    int a=wt;
    //    int b=ht;
    //    QString stra=QString::number(a,10,0); // 这是你的变量
    //    QString strb=QString::number(b,10,0); // 这是你的变量
    //    QString  str = QString::fromLocal8Bit("窗口宽度:%1,窗口高度:%2").arg(stra).arg(strb);
    //    QMessageBox mesg;
    //    mesg.about(NULL,QString::fromLocal8Bit("窗口信息") ,str);
}

//复原函数
void Widget::resetzoom()
{
    pixItem->setPos(0,0);//复原位置
    pixItem->setScaleValue(0);//复原比例
    pixItem->setZoomState(NO_STATE);
    ui->horizontalSlider->setValue(0);//滑条值
}


//打开文件按钮
void Widget::on_B_OpenFile_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(
                this, tr("open image file"),
                "./", tr("Image files(*.bmp *.jpg *.pbm *.pgm *.png *.ppm *.xbm *.xpm);;All files (*.*)"));
    if(fileName.isEmpty())
    {
       // QMessageBox::warning(this, tr("警告"), tr("打开图片失败,请重新选择图片!"),NULL, QMessageBox::Yes);
        return;
    }
    m_graphicsScene->removeItem(pixItem);   //将上一个图元从场景中移除,重新添加新的图元
    pixItem = new PixItem(new QPixmap(fileName));
    ui->graphicsView->setScene(m_graphicsScene);//添加到场景中
    m_graphicsScene->addItem(pixItem);
    pixItem->setPos(0,0);
    QObject::connect(pixItem,SIGNAL(scaleChanged()),this,SLOT(my_change()));//刷新一下链接
}

//放大按钮
void Widget::on_B_Boost_clicked()
{    
    int a=ui->spinBox->value()+1;
    ui->horizontalSlider->setValue(a);
}

//缩小按钮
void Widget::on_B_Reduce_clicked()
{
    int a=ui->spinBox->value()-1;
    ui->horizontalSlider->setValue(a);
}
运行效果如下:


  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值