一、前言
對於眾多的Qter程序員來說,美化UI一直是個老大難問題,畢竟這種事情理論上應該交給專業的美工妹妹去做,無奈在當前整體國際國內形式之下,絕大部分公司是沒有專門的美工人員的,甚至說有個兼職的美工都已經是很奢侈的事情,大部分的公司都是一個程序員同時要肩負着測試員、美工人員、售后維護人員等人員的責任,老板肯定都是這么想,我花了這么多錢招你進來,所有程序相關的和周邊的你都的給我搞定才行。
程序的UI美化,個人覺得就兩點,第一點就是布局,你必須把控件擺整齊,一定要讓用戶看着舒服,而且用戶操作交互方便,這點在美化UI中占比60%重要,擺的歪歪扭扭,再如何顏色牛逼圖標圖片牛逼也是垃圾,一看就很丑陋,就是拒絕的,你看windows系統就算沒有什么鮮艷的顏色和圖標,各種設置界面都是整整齊齊的,看起來就舒服,才有繼續用下去的可能。第二點才是顏色和圖片,顏色不知道如何配色可以去UI中國等網站找到你喜歡的界面方案,找個拾色器直接把顏色拿過來就行,圖片圖片就需要用到今天的主角圖形字體。
圖形字體的出現絕對是所有程序員的福音,各種類型的各種種類的圖標應有盡有,直接找到你想要的圖標按照值作為文字文本寫進去就行,簡直爽的不要不要的,他是作為文本的形式存在,意味着你可以任意設置大小和顏色,這就不要太強大了哇,我們需要的不就是這種效果嗎?
按照這個思路,在2014年開始就封裝了一個圖形字體類,當初非常簡單,而且重復代碼非常多,今年靜下心來重新封裝重寫了一遍,基本上形成了現在的風格,一個類同時支持多種圖形字體文件(為什么有這個需求?因為網絡上各種圖形字體文件層出不窮,不大方便合並到一個字體文件中,而你的程序又可能都需要使用到這多個圖形字體文件),全部提供靜態方法設置,支持各種導航面板風格。
二、主要功能
- 可傳入多種圖形字體文件,一個類通用所有圖形字體。
- 默認已經內置了阿里巴巴圖形字體FontAliBaBa、國際知名圖形字體FontAwesome、天氣圖形字體FontWeather。
- 可設置 QLabel、QAbstractButton 文本為圖形字體。
- 可設置圖形字體作為 QAbstractButton 按鈕圖標。
- 內置萬能的方法 getPixmap 將圖形字體值轉換為圖片。
- 無論是設置文本、圖標、圖片等都可以設置圖標的大小、尺寸、顏色等參數。
- 內置超級導航欄樣式設置,將圖形字體作為圖標設置到按鈕。
- 支持各種顏色設置比如正常顏色、懸停顏色、按下顏色、選中顏色。
- 可設置導航的位置為 left、right、top、bottom 四種。
- 可設置導航加深邊框顏色和粗細大小。
- 導航面板的各種切換效果比如鼠標懸停、按下、選中等都自動處理掉樣式設置。
- 全局靜態方法,接口豐富,使用極其簡單方便。
三、效果圖
四、開源主頁
- 以上作品完整源碼下載都在開源主頁,會持續不斷更新作品數量和質量,歡迎各位關注。
- 本開源項目已經成功升級到V2.0版本,分門別類,圖文並茂,保你爽到爆。
- Qt開源武林秘籍開發經驗,看完學完,20K起薪,沒有找我!
- 國內站點:https://gitee.com/feiyangqingyun/QWidgetDemo
- 國際站點:https://github.com/feiyangqingyun/QWidgetDemo
- 開源秘籍:https://gitee.com/feiyangqingyun/qtkaifajingyan
- 個人主頁:https://qtchina.blog.csdn.net/
- 知乎主頁:https://www.zhihu.com/people/feiyangqingyun/
五、核心代碼
QPixmap IconHelper::getPixmap1(const QColor &color, int icon, quint32 size,
quint32 width, quint32 height, int flags)
{
//主動繪制圖形字體到圖片
QPixmap pix(width, height);
pix.fill(Qt::transparent);
QPainter painter;
painter.begin(&pix);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.setPen(color);
iconFont.setPixelSize(size);
painter.setFont(iconFont);
painter.drawText(pix.rect(), flags, (QChar)icon);
painter.end();
return pix;
}
void IconHelper::setStyle1(QWidget *widget, QList<QPushButton *> btns, QList<int> icons, const IconHelper::StyleColor &styleColor)
{
QList<QAbstractButton *> list;
foreach (QPushButton *btn, btns) {
list << btn;
}
setStyle(widget, list, icons, styleColor);
}
void IconHelper::setStyle1(QWidget *widget, QList<QToolButton *> btns, QList<int> icons, const IconHelper::StyleColor &styleColor)
{
QList<QAbstractButton *> list;
foreach (QToolButton *btn, btns) {
list << btn;
}
setStyle(widget, list, icons, styleColor);
}
void IconHelper::setStyle1(QWidget *widget, QList<QAbstractButton *> btns, QList<int> icons, const IconHelper::StyleColor &styleColor)
{
int btnCount = btns.count();
int iconCount = icons.count();
if (btnCount <= 0 || iconCount <= 0 || btnCount != iconCount) {
return;
}
QString position = styleColor.position;
quint32 iconSize = styleColor.iconSize;
quint32 iconWidth = styleColor.iconWidth;
quint32 iconHeight = styleColor.iconHeight;
quint32 borderWidth = styleColor.borderWidth;
//根據不同的位置計算邊框
QString strBorder;
if (position == "top") {
strBorder = QString("border-width:%1px 0px 0px 0px;padding-top:%1px;padding-bottom:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
} else if (position == "right") {
strBorder = QString("border-width:0px %1px 0px 0px;padding-right:%1px;padding-left:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
} else if (position == "bottom") {
strBorder = QString("border-width:0px 0px %1px 0px;padding-bottom:%1px;padding-top:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
} else if (position == "left") {
strBorder = QString("border-width:0px 0px 0px %1px;padding-left:%1px;padding-right:%2px;")
.arg(borderWidth).arg(borderWidth * 2);
}
//如果圖標是左側顯示則需要讓沒有選中的按鈕左側也有加深的邊框,顏色為背景顏色
//如果圖標在文字上面而設置的邊框是 top bottom 也需要啟用加深邊框
QStringList qss;
if (styleColor.defaultBorder) {
qss << QString("QWidget[flag=\"%1\"] QAbstractButton{border-style:solid;border-radius:0px;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.normalBgColor).arg(styleColor.normalTextColor).arg(styleColor.normalBgColor);
} else {
qss << QString("QWidget[flag=\"%1\"] QAbstractButton{border-style:none;border-radius:0px;padding:5px;color:%2;background:%3;}")
.arg(position).arg(styleColor.normalTextColor).arg(styleColor.normalBgColor);
}
//懸停+按下+選中
qss << QString("QWidget[flag=\"%1\"] QAbstractButton:hover{border-style:solid;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.borderColor).arg(styleColor.hoverTextColor).arg(styleColor.hoverBgColor);
qss << QString("QWidget[flag=\"%1\"] QAbstractButton:pressed{border-style:solid;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.borderColor).arg(styleColor.pressedTextColor).arg(styleColor.pressedBgColor);
qss << QString("QWidget[flag=\"%1\"] QAbstractButton:checked{border-style:solid;%2border-color:%3;color:%4;background:%5;}")
.arg(position).arg(strBorder).arg(styleColor.borderColor).arg(styleColor.checkedTextColor).arg(styleColor.checkedBgColor);
//窗體背景顏色+按鈕背景顏色
qss << QString("QWidget#%1{background:%2;}")
.arg(widget->objectName()).arg(styleColor.normalBgColor);
qss << QString("QWidget>QAbstractButton{border-width:0px;background-color:%1;color:%2;}")
.arg(styleColor.normalBgColor).arg(styleColor.normalTextColor);
qss << QString("QWidget>QAbstractButton:hover{background-color:%1;color:%2;}")
.arg(styleColor.hoverBgColor).arg(styleColor.hoverTextColor);
qss << QString("QWidget>QAbstractButton:pressed{background-color:%1;color:%2;}")
.arg(styleColor.pressedBgColor).arg(styleColor.pressedTextColor);
qss << QString("QWidget>QAbstractButton:checked{background-color:%1;color:%2;}")
.arg(styleColor.checkedBgColor).arg(styleColor.checkedTextColor);
//設置樣式表
widget->setStyleSheet(qss.join(""));
//可能會重復調用設置所以先要移除上一次的
for (int i = 0; i < btnCount; i++) {
for (int j = 0; j < this->btns.count(); j++) {
if (this->btns.at(j) == btns.at(i)) {
disconnect(btns.at(i), SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
this->btns.at(j)->removeEventFilter(this);
this->btns.removeAt(j);
this->pixNormal.removeAt(j);
this->pixHover.removeAt(j);
this->pixPressed.removeAt(j);
this->pixChecked.removeAt(j);
break;
}
}
}
//存儲對應按鈕對象,方便鼠標移上去的時候切換圖片
int checkedIndex = -1;
for (int i = 0; i < btnCount; i++) {
int icon = icons.at(i);
QPixmap pixNormal = getPixmap1(styleColor.normalTextColor, icon, iconSize, iconWidth, iconHeight);
QPixmap pixHover = getPixmap1(styleColor.hoverTextColor, icon, iconSize, iconWidth, iconHeight);
QPixmap pixPressed = getPixmap1(styleColor.pressedTextColor, icon, iconSize, iconWidth, iconHeight);
QPixmap pixChecked = getPixmap1(styleColor.checkedTextColor, icon, iconSize, iconWidth, iconHeight);
//記住最后選中的按鈕
QAbstractButton *btn = btns.at(i);
if (btn->isChecked()) {
checkedIndex = i;
}
btn->setIcon(QIcon(pixNormal));
btn->setIconSize(QSize(iconWidth, iconHeight));
btn->installEventFilter(this);
connect(btn, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
this->btns << btn;
this->pixNormal << pixNormal;
this->pixHover << pixHover;
this->pixPressed << pixPressed;
this->pixChecked << pixChecked;
}
//主動觸發一下選中的按鈕
if (checkedIndex >= 0) {
QMetaObject::invokeMethod(btns.at(checkedIndex), "toggled", Q_ARG(bool, true));
}
}