Qt4.8.2 实现简单的界面换肤功能

声明下:这只是我自己在学习Qt的时候,想到的,也不知道这方法合不合适,反正是能够实现换肤功能。

一、思路及准备

双击主程序界面,弹出换肤界面,点击换肤界面上的图片,主程序改变相应界面背景图片。

我准备了四张图片,big_spring.png,big_summer.png,small_spring.png,small_summer.png.看名字就知道换肤界面列出来small_spring.png和small_summer.png,点击图片后,主程序界面显示相应大图。

二、皮肤窗口

新建Qt4空项目,新建C++类,继承自QWidget,取名SkinWidget

头文件暂时不修改,看看SkinWidget.cpp

#include "skinwidget.h"

#include 
#include 

SkinWidget::SkinWidget(QWidget *parent) :
    QWidget(parent)
{
    QStringList btnText;
    btnText<<"spring"<<"summer";
    QHBoxLayout *mainLayout=new QHBoxLayout;
    for(int i=0;isetToolTip(btnText[i]);//鼠标停留在按钮上的提示
        btn->setStyleSheet(qss);//设置样式表,按钮的背景图片
        btn->setFixedSize(150,120);//设置按钮固定大小为背景图片的大小
        btn->setFlat(true);//设置按钮的平坦属性,也就是按钮无边框
        mainLayout->addWidget(btn);
    }
    setLayout(mainLayout);
    setFixedSize(sizeHint().width(),sizeHint().height());//设置皮肤窗体为合适的大小
}

新建个main.cpp测试下,

#include 
#include "skinwidget.h"
int main(int argc,char *argv[])
{
    QApplication app(argc,argv);
    
    SkinWidget skin;
    skin.show();
    
    return app.exec();
}


看样子还马马虎虎,可以继续进行。

三、主程序窗口

新建C++类MainWidget,继承自QWidget。我们想实现双击主程序,弹出换肤窗体,就必须捕捉到双击时间,类似于MFC的OnDbClick。

先看看基类QWidget提供的虚函数



虚函数就是基类提供的,在我们需要的时候去重载的接口,所以在MainWidget头文件中,重载鼠标双击事件函数。

MainWidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include 

class MainWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MainWidget(QWidget *parent = 0);
    
signals:
    
public slots:

protected:
    virtual void mouseDoubleClickEvent(QMouseEvent *);//重载鼠标双击事件函数 从QWidget继承
};

#endif // MAINWIDGET_H


 MainWidget.cpp

#include "mainwidget.h"

#include //鼠标事件
#include //调色板 设置背景颜色

#include 

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent)
{
    setFixedSize(500,400);
    QPalette palette;
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/big_spring.png")));
    setPalette(palette);
}

void MainWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    //如果双击鼠标左键,弹出测试对话框
    if(event->button()&Qt::LeftButton)
        QMessageBox::information(this,"skin","leftButton double click test");
}


测试一下,结果还行。

 四、皮肤窗口与主程序窗口的交互 和QSignalMapper

在主窗口双击事件中,弹出皮肤窗体,然后把皮肤窗体各个按钮的clicked信号同主程序不同背景的槽连接起来

SkinWidget.h

#ifndef SKINWIDGET_H
#define SKINWIDGET_H

#include 

class SkinWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SkinWidget(QWidget *parent = 0);
    
signals:
    void changeSkinSpring();//与春天按钮的clicked信号绑定
    void changeSkinSummer();//与夏天按钮的clicked信号绑定
private slots:

};

#endif // SKINWIDGET_H


SkinWidget.cpp

#include "skinwidget.h"

#include 
#include 

SkinWidget::SkinWidget(QWidget *parent) :
    QWidget(parent)
{
    QStringList btnText;
    btnText<<"spring"<<"summer";
    QHBoxLayout *mainLayout=new QHBoxLayout;
    for(int i=0;isetToolTip(btnText[i]);//鼠标停留在按钮上的提示
        btn->setStyleSheet(qss);//设置样式表,按钮的背景图片
        btn->setFixedSize(150,120);//设置按钮固定大小为背景图片的大小
        btn->setFlat(true);//设置按钮的平坦属性,也就是按钮无边框
        mainLayout->addWidget(btn);
        switch(i)
        {
        case 0:
            QObject::connect(btn,SIGNAL(clicked()),this,SIGNAL(changeSkinSpring()));
            break;
        case 1:
            QObject::connect(btn,SIGNAL(clicked()),this,SIGNAL(changeSkinSummer()));
            break;
        }
    }
    setLayout(mainLayout);
    setFixedSize(sizeHint().width(),sizeHint().height());//设置皮肤窗体为合适的大小
}


MainWidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include 

class MainWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MainWidget(QWidget *parent = 0);
    
signals:
    
private slots:
    void setBkSpring();//与SkinWidget的changeSkinSpring信号连接
    void setBkSummer();//与SkinWidget的changeSkinSummer信号连接

protected:
    virtual void mouseDoubleClickEvent(QMouseEvent *);//重载鼠标双击事件函数 从QWidget继承
};

#endif // MAINWIDGET_H


MainWidget.cpp

#include "mainwidget.h"
#include "skinwidget.h"
#include //鼠标事件
#include //调色板 设置背景颜色

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent)
{
    setFixedSize(500,400);
    QPalette palette;
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/big_spring.png")));
    setPalette(palette);
}

void MainWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    SkinWidget *skin=new SkinWidget;
    skin->setAttribute(Qt::WA_DeleteOnClose);
    QObject::connect(skin,SIGNAL(changeSkinSpring()),this,SLOT(setBkSpring()));
    QObject::connect(skin,SIGNAL(changeSkinSummer()),this,SLOT(setBkSummer()));
    skin->show();
}

//private slot 换肤 春天
void MainWidget::setBkSpring()
{
    QPalette palette;
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/big_spring.png")));
    setPalette(palette);
}
//private slot 换肤 夏天
void MainWidget::setBkSummer()
{
    QPalette palette;
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/big_summer.png")));
    setPalette(palette);
}


 

运行下,确实可以。

但是,这是个好办法么,如果有1000张候选图片,我们就要建立1000个槽函数????

如果可以把图片的名字当作信号的参数多好啊,就是点击春天按钮的时候,把“spring”这个字符串当作信号的参数。点击夏天按钮的时候,把“summer”这个字符串当作信号的参数。问题转化为:如何把一个无参信号同一个有参信号联系起来。

终于,在网上搜到了这个类QSignalMapper。这个类可以看成信号的翻译和转发器,可以把无参信号翻译成带int参数、QString参数、QObject*参数或者QWidget*参数的信号, 并将之转发。

源码如下:

SkinWidget.h

#ifndef SKINWIDGET_H
#define SKINWIDGET_H

#include 

class QSignalMapper;
class SkinWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SkinWidget(QWidget *parent = 0);
    
signals:
    void skinChange(QString);

private slots:
private:
    QSignalMapper *signalMapper;

};

#endif // SKINWIDGET_H


SkinWidget.cpp

#include "skinwidget.h"

#include 
#include 
#include 

SkinWidget::SkinWidget(QWidget *parent) :
    QWidget(parent)
{
    signalMapper=new QSignalMapper(this);

    QStringList btnText;
    btnText<<"spring"<<"summer";
    QHBoxLayout *mainLayout=new QHBoxLayout;
    for(int i=0;isetToolTip(btnText[i]);//鼠标停留在按钮上的提示
        btn->setStyleSheet(qss);//设置样式表,按钮的背景图片
        btn->setFixedSize(150,120);//设置按钮固定大小为背景图片的大小
        btn->setFlat(true);//设置按钮的平坦属性,也就是按钮无边框
        mainLayout->addWidget(btn);

        QObject::connect(btn,SIGNAL(clicked()),signalMapper,SLOT(map()));
        signalMapper->setMapping(btn,btnText[i]);
    }

    connect(signalMapper,SIGNAL(mapped(QString)),this,SIGNAL(skinChange(QString)));
    setLayout(mainLayout);
    setFixedSize(sizeHint().width(),sizeHint().height());//设置皮肤窗体为合适的大小
}

QSignalMapper

 MainWidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include 

class MainWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MainWidget(QWidget *parent = 0);
    
signals:
    
private slots:
    void setBk(QString);

protected:
    virtual void mouseDoubleClickEvent(QMouseEvent *);//重载鼠标双击事件函数 从QWidget继承
};

#endif // MAINWIDGET_H


MainWidget.cpp

#include "mainwidget.h"
#include "skinwidget.h"
#include //鼠标事件
#include //调色板 设置背景颜色

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent)
{
    setFixedSize(500,400);
    setBk("spring");
}

void MainWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button()&Qt::LeftButton)
    {
        SkinWidget *skin=new SkinWidget;
        skin->setAttribute(Qt::WA_DeleteOnClose);
        QObject::connect(skin,SIGNAL(skinChange(QString)),this,SLOT(setBk(QString)));
        skin->show();
    }
}

//private slot
void MainWidget::setBk(QString picName)
{
    QPalette palette;
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/img/big_"+picName+".png")));
    setPalette(palette);
}


main.cpp

#include 
#include "skinwidget.h"
#include "mainwidget.h"
int main(int argc,char *argv[])
{
    QApplication app(argc,argv);

  //  SkinWidget skin;
  //  skin.show();

    MainWidget mainWindow;
    mainWindow.show();

    return app.exec();
}


运行结果:

你可能感兴趣的:(Qt4)