Qt純代碼實現添加背景圖片的自定義按鈕

Qt的控件中提供了按鈕類,我們在調用一個按鈕控件的時候,一般通過使用按鈕類本身的接口函數已經夠用了。
在添加按鈕的圖標或者背景的時候可以通過調用如下所示的接口函數。

void setIcon(const QIcon &icon)

雖然Qt已經提供了非常完美的接口函數,但是總有一些情況是它無法滿足的:比如在使用一些圖片進行縮放的時候,會因爲圖片放大後失真,導致貼上去的圖不精確,如果這個圖片是符合九宮格縮放後不改變原形態的這種情況,我們可以進行重新定製一個專屬按鈕。

按鈕效果:
在這裏插入圖片描述
在實現這一效果的關鍵是對 圖片縮放的處理。

關鍵代碼:

/*
**  功能             : 九宮格圖處理
**  picName          : 圖片名字
**  iHorzSplit       : 四個角上格子的寬度
**  iVertSplit       : 四個角上格子的高度
**  DstWidth         : 整個圖片縮放的寬度
**  DstWidth         : 整個圖片縮放的高度
**  返回值           : 處理完成的圖片
*/

QPixmap* Test1Button::ninePatch(QString picName,double iHorzSplit, double iVertSplit, double DstWidth, double DstHeight)
 {
     QPixmap* pix = new QPixmap(picName);
     int pixWidth = pix->width();
     int pixHeight = pix->height();
     QPixmap pix_1 = pix->copy(0, 0, iHorzSplit, iVertSplit);//0 0 22 14
     QPixmap pix_2 = pix->copy(iHorzSplit, 0, pixWidth-iHorzSplit*2, iVertSplit);//22 0 22 14
     QPixmap pix_3 = pix->copy(pixWidth-iHorzSplit, 0, iHorzSplit, iVertSplit);// 44 0 22 14

     QPixmap pix_4 = pix->copy(0, iVertSplit, iHorzSplit, pixHeight-iVertSplit*2);//0 14 22 16
     QPixmap pix_5 = pix->copy(iHorzSplit, iVertSplit, pixWidth-iHorzSplit*2, pixHeight-iVertSplit*2);//22 14  22 16
     QPixmap pix_6 = pix->copy(pixWidth-iHorzSplit, iVertSplit, iHorzSplit, pixHeight-iVertSplit*2);//44  14  22 16

     QPixmap pix_7 = pix->copy(0, pixHeight-iVertSplit, iHorzSplit, iVertSplit);//0 30 22 14
     QPixmap pix_8 = pix->copy(iHorzSplit, pixHeight-iVertSplit, pixWidth-iHorzSplit*2, iVertSplit);//22 30 22 14
     QPixmap pix_9 = pix->copy(pixWidth-iHorzSplit, pixHeight-iVertSplit, iHorzSplit, iVertSplit);//44 30 22 14
     pix_2 = pix_2.scaled(DstWidth-iHorzSplit*2+6,iVertSplit, Qt::IgnoreAspectRatio);//保持高度拉寬
     pix_4 = pix_4.scaled(iHorzSplit, DstHeight-iVertSplit*2+4, Qt::IgnoreAspectRatio);//保持寬度拉高
     pix_5 = pix_5.scaled(DstWidth-iHorzSplit*2+6,DstHeight-iVertSplit*2+4, Qt::IgnoreAspectRatio);//寬高都縮放
     pix_6 = pix_6.scaled(iHorzSplit, DstHeight-iVertSplit*2+4, Qt::IgnoreAspectRatio);//保持寬度拉高
     pix_8 = pix_8.scaled(DstWidth-iHorzSplit*2+6, iVertSplit);//保持高度拉寬


     QPixmap* resultImg =new QPixmap(DstWidth, DstHeight);
     QPainter* painter = new QPainter(resultImg);
     if (!resultImg->isNull()) {
         painter->drawPixmap(-3,0,pix_1);
         painter->drawPixmap(iHorzSplit-3, 0, pix_2);
         painter->drawPixmap(DstWidth-iHorzSplit+3,0,pix_3);

         painter->drawPixmap(-3, iVertSplit, pix_4);
         painter->drawPixmap(iHorzSplit-3, iVertSplit, pix_5);
         painter->drawPixmap(DstWidth-iHorzSplit+3, iVertSplit, pix_6);

         painter->drawPixmap(-3, DstHeight-iVertSplit+4, pix_7);
         painter->drawPixmap(iHorzSplit-3, DstHeight-iVertSplit+4, pix_8);
         painter->drawPixmap(DstWidth-iHorzSplit+3, DstHeight-iVertSplit+4, pix_9);
         painter->end();
     }
     return resultImg;
 }

關於圖片的縮放處理,我借鑑了csdn大佬的九宮格縮放圖片算法:https://blog.csdn.net/caoshangpa/article/details/53391230
但是在大佬的源碼程序中,我遇到了 按鈕重繪圖片後存在黑邊的問題。在我自己的代碼中已經將它解決了。

