使用Qt实现超酷炫按钮特效

简介: 使用Qt实现超酷炫按钮特效

Hello,大家好,今天给大家分享个比较有趣的小示例,按钮特效,具体效果如下图所示



下面,我们来看看它是如何实现的。


按钮特效,需要用到QWidget的方法:

  1. voidQWidget::setGraphicsEffect(QGraphicsEffect*effect)


QGraphicsEffect类是窗口特效的基类,基于该基类,Qt提供了四种便捷类:

不加特效的正常图片


1 QGraphicsBlurEffect //模糊特效


2 QGraphicsColorizeEffect //颜色特效


3 QGraphicsOpacityEffect //透明度特效


4 QGraphicsDropShadowEffect //阴影特效


示例中的按钮使用了阴影特效,其它特效用法类似。

新建一个GUI工程,取名为SwitchButtonWidget ui界面为:

按钮命名格式为“btn行号列号”,并且将这些QPushButton提升为MyButton,MyButton我们后面再定义。

使用这样的命名规则是为了当按下方向键(上下左右键)方便将焦点框切换到对应的按钮上

右键,修改样式表,修改窗口的样式为:

QPushButton {
    border-radius: 4px; 
    border: none; 
    width: 35px; 
    height: 35px; 
    color: rgb(180, 0, 0);
    font: bold 25px;
}
QPushButton:hover { 
    background: rgb(85, 85, 85); 
}
QPushButton:pressed{ 
    background: rgb(80, 80, 80); 
}
QWidget { 
    border: 1px solid "#222222"; 
    background-color: "#222222"; 
}


switchbuttonwidget.h

#ifndef SWITCHBUTTONWIDGET_H
#define SWITCHBUTTONWIDGET_H
#include <QtWidgets>
#include "controltable.h"
namespace Ui {
class SwitchButtonWidget;
}
class SwitchButtonWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SwitchButtonWidget(QWidget *parent = 0);
    ~SwitchButtonWidget();
protected:
    //重写实现按键事件
    void keyPressEvent(QKeyEvent* e);
private:
    void createTable();
private:
    Ui::SwitchButtonWidget *ui;
    ControlTable* table;
};
#endif // SWITCHBUTTONWIDGET_H


switchbuttonwidget.cpp

#include "switchbuttonwidget.h"
#include "ui_switchbuttonwidget.h"
SwitchButtonWidget::SwitchButtonWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SwitchButtonWidget)
{
    ui->setupUi(this);
    createTable();
}
SwitchButtonWidget::~SwitchButtonWidget()
{
    delete ui;
}
void SwitchButtonWidget::keyPressEvent(QKeyEvent *e)
{
    int k = e->key();
    switch (k)
    {
    case Qt::Key_Up:
    {
        table->toUp();
        break;
    }
    case Qt::Key_Down:
    {
        table->toDown();
        break;
    }
    case Qt::Key_Left:
    {
        table->toLeft();
        break;
    }
    case Qt::Key_Right:
    {
        table->toRight();
        break;
    }
    }
}
void SwitchButtonWidget::createTable()
{
    QList<ControlList> tmpTable;
    ControlList row0;
    ControlList row1;
    ControlList row2;
    ControlList row3;
    row0 << ui->btn_0_0 << ui->btn_0_1 << ui->btn_0_2;
    row1 << ui->btn_1_0 << ui->btn_1_1 << ui->btn_1_2;
    row2 << ui->btn_2_0 << ui->btn_2_1 << ui->btn_2_2;
    row3 << ui->btn_3_0 << ui->btn_3_1 << ui->btn_3_2;
    tmpTable << row0 << row1 << row2 << row3;
    table = new ControlTable(this);
    table->setTable(tmpTable);
}


下面是controltable的声明,具体思路已经写在注释里了,这里就不多解释了

controltable.h

