這篇博文主要講述360安全衛士工具欄的創建;工具欄由圖片和文字組成,當鼠標移到工具欄按鈕上時,需要有些特征表達該現象,如背景色變化等;當然鼠標單擊工具欄按鈕時,同樣也要有些特征,並且這個特征區別於鼠標移到按鈕上的特征;寫起來有些拗口,我給大家先看看我實現的效果圖。

單擊按鈕時和鼠標移到按鈕上時,按鈕背景會不同,並且單擊其他按鈕時,已單擊的那個按鈕背景應該恢復。下面講解其具體實現。
一、工具欄的創建
工具欄當然是自定義的部件了(繼承於QWidget),工具欄上的那些按鈕都是繼承於QToolButton;其中有9個按鈕,最右邊的是label;工具欄類的成員變量如下所示:
View Code
QList<MyBtn*> m_listMyBtnPoint;//自定義按鈕
QList<QString> m_listMyStr;//按鈕對應的文本
QLabel *m_pLabel;//label,顯示logo
首先當然是創建這些子部件了,和一般的沒啥區別:
View Code
//CreateWidget創建部件
void ToolBar::CreateWidget()
{
//文本例子
m_listMyStr<<"Examine"<<"KillTrojan"<<"CleanDust"<<"LeakRepair"<<"SysRepair"
<<"CleanCom"<<"FunFull"<<"SoftMan"<<"OptSpeed";
//創建toolbutton
for(int nIndex = 0;nIndex<WIDGET_CNT;++nIndex)
{
//圖像資源路徑
QString strImage = QString(":/image/%1.png").arg(nIndex+1);
//創建自定義QToolButton(MyBtn)
m_listMyBtnPoint.append(new MyBtn(strImage,m_listMyStr[nIndex],this));
//設置toolbutton的位置
m_listMyBtnPoint.at(nIndex)->move(nIndex*TOOLWIDGET_H+VALUE_DIS,0);
//該信號槽設置其他按鈕的按下狀態bool值
connect(m_listMyBtnPoint.at(nIndex),SIGNAL(signal_parent(void*)),this,SLOT(slot_set(void*)));
}
//創建label
m_pLabel = new QLabel(this);
m_pLabel->setPixmap(QPixmap(":/image/logo.png"));
}
工具欄里的按鈕和label都是手動定位(即設置位置信息),所以重寫了resizeEvent事件,在resizeEvent事件里進行部件定位,如下所示:
View Code
//resizeEvent
void ToolBar::resizeEvent (QResizeEvent * event)
{
//按鈕垂直居中
m_pLabel->move(rect().width()-m_pLabel->pixmap()->width()-VALUE_DIS,(rect().height()-m_pLabel->pixmap()->height())/2);
}
大家可能會想:在resizeEvent事件里只對label進行定位了,那其他9個按鈕了?因為其他9個按鈕都是從最左邊(也就是0)計算相對位移,而label是從最右邊計算的,通過rect()函數獲得工具欄的最右邊位置信息;按鈕在創建部件函數的時候就定位了位置,如果label也在那個時候定位位置的話是錯誤的,因為那是工具欄部件的大小是未知的,所以rect()函數返回的值也是未知的;當放在resizeEvent事件中進行處理時,工具欄部件顯示出來的時候,其大小都是可以確定的。
二、工具欄按鈕效果設置
工具欄按鈕繼承於QToolButton;首先是設置按鈕的基本顯示效果了,去掉Qt自帶的效果;包括文本顏色,文本字體,樣式大小等,這些在我前幾篇的博文中有講解;代碼如下所示:
View Code
//構造函數
MyBtn::MyBtn(const QString &strImage,const QString &strInfo,QWidget *parent):QToolButton(parent),
m_bOver(false),m_bPress(false),m_strImage(strImage),m_strInfo(strInfo)
{
//文本顏色
QPalette objPalette = palette();
objPalette.setColor(QPalette::ButtonText, QColor(220,220,220));
setPalette(objPalette);
//文本粗體
QFont &objFont = const_cast<QFont &>(font());
objFont.setWeight(QFont::Bold);
//樣式
setStyleSheet("QToolButton{border:0px;}");
//大小
setIconSize(QSize(TOOLICON_WH,TOOLICON_WH));
resize(TOOLWIDGET_W,TOOLWIDGET_H);
setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
//設置圖像文本
setIcon(QPixmap(strImage));
setText(strInfo);
//連接press信號槽,表示按鈕按下時
connect(this,SIGNAL(pressed()),this,SLOT(slot_pressed()));
}
OK,按鈕的基本效果就出來了,按鈕是透明的,只顯示圖片和文本,沒背景信息。
再一步就是設置鼠標移到按鈕上的效果了,鼠標移到按鈕上時,背景呈現立體的半透明效果;當鼠標移上去時,設置移動標志(m_bOver)為ture,當鼠標離開按鈕時,設置移動標志為false;然后各自update發出重繪事件請求即可。
View Code
//enterEvent--鼠標移到按鈕上事件
void MyBtn::enterEvent(QEvent *event)
{
SetOver(true);
}
//leaveEvent--鼠標離開按鈕事件
void MyBtn::leaveEvent(QEvent *event)
{
SetOver(false);
}
//SetOver
void MyBtn::SetOver(bool bEnable)
{
if(bEnable!=m_bOver)
{
//設置m_bOver標志位
m_bOver = bEnable;
//更新
update();
}
}
在重繪事件里會對bOver進行判斷來繪制鼠標移到按鈕上的效果,后面講解到重繪時再細節描述。
然后就是鼠標單擊按鈕時的效果了,和鼠標移到按鈕上的實現原理基本一樣;不過只是在槽函數中而不是由事件觸發了;信號和槽函數在構造函數中已經被連接上了,槽函數如下:
View Code
//slot_pressed--槽函數
void MyBtn::slot_pressed()
{
SetPress(true);
emit signal_parent(this);
}
其中SetPress函數即設置按下標志(m_bPress)然后發送重繪請求。
View Code
//SetPress
void MyBtn::SetPress(bool bEnable)
{
if(bEnable!=m_bPress)
{
//設置m_bOver標志位
m_bPress = bEnable;
//更新
update();
}
}
其中slot_pressed槽函數中發送了一個自定義信號signal_parent,在工具欄部件中會對該信號進行連接,其中信號的參數為按鈕對象的指針。工具欄部件連接該信號的槽函數為slot_set函數:
View Code
//槽函數
void ToolBar:: slot_set(void *pObject)
{
for(int nIndex = 0;nIndex<WIDGET_CNT;++nIndex)
{
if(m_listMyBtnPoint.at(nIndex)!=pObject)
{
m_listMyBtnPoint.at(nIndex)->SetPress(false);
}
}
}
總體意思是:例如有A,B,C三個按鈕在工具欄中,如果按下了A按鈕,這是按下B按鈕時,發送信號給工具欄,然后在工具欄對應的槽函數中進行指針值對比,如果不是B按鈕,就調用其他對應按鈕的SetPress函數,並設置為false,這樣A按鈕就沒有按下去的背景效果了(排他性)。
三、工具欄按鈕效果繪制
繪制當然要在按鈕的paintEvent事件處理函數中實現了,代碼如下所示,代碼注釋的很詳細,我就不多說了:
View Code
//重繪事件
void MyBtn::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
//如果按鈕被按下
if(m_bPress)
{
//繪制被按下時的效果
painterinfo(150,200,&painter);
}
else if(m_bOver)//如果按鈕沒有被按下並且鼠標移到按鈕上
{
//繪制鼠標移到按鈕上的按鈕效果
painterinfo(50,100,&painter);
}
//調用基類的重繪事件以顯示圖像文本等
QToolButton::paintEvent(event);
}
//繪制背景漸變
void MyBtn::painterinfo(int nTopPartOpacity,int nBottomPartOpacity,QPainter *pPainter)
{
//設置畫筆
QPen objPen(Qt::NoBrush,1);
pPainter->setPen(objPen);
//設置漸變畫刷
QLinearGradient objLinear(rect().topLeft(),rect().bottomLeft());
//頂部顏色和透明度
objLinear.setColorAt(0,QColor(150,150,150,nTopPartOpacity));
//中間顏色和透明度
objLinear.setColorAt(0.5,QColor(50,50,50,255));
//底部顏色和透明度
objLinear.setColorAt(1,QColor(100,100,100,nBottomPartOpacity));
QBrush objBrush(objLinear);
pPainter->setBrush(objBrush);
//畫圓角矩形
pPainter->drawRoundedRect(rect(),5,5);
}
OK,這篇博文就寫完了,下一篇博文主要講解標題欄和狀態欄的構建了。