完整代碼:

imagebutton.h

#ifndef TEST1BUTTON_H
#define TEST1BUTTON_H

#include <QPushButton>
#include <QColor>

class Test1Button : public QPushButton
{
    Q_OBJECT

public:
    explicit Test1Button(QWidget *parent = nullptr);
    explicit Test1Button(const QString&text,QWidget *parent = nullptr);
    ~Test1Button();
    void setText(const QString&text);
    void setMyIcon(const QString &icon);
    void setImageName(const QString &img);

protected:
    void paintEvent(QPaintEvent *event);
    void drawText(QPainter *painter);
    void drawImage(QPainter*painter);
    void drawIcon(QPainter*painter);
    QPixmap* ninePatch(QString picName,double iHorzSplit,double iVertSplit, double DstWidth, double DstHeight);
    QPixmap generatePixmap(const QPixmap& img_in, int radius1,int radius2);

private:
    QString  mFileName;
    QString mText;
    QString mIcon;
    int mWidth;
    int mHeight;
    bool pressed;
};

#endif // TEST1BUTTON_H

imagebutton.cpp

#include "imagebutton.h"
#include <QPainter>
#include <QDebug>
#include <QBitmap>
#include <QMouseEvent>
#include <QSizePolicy>
Test1Button::Test1Button(QWidget *parent):QPushButton(parent),mWidth(100),mHeight(100)
{
    pressed = false;
    mText = "";
    mIcon = "";
    mFileName = "/home/rabbitchenc/Image/btn2_normal.png";
    setSizePolicy(QSizePolicy::Ignored,
                 QSizePolicy::Ignored
);

    connect(this,&QPushButton::pressed,[=](){
        pressed = true;
        setImageName("/home/rabbitchenc/Image/btn2_pressed.png");
    });

    connect(this,&QPushButton::released,[=](){

        pressed = false;
        setImageName("/home/rabbitchenc/Image/btn2_normal.png");

    });
}

Test1Button::Test1Button(const QString&text,QWidget *parent):QPushButton(parent),mWidth(100),mHeight(30),mText(text)
{
    pressed = false;
    mText = "";
    mIcon = "";
    setImageName("/home/rabbitchenc/Image/btn2_normal.png");
    setSizePolicy(QSizePolicy::Preferred,
                  QSizePolicy::Preferred
);

    connect(this,&QPushButton::pressed,[=](){
        setImageName("/home/rabbitchenc/Image/btn2_pressed.png");
    });

    connect(this,&QPushButton::released,[=](){
        setImageName("/home/rabbitchenc/Image/btn2_normal.png");
    });
}


Test1Button::~Test1Button()
{

}

void Test1Button::paintEvent(QPaintEvent *event)
{
 QPainter painter(this);
 painter.setRenderHint(QPainter::Antialiasing);
 painter.setRenderHint(QPainter::TextAntialiasing);
 drawImage(&painter);
 drawText(&painter);
 drawIcon(&painter);

}

