声明下:这只是我自己在学习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());//设置皮肤窗体为合适的大小
}
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();
}
运行结果: