Qt实战案例(20)——利用QPixmap实现图片缩放、平移等操作

目录

    • 一、项目介绍
    • 二、项目基本配置
    • 三、UI界面设计
    • 四、主程序实现
      • 4.1 widget.h头文件
      • 4.2 widget.cpp源文件
    • 五、效果演示

一、项目介绍

利用QPixmap实现图片缩放、平移等操作。

二、项目基本配置

新建一个Qt案例,项目名称为“PhotoTest”,基类选择“QWidget”,取消创建UI界面复选框的选中状态,完成项目创建。

三、UI界面设计

无UI界面

四、主程序实现

4.1 widget.h头文件

声明一个类型:

    enum  Type {
        None          = 0,
        Amplification ,
        Shrink,
        Lift,
        Right,
        Up,
        Down,
        Move,
        Reset
    };

声明若干个私有变量和私有函数:

private :
    QPixmap  pix;
    QPixmap  crtPix;
    int action;          //动作(放大,缩小,移动...)
    int pixW;            //图片宽
    int pixH;            //图片高
    QWidget Paint;         //绘画区域
    QImage image;        //打开的图片
    float ratio;              //缩放比例
    QPoint offset;           //一次的图片偏移值
    QPoint Alloffset;          //总偏移
    QLabel label;

    QPushButton  BiBtn;  //放大
    QPushButton  LeBtn;  //缩小
    QPushButton  LBtn;   //左移
    QPushButton  RBtn;   //右移
    QPushButton  UBtn;   //上移
    QPushButton  DBtn;   //下移
    QPushButton  ResetBtn;
    QPushButton  OpenBtn;  //打开



    void AddComboItem(QComboBox* cmbo);
    bool event(QEvent * event);
    void wheelEvent(QWheelEvent* e);     //鼠标滑轮事件

声明按钮点击槽函数:

private slots:
    void    onUpClicked();
    void    onDownClicked();
    void    onResetClicked();
    void    OnLeftClicked();
    void    OnRightClicked();
    void    onLittleClicked();
    void    onBigClicked();
    void    onOpenClicked();
    void paintEvent(QPaintEvent *event);

4.2 widget.cpp源文件

主函数内首先定义八个按钮和一个label,然后新建栅格布局,将按钮、label和QWidget进行栅格布局,并设置相应尺寸,最后将八个按钮的点击事件与相应槽函数连接,代码如下:

Widget::Widget(QWidget *parent)
    : QWidget(parent),
    BiBtn("放大",this),
    LeBtn("缩小",this),
    LBtn("向左",this),
    RBtn("向右",this),
    UBtn("向上",this),
    DBtn("向下",this),
    ResetBtn("还原",this),
    OpenBtn("打开文件",this),
    Alloffset(0,0),
    label("100%",this)
{
    ratio= 1.0;             //初始化图片缩放比例
    action = Widget::None;

    //新建栅格布局
    QGridLayout *layout=new QGridLayout;

    //设置按钮尺寸
    BiBtn.setMaximumSize(100,40);
    LeBtn.setMaximumSize(100,40);
    LBtn.setMaximumSize(100,40);
    RBtn.setMaximumSize(100,40);
    UBtn.setMaximumSize(100,40);
    DBtn.setMaximumSize(100,40);
    ResetBtn.setMaximumSize(100,40);
    OpenBtn.setMaximumSize(100,40);
    Paint.setMinimumSize(700,600);
    label.setMaximumSize(50,40);

    //设置按钮尺寸
    BiBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    LeBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    LBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    RBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    UBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    DBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    ResetBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    OpenBtn.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    //向布局管理器添加组件
    layout->addWidget(&Paint,0,0,-1,1);
    layout->addWidget(&BiBtn,0,1,1,1);
    layout->addWidget(&LeBtn,1,1,1,1);
    layout->addWidget(&LBtn,2,1,1,1);
    layout->addWidget(&RBtn,3,1,1,1);
    layout->addWidget(&UBtn,4,1,1,1);
    layout->addWidget(&DBtn,5,1,1,1);
    layout->addWidget(&ResetBtn,6,1,1,1);
    layout->addWidget(&OpenBtn,7,1,1,1);
    layout->addWidget(&label,8,1,1,1);

    setLayout(layout);           //为部件设置布局管理器

//     BiBtn.setGeometry(822,10,60,25);
     connect(&BiBtn,SIGNAL(clicked()),this,SLOT(onBigClicked()));

//     LeBtn.setGeometry(822,40,60,25);
     connect(&LeBtn,SIGNAL(clicked()),this,SLOT(onLittleClicked()));

//     LBtn.setGeometry(822,70,60,25);
     connect(&LBtn,SIGNAL(clicked()),this,SLOT(OnLeftClicked()));
//     RBtn.setGeometry(822,100,60,25);
     connect(&RBtn,SIGNAL(clicked()),this,SLOT(OnRightClicked()));
//     UBtn.setGeometry(822,130,60,25);
     connect(&UBtn,SIGNAL(clicked()),this,SLOT(onUpClicked()));
//     DBtn.setGeometry(822,160,60,25);
     connect(&DBtn,SIGNAL(clicked()),this,SLOT(onDownClicked()));


//     ResetBtn.setGeometry(822,190,60,25);
     connect(&ResetBtn,SIGNAL(clicked()),this,SLOT(onResetClicked()));

//     OpenBtn.setGeometry(822,220,60,25);
     connect(&OpenBtn,SIGNAL(clicked()),this,SLOT(onOpenClicked()));

//     label.move(840,260);
     resize(800,600);    //调整窗口大小

     this->setWindowTitle("图片浏览器(请打开文件)");//设置窗口标题
 }

