有時(shí)候我們需要根據(jù)按鈕的check狀態(tài)來(lái)設(shè)置按鈕的不同背景或者是實(shí)現(xiàn)不同的功能。關(guān)于Qt 中的四大按鈕——QCheckBox, QPushButton, QRadioButton, QToolButton,這四個(gè)按鈕都繼承自QAbstractButton,所以他們Check狀態(tài)的變化都由QAbstractButton來(lái)控制。要使用按鈕的Check狀態(tài)前提需要設(shè)置屬性checkable為true。
通常每次點(diǎn)擊按鈕都會(huì)改變按鈕的Check狀態(tài),看一下Qt如何實(shí)現(xiàn)的:
void QAbstractButton::nextCheckState()
This virtual handler is called when a button is clicked. The default implementation calls setChecked(!isChecked()) if the button isCheckable(). It allows subclasses to implement intermediate button states.
在按鈕設(shè)置checkable為true時(shí),當(dāng)按鈕被點(diǎn)擊的時(shí)候nextCheckState方法被調(diào)用,而默認(rèn)實(shí)現(xiàn)是調(diào)用setChecked(!isChecked())方法,也可以通過(guò)子類實(shí)現(xiàn)不同的按鈕狀態(tài)。
所以簡(jiǎn)單的來(lái)講在每次點(diǎn)擊按鈕的時(shí)候其實(shí)就是調(diào)用了setChecked(!isChecked())方法。
這里我重寫了QToolButton,并重寫了mousePressEvent、mouseReleaseEvent、nextCheckState、checkStateSet方法,并對(duì)pressed、clicked、released信號(hào)綁定了不同的槽:
connect(this, SIGNAL(pressed()), this, SLOT(onMousePress())); connect(this, SIGNAL(clicked()), this, SLOT(onMouseClicked())); connect(this, SIGNAL(released()), this, SLOT(onMouseRelease()));
點(diǎn)擊按鈕后輸出:
this is mousePressEvent Fuctionthis is onMousePress Fuctionthis is mouseReleaseEvent Fuctionthis is nextCheckState Fuctionthis is onMouseRelease Fuctionthis is onMouseClicked Fuction
根據(jù)上面的調(diào)用順序我們可以在相應(yīng)的地方去調(diào)用setChecked方法來(lái)設(shè)置按鈕的Check狀態(tài)。需要注意的是setChecked方法不是隨便用的。如果我們想每次按鈕點(diǎn)擊的時(shí)候都將按鈕的Check狀態(tài)設(shè)置為true,在mousePressEvent或者onMousePress或者mouseReleaseEvent方法中去調(diào)用setChecked(true),那么在nextCheckState方法中會(huì)調(diào)用setChecked(!isChecked());這樣的話每次點(diǎn)擊按鈕之后,按鈕的Check狀態(tài)都會(huì)設(shè)置為false。
關(guān)于checkStateSet方法的調(diào)用,看一下Qt中對(duì)這個(gè)方法的描述:
void QAbstractButton::checkStateSet()
This virtual handler is called when setChecked() is used, unless it is called from within nextCheckState(). It allows subclasses to reset their intermediate button states.
當(dāng)調(diào)用setChecked方法時(shí)會(huì)自動(dòng)調(diào)用checkStateSet方法,而在nextCheckState方法中調(diào)用setChecked方法時(shí)則不會(huì)調(diào)用。當(dāng)然在checkStateSet方法內(nèi)部調(diào)用setChecked方法的話也會(huì)自動(dòng)調(diào)用本身,會(huì)導(dǎo)致進(jìn)入到一個(gè)死循環(huán)中導(dǎo)致程序崩潰,所以不能在checkStateSet內(nèi)部設(shè)置按鈕Check狀態(tài)。
我們?cè)诮oQToolButton進(jìn)行設(shè)置setPopupMode(QToolButton::MenuButtonPopup);(帶彈出式菜單)時(shí),再設(shè)置一個(gè)菜單變量setMenu(m_menu); 這樣在我們點(diǎn)擊QToolButton菜單區(qū)域部分會(huì)彈出自定義菜單,如下圖:
但是這樣我們點(diǎn)擊QToolButton菜單區(qū)域部分只能彈出之前設(shè)置的菜單,沒(méi)有可拓展性。所以我們可以獲取QToolButton右邊菜單的區(qū)域,在鼠標(biāo)點(diǎn)擊這塊區(qū)域時(shí)我們可以有不同的實(shí)現(xiàn)。下面是在mousePressEvent中獲取到QToolButton菜單區(qū)域,然后判斷當(dāng)前鼠標(biāo)是否點(diǎn)擊在該區(qū)域中。
void MyToolButton::mousePressEvent(QMouseEvent *event){ QStyleOptionToolButton styleIOption; initStyleOption(&styleIOption); if (Qt::LeftButton == event->button() && MenuButtonPopup == popupMode()) { // 獲取QToolButton右邊菜單按鈕的區(qū)域; QRect popupButtonRect = style()->subControlRect(QStyle::CC_ToolButton, &styleIOption, QStyle::SC_ToolButtonMenu, this); if (popupButtonRect.isValid() && popupButtonRect.contains(event->pos())) { //在這里實(shí)現(xiàn)不同的功能,我這里是根據(jù)鼠標(biāo)點(diǎn)擊的位置顯示菜單 if (this->isChecked()) { m_menu->exec(event->globalPos()); } // 可以向外發(fā)出信號(hào) //emit signalToolMenuClicked(); } } qDebug() << "this is mousePressEvent Fuction"; QToolButton::mousePressEvent(event);}
下圖為根據(jù)鼠標(biāo)點(diǎn)擊的位置顯示菜單:
下圖為點(diǎn)擊菜單區(qū)域彈出窗口:
仔細(xì)看下圖的菜單小箭頭的顏色變化,不知道算不算上是QQ的一個(gè)bug。不過(guò)這只是一個(gè)小細(xì)節(jié),純屬好玩發(fā)現(xiàn)的。(鼠標(biāo)第一次點(diǎn)擊小箭頭變成黑色,再次點(diǎn)擊變成灰色,后面連續(xù)點(diǎn)擊任然是灰色,當(dāng)鼠標(biāo)離開(kāi)這個(gè)控件區(qū)域后,再次點(diǎn)擊變成黑色。也就是說(shuō)在每次鼠標(biāo)第一次進(jìn)入到菜單按鈕區(qū)域時(shí)點(diǎn)擊小箭頭會(huì)變黑色后面再次點(diǎn)擊變灰色,可能個(gè)人想法不同,實(shí)現(xiàn)方案也不同。
聯(lián)系客服