#ifndef CONTROLTABLE_H
#define CONTROLTABLE_H
#include <QtWidgets>
typedef QList<QWidget*> ControlList;
class ControlTable: public QObject
{
    Q_OBJECT
public:
    //注意parent不能为空
    ControlTable(QWidget *parent);
    void setTable(const QList<ControlList>& t);
    //按钮焦点上移
    void toUp();
    //按钮焦点下移
    void toDown();
    //按钮焦点左移
    void toLeft();
    //按钮焦点右移
    void toRight();
signals:
    void controlSwitched(QWidget* oldControl, QWidget* newControl);
private:
    //返回按钮表格第r行所有按钮列表
    ControlList rowControls(int r);
    //返回按钮表格第c列所有按钮列表
    ControlList colControls(int c);
    //获取控件行号
    int row(QWidget* control);
    //获取控件列号
    int col(QWidget* control);
    //判断行列是否都有效
    bool isValid(int r, int c);
    //按钮表格最大行数
    int  rowCount();
    //选中btn
    void selectControl(QWidget* control);
    //返回btnList第index索引位置的后一个按钮
    //如果btnList只有一个按钮,则返回按钮本身
    QWidget* nextControl(const ControlList& controlList, int index);
    //返回btnList第index索引位置的前一个按钮
    //如果btnList只有一个按钮,则返回按钮本身
    QWidget* preControl(const ControlList& controlList, int index);
    //设置特效颜色阴影边框
    void setFrame(QWidget *control, const QColor& color);
    //取消特效颜色边框
    void unSetFrame(QWidget* control);
private:
    QWidget* widget;
    QWidget* currentContrl; //记录当前焦点所在按钮
    QList<ControlList> table;//按钮表格
    const char* rowid;
    const char* colid;
};
#endif // CONTROLTABLE_H


controltable.cpp

#include "controltable.h"
ControlTable::ControlTable(QWidget *parent):
    QObject(parent),rowid("table_row"),colid("table_col")
{
    Q_ASSERT(parent);
    currentContrl = 0;
    widget = parent;
}
/*
按钮表格图解,在阅读代码时,可参考此图解
btn代表按钮 null代表空
-----------------------
     col1 col2 col3
row1 btn  btn  null
row2 null btn  null
row3 btn  btn  btn
-----------------------
SwitchButtonWidget中的成员变量“table”是所有按钮指针和空指针的集合
例如table的第一行列表元素为[btn,btn,null]
在ui界面中,每个按钮的名称都采用 btn_行索引_列索引 的格式命名
这样取名只是为了直接能用ui指定行列
如果不想按照此命名规则排列,可在MyButton中添加行列成员,可达到相同效果
*/
void ControlTable::setTable(const QList<ControlList> &t)
{
    bool isSetDefaultControl = false;
    table = t;
    for (int i = 0; i < rowCount(); ++i)
    {
        ControlList controList =table.at(i);
        for (int j = 0; j < controList.size(); ++j)
        {
            if (table[i][j])
            {
                table[i][j]->setProperty(rowid, i);
                table[i][j]->setProperty(colid, j);
                if (!isSetDefaultControl)
                {
                    selectControl(table[i][j]);
                    isSetDefaultControl = true;
                }
            }
        }
    }
}
void ControlTable::toUp()
{
    QWidget* control = currentContrl;
    int curRow = row(control);
    int curCol = col(control);
    if (isValid(curRow, curCol))
    {
        control = preControl(colControls(curCol), curRow);
        selectControl(control);
    }
}
void ControlTable::toDown()
{
    QWidget* control = currentContrl;
    int curRow = row(control);
    int curCol = col(control);
    if (isValid(curRow, curCol))
    {
        control = nextControl(colControls(curCol), curRow);
        selectControl(control);
    }
}
void ControlTable::toLeft()
{
    QWidget* control = currentContrl;
    int curRow = row(control);
    int curCol = col(control);
    if (isValid(curRow, curCol))
    {
        control = preControl(rowControls(curRow), curCol);
        selectControl(control);
    }
}
void ControlTable::toRight()
{
    QWidget* control = currentContrl;
    int curRow = row(control);
    int curCol = col(control);
    if (isValid(curRow, curCol))
    {
        control = nextControl(rowControls(curRow), curCol);
        selectControl(control);
    }
}
ControlList ControlTable::rowControls(int r)
{
    return table[r];
}
ControlList ControlTable::colControls(int c)
{
    ControlList ret;
    for (int i = 0; i < rowCount(); ++i)
    {
        ret.append(table[i][c]);
    }
    return ret;
}
int ControlTable::row(QWidget *control)
{
    if (!control)
    {
        return -1;
    }
    if (!control->property(rowid).isValid())
    {
        return -1;
    }
    return control->property(rowid).toInt();
}
int ControlTable::col(QWidget *control)
{
    if (!control)
    {
        return -1;
    }
    if (!control->property(colid).isValid())
    {
        return -1;
    }
    return control->property(colid).toInt();
}
bool ControlTable::isValid(int r, int c)
{
    return r != -1 && c != -1;
}
int ControlTable::rowCount()
{
    return table.size();
}
void ControlTable::selectControl(QWidget *control)
{
    QWidget* old= currentContrl;
    if (old)
    {
        unSetFrame(old);
    }
    setFrame(control, Qt::red);
    currentContrl = control;
    emit controlSwitched(old, control);
}
QWidget *ControlTable::nextControl(const ControlList &controlList, int index)
{
    QWidget * ret = 0;
    int tmp = 0;
    int size = controlList.size();
    for (int i = index+1; i <= size+index; ++i)
    {
        tmp = i % size;
        if (controlList.at(tmp) != 0)
        {
            ret = controlList.at(tmp);
            break;
        }
    }
    return ret;
}
QWidget *ControlTable::preControl(const ControlList &controlList, int index)
{
    QWidget* ret = 0;
    int tmp = 0;
    int size = controlList.size();
    for (int i = index-1; i >= index-size; --i)
    {
        if (i < 0)
        {
            tmp = i + size;
        }
        else
        {
            tmp = i;
        }
        if (controlList.at(tmp) != 0)
        {
            ret = controlList.at(tmp);
            break;
        }
    }
    return ret;
}
void ControlTable::setFrame(QWidget* control, const QColor &color)
{
    QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect ();
    effect->setBlurRadius(50); //设置模糊半径为50px
    effect->setColor(color); //设置阴影颜色
    effect->setOffset(0); //设置水平和垂直方向的偏移量都为0
    control->setGraphicsEffect(effect); //为控件应用特效
}
void ControlTable::unSetFrame(QWidget* control)
{
    control->setGraphicsEffect(0);
}