定义鼠标按下拖动事件,并修改鼠标样式:

//鼠标按下拖动事件
 bool Widget::event(QEvent * event)
 {
     static bool press=false;
     static QPoint PreDot;
    //检测鼠标按下
     if(event->type() == QEvent::MouseButtonPress)
     {
            QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);

            //判断鼠标是否是左键按下,且鼠标位置是否在绘画区域
            //if(mouse->button()==Qt::LeftButton &&Paint.contains(mouse->pos()))
                if(mouse->button()==Qt::LeftButton)
            {
                press=true;
                QApplication::setOverrideCursor(Qt::OpenHandCursor); //设置鼠标样式

                PreDot = mouse->pos();
            }

     }
     //检测鼠标松开
     else if(event->type() == QEvent::MouseButtonRelease)
     {
         QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);

         //判断鼠标是否是左键释放,且之前是在绘画区域
         if(mouse->button()==Qt::LeftButton && press )
         {
             QApplication::setOverrideCursor(Qt::ArrowCursor); //改回鼠标样式
             press=false;
         }
     }
    //检测鼠标移动
      if(event->type() == QEvent::MouseMove)              //移动图片
      {
           if(press)
          {
             QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);

             offset.setX(mouse->x() - PreDot.x());
             offset.setY(mouse->y() - PreDot.y());
             PreDot = mouse->pos();
             action = Widget::Move;

             this->update();
          }
      }
     return QWidget::event(event);
 }

定义鼠标滑轮事件:

//鼠标滑轮事件
 void Widget::wheelEvent(QWheelEvent* event)
 {
  if (event->angleDelta().y()>0) {      //上滑,缩小

     action=Widget::Shrink;
     this->update();
  } else {                    //下滑,放大
      action=Widget::Amplification;
      this->update();
  }

  event->accept();
 }

重写绘图事件,设置缩放比例为5%:

//重写绘图事件
 void Widget::paintEvent(QPaintEvent *event)
 {
     QPainter painter(this);
     //设置渲染方式
     painter.setRenderHints(QPainter::SmoothPixmapTransform|QPainter::Antialiasing|QPainter::TextAntialiasing);
     painter.drawRect(Paint.x()-1,Paint.y()-1,Paint.width()+1,Paint.height()+1); //画框

     if(image.isNull())
     {
      return;
     }

     int NowW = ratio *pixW;
     int NowH = ratio *pixH;

     if(action==Widget::Shrink)   //缩小
     {
           ratio-=0.05*ratio;
         if(ratio<0.018)
           ratio = 0.01;

         /*显示比例*/
         QString str;
         str=str.setNum(ratio*100)+"%";
         //str.sprintf("%.0f%",ratio*100);
         label.setText(str) ;
         qDebug()<<"缩小:"<<ratio;
     }
     else  if(action==Widget::Amplification) //放大
     {

          ratio+=0.05*ratio;
        if(ratio>4.5)
          ratio = 5.000;

         /*显示比例*/
         QString str;
         str=str.setNum(ratio*100)+"%";;
         //str.sprintf("%.0f%",ratio*100);
         label.setText(str);
         qDebug()<<"放大:"<<ratio;
     }


     if(action==Widget::Amplification || action==Widget::Shrink || action==Widget::Reset)      //更新图片
     {
       NowW = ratio *pixW;
       NowH = ratio *pixH;


       crtPix= pix.scaled(NowW, NowH,Qt::KeepAspectRatio,Qt::SmoothTransformation); //重新装载

       action=Widget::None;
     }

     if(action==Widget::Move)                    //移动
     {
         int offsetx=Alloffset.x()+offset.x();
         Alloffset.setX(offsetx);

         int offsety=Alloffset.y()+offset.y();
         Alloffset.setY(offsety);
         action=Widget::None;
     }

     if(abs(Alloffset.x())>=(Paint.width()/2 + NowW/2 -10))    //限制X偏移值
     {
         if(Alloffset.x()>0)
             Alloffset.setX(Paint.width()/2 + NowW/2 -10);
         else
          Alloffset.setX(-Paint.width()/2 + -NowW/2 +10);

     }
     if(abs(Alloffset.y())>=(Paint.height()/2 + NowH/2 -10))    //限制Y偏移值
     {
         if(Alloffset.y()>0)
             Alloffset.setY(Paint.height()/2 + NowH/2 -10);
         else
          Alloffset.setY(-Paint.height()/2 + -NowH/2 +10);

     }

     int x = Paint.width()/2 + Alloffset.x() -NowW/2;
     if(x<0)
         x=0;

     int y = Paint.height()/2 + Alloffset.y() -NowH/2;
     if(y<0)
         y=0;

     int  sx = NowW/2 - Paint.width()/2 - Alloffset.x();
     if(sx<0)
         sx=0;

     int  sy = NowH/2 - Paint.height()/2 - Alloffset.y();
     if(sy<0)
         sy=0;

     int w =(NowW - sx)>Paint.width()? Paint.width() : (NowW - sx);
     if(w>(Paint.width()-x))
         w = Paint.width()-x;

     int h =(NowH - sy)>Paint.height()? Paint.height() : (NowH - sy);
     if(h>(Paint.height()-y))
         h = Paint.height()-y;



     painter.drawTiledPixmap(x+Paint.x(),y+Paint.y(),w,h,crtPix,sx,sy);  //绘画图形

 }

缩小按钮响应槽函数:

//缩小按钮响应槽函数
 void  Widget::onLittleClicked()
 {
   action=Widget::Shrink;
   this->update();
 }

放大按钮响应槽函数:

 void  Widget::onBigClicked()
 {

   action=Widget::Amplification;
   this->update();
 }

打开按钮响应槽函数:

//打开按钮响应槽函数
 void Widget::onOpenClicked()
 {


     QString str = QFileDialog::getOpenFileName(this,
                                  "open",
                                  "D:",
                                  "img (*.png *.jpg)");

     if(!str.isNull())
     {


        image.load(str);
        pix = pix.fromImage(image);

        crtPix = pix;
        pixW = image.width();            //图片宽
        pixH = image.height();           //图片高
        qDebug()<<str<<pixW<<pixH;
        this->setWindowTitle("图片浏览器("+str+")");
        onResetClicked();
     }
 }

上移按钮响应槽函数:

 //上移按钮响应函数
 void Widget::onUpClicked()
 {
   action=Widget::Move;
   offset.setX(0);
   offset.setY(-20);

   this->update();
 }

下移按钮响应槽函数:

//下移按钮响应槽函数
 void Widget::onDownClicked()
 {
   action=Widget::Move;
   offset.setX(0);
   offset.setY(20);
   this->update();
 }

重置按钮响应槽函数:

//重置按钮响应槽函数
 void Widget::onResetClicked()
 {
   action=Widget::Reset;
   Alloffset.setX(0);
   Alloffset.setY(0);
   ratio = 1.000;
   label.setText("100%");
   this->update();
 }

左移按钮响应槽函数:

 //左移按钮响应槽函数
 void Widget::OnLeftClicked()
 {
   action=Widget::Move;
   offset.setX(-20);
   offset.setY(0);

   this->update();
 }

右移按钮响应槽函数:

 //右移按钮响应槽函数
 void Widget::OnRightClicked()
 {
   action=Widget::Move;
   offset.setX(20) ;
   offset.setY(0) ;

   this->update();
 }

五、效果演示

如果没有看懂的话,完整代码可以参考:
https://download.csdn.net/download/didi_ya/75511194


ok,以上便是本文的全部内容了,如果对你有所帮助,记得点个赞哟~

你可能感兴趣的