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

来源:互联网 发布:黑产数据交易平台 编辑:程序博客网 时间:2024/06/04 19:43

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"//构造函数初始化了变量pixPixItem::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_OBJECTpublic:    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);}
运行效果如下:


原创粉丝点击