为了让按钮响应按键操作并统一管理显示特效框,我们自定义MyButton类,继承自QPushButton

mybutton.h

#ifndef MYBUTTON_H
#define MYBUTTON_H
#include <QPushButton>
class MyButton : public QPushButton
{
    Q_OBJECT
public:
    MyButton(QWidget* parent = 0);
protected:
    void keyPressEvent(QKeyEvent* e);
};
#endif // MYBUTTON_H


mybutton.cpp

#include <QKeyEvent>
#include "mybutton.h"
MyButton::MyButton(QWidget *parent):
    QPushButton(parent)
{
}
void MyButton::keyPressEvent(QKeyEvent *e)
{
    int k = e->key();
    if (   k == Qt::Key_Up
           || k == Qt::Key_Down
           || k == Qt::Key_Left
           || k == Qt::Key_Right)
    {
        e->ignore();//让这些事件继续上传给父窗口,在本例中指SwitchButtonWidget
    }
    else
    {
        e->accept();//停止其它事件向上传播
    }
}


OK,到此,所有的代码全部编写完毕,运行程序,不出意外的话将会得到文章开头gif图片的按钮特效程序,使用方向键控制焦点框移动,是不是很酷啊。


好了,关于窗口特效的分享就到这里啦,其它特效使用方法和阴影特效非常类似,小豆君就不在这里一一列举了,最后,喜欢的朋友不要忘记点赞哦,您的支持就是对我最大的鼓励^_^

欢迎关注微信公众号-小豆君Qt分享


相关文章
|
3天前
【Qt 学习笔记】按钮实现helloworld | 信号与槽概述
【Qt 学习笔记】按钮实现helloworld | 信号与槽概述
31 0
|
3天前
QT中按钮格式QSS代码
QT中按钮格式QSS代码
|
3天前
|
安全 前端开发 C++
C++视角下的Qt按钮:从基础应用到高级定制(二)
C++视角下的Qt按钮:从基础应用到高级定制
52 2
|
3天前
|
XML JSON 算法
C++视角下的Qt按钮:从基础应用到高级定制(一)
C++视角下的Qt按钮:从基础应用到高级定制
101 2
|
6月前
06 QT - 按钮创建
06 QT - 按钮创建
27 0
|
3天前
|
算法 API 开发者
【Qt UI相关】Qt中如何控制 窗口的最大化、最小化和关闭按钮?一文带你掌握用法
【Qt UI相关】Qt中如何控制 窗口的最大化、最小化和关闭按钮?一文带你掌握用法
174 1
|
3天前
|
开发框架 UED 开发者
QML(Qt Quick) 按钮设计指南
QML(Qt Quick) 按钮设计指南
89 0
|
3天前
|
设计模式 安全 API
C++视角下的Qt按钮:从基础应用到高级定制(三)
C++视角下的Qt按钮:从基础应用到高级定制
59 0