一.背景图片描述
1. 名称定义
在Qt的控件中,加入类似CSS3的box-shodow的阴影效果。由于QSS不支持box-shodow属性,故而通过截图拼凑来模拟。
图1. radius_border.png
上图为我们需要准备的背景图(radius_border.png):
矩形区域(x2,y2,x5,y5)所内切包含的圆角矩形背景透明,之所以透明,是为了不遮掩住QT的控件背景,比如QLineEdit;
矩形区域(x1,y1,x6,y6)所内切包含的蓝色带状区域为控件的阴影;
矩形区域(x1,y1,x3,y3)所内切包含的蓝色扇环区域命名为leftTop;
矩形区域(x3,y1,x4,y2)所内切包含的蓝色矩形区域命名为top;
矩形区域(x4,y1,x6,y3)所内切包含的蓝色扇环区域命名为rightTop;
矩形区域(x5,y3,x6,y4)所内切包含的蓝色矩形区域命名为right;
矩形区域(x4,y4,x6,y6)所内切包含的蓝色扇环区域命名为rightBottom;
矩形区域(x3y5,x4,y6)所内切包含的蓝色矩形区域命名为bottom;
矩形区域(x1,y4,x3,y6)所内切包含的蓝色扇环区域命名为leftBottom
矩形区域(x1,y3,x2,y4)所内切包含的蓝色矩形区域命名为left;
注:当border_radius为0时,阴影即为直角矩形,其所修饰的控件也应该为直角。
2. 变量定义
border_width: 蓝色带状阴影的宽度
border_radius: 带状阴影圆角的幅度
background_width: 背景图片的宽度
background_height: 背景图片的高度
二.背景图片使用
1. 获取背景图片的尺寸
QPixmap background =QPixmap(":/image/radius_border.png");
int background_width = background.width(); // 背景图片宽度
int background_height =background.height(); // 背景图片高度
2. 定义阴影带相关值
int border_width = 5; //阴影带的宽度
int border_radius = 5; // 阴影带圆角的半径
int corner_width = border_width + border_radius; // 阴影带4个转角的宽
int corner_height = border_width +border_radius; // 阴影带4个转角的高
int original_border = 1; // 控件原始边界宽度
3. 从左上角(leftTop)开始,顺时针截取(QPixmap对象的copy方法)4个转角与4个边
QPixmap leftTop =
background.copy(0, 0, corner_width,corner_height);
QPixmap top =
background.copy(corner_width, 0,background_width - 2 * corner_width, border_width);
QPixmap rightTop =
background.copy(background_width- corner_width, 0, corner_width, corner_height);
QPixmap right =
background.copy(background_width- border_width, corner_height, border_width,
background_height - 2 *corner_height);
QPixmap rightBottom =
background.copy(background_width - corner_width,background_height - corner_height,
corner_width, corner_height);
QPixmap bottom =
background.copy(corner_width, background_height -border_width, background_width –
2 * corner_width, border_width);
QPixmap leftBottom =
background.copy(0, background_height -corner_height, corner_width, corner_height);
QPixmap left =
background.copy(0, corner_height,border_width, background_height - 2 * corner_height);
4. 获取控件的位置,把上述截取的4角4边绘制在控件的边缘
/* 获取控件的位置 */
QRect rect =ui->lineEdit->geometry();
int startX = rect.left(); // 控件的起始X坐标
int endX = rect.right(); // 控件的终止X坐标
int startY = rect.top(); // 控件的起始Y坐标
int endY = rect.bottom(); // 控件的终止Y坐标
int width = rect.width(); // 控件宽度
int height = rect.height(); // 控件高度
/* 绘制4角4边 */
painter.drawPixmap(startX - border_width,startY - border_width, leftTop);
painter.drawPixmap(startX + border_radius,startY - border_width,
width - 2 *border_radius - original_border, border_width, top);
painter.drawPixmap(endX - border_radius,startY - border_width, rightTop);
painter.drawPixmap(endX, startY +border_radius, border_width,
height - 2 *border_radius - original_border, right);
painter.drawPixmap(endX - border_radius,endY - border_radius, rightBottom);
painter.drawPixmap(startX + border_radius,endY , width - 2 * border_radius - original_border,
border_width,bottom);
painter.drawPixmap(startX - border_width,endY - border_width, leftBottom);
painter.drawPixmap(startX - border_width,startY + border_radius, border_width,
height - 2 *border_radius - original_border, left);
二.工程源代码
2.1 工程结构如下图所示:
2.2 边界描述类
2.2.1 头文件 border.h
#ifndef BORDER_H
#define BORDER_H
#include <QPixmap>
#include <QPainter>
class Border
{
public:
Border(const char* bg);
Border(const char* bg, int border_width, int border_radius, int original_border);
void paintBorder(QPainter &painter, QRect &rect);
~Border();
private:
QPixmap background; // 完整背景图
int background_width; // 背景图片宽度
int background_height; // 背景图片高度
int border_width;
int border_radius;
int original_border;
int corner_width;
int corner_height;
QPixmap leftTop;
QPixmap top;
QPixmap rightTop;
QPixmap right;
QPixmap rightBottom;
QPixmap bottom;
QPixmap leftBottom;
QPixmap left;
QPixmap center;
};
#endif // BORDER_H
2.2.2 源文件border.cpp
#include "border.h"
Border::Border(const char* bg):border_width(5), border_radius(5), original_border(1) {
this->background = QPixmap(bg);
}
Border::Border(const char* bg, int border_width, int border_radius, int original_border)
:border_width(5), border_radius(5), original_border(1) {
this->background = QPixmap(bg);
this->background_width = background.width(); // 背景图片宽度
this->background_height = background.height(); // 背景图片高度
this->border_width = border_width;
this->border_radius = border_radius;
this->original_border = original_border;
this->corner_width = border_width + border_radius;
this->corner_height = border_width + border_radius;
/* 以顺时针方向旋转的边界 */
this->leftTop = background.copy(0, 0, corner_width, corner_height);
this->top = background.copy(corner_width, 0, background_width - 2 * corner_width, border_width);
this->rightTop = background.copy(background_width - corner_width, 0, corner_width, corner_height);
this->right = background.copy(background_width - border_width, corner_height, border_width,
this-> background_height - 2 * corner_height);
this->rightBottom = background.copy(background_width - corner_width, background_height - corner_height,
this-> corner_width, corner_height);
this->bottom = background.copy(corner_width, background_height - border_width,
this-> background_width - 2 * corner_width, border_width);
this->leftBottom = background.copy(0, background_height - corner_height, corner_width, corner_height);
this->left = background.copy(0, corner_height, border_width, background_height - 2 * corner_height);
}
Border::~Border() {
}
void Border::paintBorder(QPainter &painter, QRect& rect) {
int startX = rect.left();
int endX = rect.right();
int startY = rect.top();
int endY = rect.bottom();
int width = rect.width();
int height = rect.height();
painter.drawPixmap(startX - border_width, startY - border_width, leftTop);
painter.drawPixmap(startX + border_radius, startY - border_width,
width - 2 * border_radius - original_border, border_width, top);
painter.drawPixmap(endX - border_radius, startY - border_width, rightTop);
painter.drawPixmap(endX, startY + border_radius, border_width,
height - 2 * border_radius - original_border, right);
painter.drawPixmap(endX - border_radius, endY - border_radius, rightBottom);
painter.drawPixmap(startX + border_radius, endY , width - 2 * border_radius - original_border,
border_width, bottom);
painter.drawPixmap(startX - border_width, endY - border_width, leftBottom);
painter.drawPixmap(startX - border_width, startY + border_radius, border_width,
height - 2 * border_radius - original_border, left);
}
2.3 主窗口
2.3.1 头文件mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTabWidget>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QToolBar>
#include "border.h"
namespace Ui {
class MainWindow;
}
/*
* class MainWindow: 子类
* public QMainWindow:父类
*/
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Border *border;
protected:
void paintEvent(QPaintEvent *event);
bool eventFilter(QObject *watched,QEvent *event);
bool event(QEvent *event);
};
#endif // MAINWINDOW_H
2.3.2 源文件mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QMessageBox>
#include <QGraphicsDropShadowEffect>
#include <QDebug>
#include <QPainter>
#include <QMouseEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 遍历子控件
QObjectList list = ui->centralWidget->children();
foreach (QObject *obj, list) {
obj->installEventFilter(this);
#if 0
qDebug() << obj->objectName(); // 控件名称
qDebug() << obj->metaObject()->className(); // 控件类名称
#endif
char *className = (char *)obj->metaObject()->className();
// 去掉按钮的焦点
if(strcmp(className, "QPushButton") == 0) {
QPushButton *button = qobject_cast<QPushButton*>(obj);
button->setFocusPolicy(Qt::NoFocus);
}
}
border = new Border(":/image/radius_border.png", 5, 5, 1);
}
MainWindow::~MainWindow()
{
delete ui;
}
/*
* 在eventFilter函数中调用this->update(),则会触发该函数
*/
void MainWindow::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QObjectList list = ui->centralWidget->children();
foreach (QObject *obj, list) {
char *className = (char *)obj->metaObject()->className();
if(strcmp(className, "QPushButton") == 0) {
QPushButton *button = qobject_cast<QPushButton*>(obj);
if(button->isDown()) {
QRect rect = button->geometry();
border->paintBorder(painter, rect);
}
}
if(strcmp(className, "QLineEdit") == 0) {
QLineEdit *edit = qobject_cast<QLineEdit*>(obj);
if(edit->hasFocus()) {
QRect rect = edit->geometry();
border->paintBorder(painter, rect);
}
}
}
}
/*
* eventFilter针对某一控件事件的过滤,使用前需要在控件安装事件过滤器:
* QObject->installEventFilter(this);
*/
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
char *className = (char *)watched->metaObject()->className();
if(strcmp(className, "QPushButton") == 0 ||
strcmp(className, "QLineEdit") == 0) {
this->update();
}
return QWidget::eventFilter(watched, event);
}
/*
* MainWindow的事件处理函数,例如鼠标点击事件:若鼠标点击在MainWindow窗口上面,则进入该函数。
* 如果鼠标点击事件在QLineEdit或者QPushButton上面,则不会进入。
*/
bool MainWindow::event(QEvent* event)
{
switch(event->type()) {
case QEvent::MouseButtonPress:
qDebug() << "QEvent::MouseButtonPress";
break;
default:
break;
}
return QWidget::event(event);
}
2.4 主函数 main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QFile>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QFile styleFile(":/image/blue.css");
styleFile.open(QIODevice::ReadOnly);
QString setStyleSheet(styleFile.readAll());;
a.setStyleSheet(setStyleSheet);
return a.exec();
}
点击下载
最后要感谢的是刘典武大侠,本工程所采用的blue.css是从他的工程里面拿来的,3ks!