//組按鍵的狀態被解決
void Test1Button::drawImage(QPainter*painter)
{
    painter->save();
    QPixmap pixmap;
    mWidth = width();
    mHeight = height();

    if(isEnabled()){
        if(isCheckable()){
            if(isChecked()){
                mFileName = "/home/rabbitchenc/Image/btn2_pressed.png";
            }else{
                mFileName = "/home/rabbitchenc/Image/btn2_normal.png";
            }
            if(pressed){
                mFileName = "/home/rabbitchenc/Image/btn2_focused.png";
            }
        }
    }else {
        mFileName ="/home/rabbitchenc/Image/btn2_disable.png";
}
    qDebug() << "filename" <<mFileName;
    pixmap = QPixmap( mFileName);
    int pixWidth = pixmap.width();
    int pixHeight = pixmap.height();

    pixmap = *ninePatch( mFileName,pixWidth/3,pixHeight/3, mWidth,mHeight);
    pixmap = generatePixmap(pixmap, 9,9);
    painter->drawPixmap(0,0,mWidth,mHeight,pixmap);
    painter->restore();
}
/*
**  功能             : 九宮格圖處理
**  picName          : 圖片名字
**  iHorzSplit       : 四個角上格子的寬度
**  iVertSplit       : 四個角上格子的高度
**  DstWidth         : 整個圖片縮放的寬度
**  DstWidth         : 整個圖片縮放的高度
**  返回值           : 處理完成的圖片
*/
//猜測出現這種問題的原因1  精度不夠 問題二 圖片邊框 本身就是存在問題的   換一張圖進行嘗試

 QPixmap* Test1Button::ninePatch(QString picName,double iHorzSplit, double iVertSplit, double DstWidth, double DstHeight)//將數據都修改成 double類型 進行測試
 {

     QPixmap* pix = new QPixmap(picName);
     int pixWidth = pix->width();
     int pixHeight = pix->height();
     QPixmap pix_1 = pix->copy(0, 0, iHorzSplit, iVertSplit);//0 0 22 14
     QPixmap pix_2 = pix->copy(iHorzSplit, 0, pixWidth-iHorzSplit*2, iVertSplit);//22 0 22 14
     QPixmap pix_3 = pix->copy(pixWidth-iHorzSplit, 0, iHorzSplit, iVertSplit);// 44 0 22 14

     QPixmap pix_4 = pix->copy(0, iVertSplit, iHorzSplit, pixHeight-iVertSplit*2);//0 14 22 16
     QPixmap pix_5 = pix->copy(iHorzSplit, iVertSplit, pixWidth-iHorzSplit*2, pixHeight-iVertSplit*2);//22 14  22 16
     QPixmap pix_6 = pix->copy(pixWidth-iHorzSplit, iVertSplit, iHorzSplit, pixHeight-iVertSplit*2);//44  14  22 16

     QPixmap pix_7 = pix->copy(0, pixHeight-iVertSplit, iHorzSplit, iVertSplit);//0 30 22 14
     QPixmap pix_8 = pix->copy(iHorzSplit, pixHeight-iVertSplit, pixWidth-iHorzSplit*2, iVertSplit);//22 30 22 14
     QPixmap pix_9 = pix->copy(pixWidth-iHorzSplit, pixHeight-iVertSplit, iHorzSplit, iVertSplit);//44 30 22 14
     pix_2 = pix_2.scaled(DstWidth-iHorzSplit*2+6,iVertSplit, Qt::IgnoreAspectRatio);//保持高度拉寬
     pix_4 = pix_4.scaled(iHorzSplit, DstHeight-iVertSplit*2+4, Qt::IgnoreAspectRatio);//保持寬度拉高
     pix_5 = pix_5.scaled(DstWidth-iHorzSplit*2+6,DstHeight-iVertSplit*2+4, Qt::IgnoreAspectRatio);//寬高都縮放
     pix_6 = pix_6.scaled(iHorzSplit, DstHeight-iVertSplit*2+4, Qt::IgnoreAspectRatio);//保持寬度拉高
     pix_8 = pix_8.scaled(DstWidth-iHorzSplit*2+6, iVertSplit);//保持高度拉寬


     QPixmap* resultImg =new QPixmap(DstWidth, DstHeight);
     QPainter* painter = new QPainter(resultImg);
     if (!resultImg->isNull()) {
         painter->drawPixmap(-3,0,pix_1);
         painter->drawPixmap(iHorzSplit-3, 0, pix_2);
         painter->drawPixmap(DstWidth-iHorzSplit+3,0,pix_3);

         painter->drawPixmap(-3, iVertSplit, pix_4);
         painter->drawPixmap(iHorzSplit-3, iVertSplit, pix_5);
         painter->drawPixmap(DstWidth-iHorzSplit+3, iVertSplit, pix_6);

         painter->drawPixmap(-3, DstHeight-iVertSplit+4, pix_7);
         painter->drawPixmap(iHorzSplit-3, DstHeight-iVertSplit+4, pix_8);
         painter->drawPixmap(DstWidth-iHorzSplit+3, DstHeight-iVertSplit+4, pix_9);
         painter->end();
     }
     return resultImg;

 }


 /**
    * 圓角圖片
    * src 原圖片
    * radius 圖片半徑
    */

 QPixmap Test1Button::generatePixmap(const QPixmap& img_in, int radius1,int radius2) {

     if (img_in.isNull())
        {
            return QPixmap();
        }
        QSize size(img_in.size());
        QBitmap mask(size);
        QPainter painter(&mask);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setRenderHint(QPainter::SmoothPixmapTransform);
        painter.fillRect(mask.rect(), Qt::white);
        painter.setBrush(QColor(0, 0, 0));
        painter.drawRoundedRect(mask.rect(), radius1, radius2);
        QPixmap image = img_in;
        image.setMask(mask);
        return image;
    }

 //添加文字
  void Test1Button::drawText(QPainter *painter)
  {
      painter->save();
      QFont font = painter->font();
      painter->drawText(0,0,mWidth,mHeight,Qt::AlignCenter,mText);
      painter->restore();
  }

  //添加圖標
  void Test1Button::drawIcon(QPainter*painter)
  {
      painter->save();
      qDebug() << "icon" << mIcon;
      QPixmap pixmap(mIcon);
      if(pressed){
          painter->drawPixmap((width()-pixmap.width())/2,(height()-pixmap.height())/2,pixmap.width(),pixmap.height(),pixmap);
      }else{
          painter->drawPixmap((width()-pixmap.width())/2,(height()-pixmap.height())/2,pixmap.width(),pixmap.height(),pixmap);
      }

      painter->restore();
  }

 void Test1Button::setText(const QString&text)
 {
     mText = text;
     update();
 }


void Test1Button::setMyIcon(const QString &icon)
{
    mIcon = icon;
    update();
}
void Test1Button::setImageName(const QString &img)
{
    mFileName = img;
    update();
}

我是剛剛學習剛剛學習Qt和cpp兩個月的菜雞程序員,會水羣,白嫖,寫bug,請大佬門多多指教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章