Hello,大家好,今天给大家分享个比较有趣的小示例,按钮特效,具体效果如下图所示
下面,我们来看看它是如何实现的。
按钮特效,需要用到QWidget的方法:
void
QWidget::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分享