在項目中經常遇到需要高度定製的QPushButton,互斥性的QPushButton菜單便是其中一例。老手就不用看了,沒啥技術含量,希望能給新手點思路吧。再複雜的控件,也可以通過這種思路去構造。
效果圖如下:
基本需求就是鼠標三態(normal,hover,press),佈局樣式就是圖片+文字。這種樣式的按鈕應用場景還是挺多的,比如tab頁,工具欄,小到單個按鈕的需求。
基本思路:單個按鈕封裝成控件,這個控件包含這個按鈕的類別,文字,以及圖片路徑的類信息成員。然後實現這個控件的mouseReleaseEvent,enterEvent, leaveEvent等。再提供一個setStyle接口,用於設置不同狀態下的樣式。最後再把這些單個控件放到佈局裏,或者說是上層封裝的一個控件(比如工具欄控件)。 上面的樣式我只用到了兩態,實現的也有複雜一些的,不過道理都是一樣的。上代碼吧。
NaviBtn.h
#include <QWidget>
class QLabel;
enum ENavi
{
Navi_ClassRoom,
Navi_Courseware,
};
struct NaviInfo
{
ENavi type;
QString name;
QString imagePath;
};
class NaviBtn : public QWidget
{
Q_OBJECT
public:
NaviBtn(QWidget *parent, const NaviInfo &naviInfo);
~NaviBtn();
void setChecked(bool checked = true);
ENavi getType() { return m_NaviInfo.type; }
protected:
virtual void mouseReleaseEvent(QMouseEvent * event);
void paintEvent(QPaintEvent *event);
private:
void setStyle(bool checked = false);
signals:
void sig_NaviBtnClick(ENavi type);
private:
NaviInfo m_NaviInfo;
QLabel* m_ImageLbl = nullptr;
QLabel* m_NameLbl = nullptr;
bool m_IsChecked = false;
};
NaviBtn.cpp
NaviBtn::NaviBtn(QWidget *parent, const NaviInfo &naviInfo)
: QWidget(parent),m_NaviInfo(naviInfo)
{
setFixedSize(104, 104);
setObjectName("NaviBtn");
m_ImageLbl = new QLabel(this);
m_ImageLbl->setFixedSize(48, 48);
m_NameLbl = new QLabel(this);
m_NameLbl->setText(m_NaviInfo.name);
m_NameLbl->setObjectName("NaviBtnName");
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setSpacing(0);
layout->setContentsMargins(0, 14, 0, 0);
layout->setAlignment(Qt::AlignHCenter|Qt::AlignTop);
layout->addWidget(m_ImageLbl, 0, Qt::AlignHCenter);
layout->addSpacing(4);
layout->addWidget(m_NameLbl, 0, Qt::AlignHCenter);
layout->addStretch();
setStyle(m_NaviInfo.type == Navi_ClassRoom);
}
NaviBtn::~NaviBtn()
{
}
void NaviBtn::mouseReleaseEvent(QMouseEvent * event)
{
m_IsChecked = true;
setStyle(true);
emit sig_NaviBtnClick(m_NaviInfo.type);
}
void NaviBtn::setChecked(bool checked)
{
m_IsChecked = checked;
setStyle(checked);
}
void NaviBtn::setStyle(bool checked)
{
QString imageStyle;
if (checked)
{
setProperty("isCheck", true);
m_NameLbl->setProperty("isCheck", true);
imageStyle = QString("background-image:url(:/common/%1_check)").arg(m_NaviInfo.imagePath);
}
else
{
setProperty("isCheck", false);
m_NameLbl->setProperty("isCheck", false);
imageStyle = QString("background-image:url(:/common/%1)").arg(m_NaviInfo.imagePath);
}
style()->polish(this);
m_NameLbl->style()->polish(m_NameLbl);
m_ImageLbl->setStyleSheet(imageStyle);
}
void NaviBtn::paintEvent(QPaintEvent *event)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
對應的qss樣式如下:
QWidget#NaviBtn
{
border-radius:8px;
background-color:transparent;
}
QWidget#NaviBtn[isCheck = "true"]
{
background-color:rgba(0,0,0,0.06);
}
QLabel#NaviBtnName
{
font-size:18px;
color:rgba(0,0,0,0.6);
font-weight:400;
background-color:transparent;
}
QLabel#NaviBtnName[isCheck = "true"]
{
color:#FF6000;
}
是不是很簡單呢~