網站首頁 編程語言 正文
前沿
什么叫做自定義Widget實現互斥效果呢?
在使用Qt做一個界面美觀性比較強的功能時,可能會遇到這種問題:多個控件互斥,類似于QRadiButton控件,但又不是單純的QRadioButton控件,互斥的可能是一個窗口,也可能是幾個按鈕,等等多種情況。
這里我只是列舉了一個簡單的互斥例子,雖然簡單,但是包含了各種坑,有需要的掘友們可以小筆記們記一下,尤其是對Qt新手來說,還是很有必要的。
由效果圖可以看出創建了3個自定義widget,點擊其中一個時,另外兩個背景色以及文本顏色變化,處于選中狀態。
接下來,針對效果圖展示的功能進行逐一講解,包含了知識點以及踩坑記錄。
功能實現
實現自定義互斥widget過程中遇到了如下知識點以及問題,看看有沒有你曾經遇到的或者是剛好需要的功能吧!
知識點
1:Widget模擬按鈕的四態功能,包括了:常態、按下、聚焦、禁用
2:Widget自定義類的背景色設置以及文本內容風格設置
3:如何讓多個widget實現互斥效果
問題
1:自定義Widget背景色設置之后為什么不生效?
針對上述知識點以及問題來講述這個簡單的功能吧!
講解知識點1
使用Widget模擬按鈕的四態功能,需要用到Widget自身的消息:鼠標按下,鼠標進入、鼠標離開。
virtual void mousePressEvent(QMouseEvent *event); //鼠標按下響應消息 virtual void enterEvent(QEvent *event); //鼠標進入響應消息 virtual void leaveEvent(QEvent *event); //鼠標離開響應消息
有沒有人會問道,為什么沒有mouseMoveEvent消息?
解答:在Qt中直接使用mouseMoveEvent消息鼠標是無法觸發的,必須要設置setMouseTracking(true)讓鼠標跟蹤事件在當前窗口處于有效狀態。
根據使用的具體情況是否需要設置這個功能。當前的小demo中,只是做圖片的轉換,沒有必要在mouseMove中一直消耗資源。
(題外話:在MFC框架下的鼠標mosemove事件是直接可用的不需要進行特殊設置)
鼠標進入到widget之后,就可以標記為鼠標一直在該widget中活動,除非觸發了leaveEvent消息。
鼠標按下響應消息
void QCustomWidget::mousePressEvent(QMouseEvent *event) { this->SetWidgetStyle(Style_Down); QWidget::mousePressEvent(event); }
當前采用的枚舉類型:鼠標按下響應。
鼠標進入widget響應消息
void QCustomWidget::enterEvent(QEvent *event) { this->SetWidgetStyle(Style_Focus); QWidget::enterEvent(event); }
當前采用的枚舉類型:鼠標聚焦狀態,使用進入消息代替了mousemove消息。
如果大家打日志會發現,該觸發函數只會在鼠標進入的時候走一次,當鼠標持續在widget內部移動時是不觸發的,極大的減少了消息處理。
鼠標離開widget響應消息
void QCustomWidget::leaveEvent(QEvent *event) { this->SetWidgetStyle(Style_Normal); QWidget::leaveEvent(event); }
當前采用的枚舉類型:鼠標離開狀態。
我只是展示了最簡單的離開設置,有一點需要考慮,當前widget如果處于按下狀態,此刻鼠標離開了,該如何展示呢?
難道還要顯示常態風格嗎?
答案肯定是NO!
雖然鼠標已經移開,但是選中狀態已經由常態變成了按下狀態。在程序中我們需要用一個bool值變量來記錄當前widget是否已經被選中過,如果選中過,當鼠標離開時就需要更改為選中狀態
修改如下所示:
if (m_bClickedState == true) { this->SetWidgetStyle(Style_Down); } else this->SetWidgetStyle(Style_Normal);
講解知識點2
在程序中對于模擬的狀態采用了枚舉的類型進行表示。
類型 | 說明 |
---|---|
Style_Normal | 鼠標未做任何操作的初始狀態 |
Style_Down | 鼠標在wiget中進行了按下操作 |
Style_Focus | 鼠標在widget中進行移動時操作狀態 |
Style_Disable | 當前widget處于進行狀態 |
每一個widget中都展示了相同的內容:編號,文本
因為只是做了展示功能,所以全部使用了QLabel控件
QLabel *m_labNumber; //編號類指針
QLabel *m_LabContent; //內容類指針
對應的實際處理
void QCustomWidget::SetWidgetStyle(ENUM_WidgetStyle enumStyle) { //TODO:設置widget風格 QString qsStyle = "", gStyleNumberNormal = "", gStyleContentNormal = ""; switch (enumStyle) { case Style_Normal: //常態顯示 { //設置:背景 qsStyle = "QWidget{background-color:#FFD700}"; //設置:編號風格 gStyleNumberNormal = "QLabel{color:#666666; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; //設置:內容風格 gStyleContentNormal = "QLabel{color:#666666; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; } break; case Style_Down: //按下 { //設置:背景 qsStyle = "QWidget{background-color:#FFB6C1}"; //設置:編號風格 gStyleNumberNormal = "QLabel{color:#0000FF; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; //設置:內容風格 gStyleContentNormal = "QLabel{color:#00FFFF; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; } break; case Style_Focus: //聚焦 { //設置:背景 qsStyle = "QWidget{background-color:#FFF0F5}"; //設置:編號風格 gStyleNumberNormal = "QLabel{color:#98FB98; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; //設置:內容風格 gStyleContentNormal = "QLabel{color:#98FB98; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; } break; case Style_Disable: //禁用 { //設置:背景 qsStyle = "QWidget{background-color:#DCDCDC}"; //設置:編號風格 gStyleNumberNormal = "QLabel{color:#696969; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; //設置:內容風格 gStyleContentNormal = "QLabel{color:#696969; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}"; } break; default: break; } this->setStyleSheet(qsStyle); m_labNumber->setStyleSheet(gStyleNumberNormal); m_labContent->setStyleSheet(gStyleContentNormal); }
根據不同的類型對應的背景風格也不同。大家可以將代碼帶入,運行查看下效果,是不是跟我展示的效果一致呢?
哈哈!如果你嘗試了,就會發現是這個樣子的效果:
為什么只能顯示文字,我的背景呢?去了哪里?我不是已經設置了嗎?
很多Qt新手在這里都會遇到這樣的問題,于是開啟了各種搜索模式,嘗試各種方法,有的時候改著改著就對了,也就忽略了這個問題。
當我們創建一個自定義widget時,通用的方法使用new實例的方式,在new的過程中,為了層級關系好打理已經父子關系明確,都會傳入this作為新創建窗口的父指針。
一旦我們傳入了this指針之后,并未在自定義Widget中做任何處理時,此時就會出現這樣的情況。
子類繼承了父窗口的風格樣式。
一般遇到這種情況時,會有兩種處理方式:重寫當前窗口的paintEvent函數,設置不沿用父窗口風格
為了方便起見,當窗口繪制的背景圖不復雜的情況下都會采用第二種方式設置:
this->setAttribute(Qt::WA_StyledBackground);
在當前自定義widget類構造函數中設置上述代碼后,之前出現的設置了背景風格卻看不見的問題就迎刃而解了。
講解知識點3
如何實現多個widget之間的互斥呢?
使用過QRadioButton控件的掘友們都知道,該控件想要設置互斥只需要簡單的設置函數就可以了。
對于我們自定義的widget來說,是不存在這種函數的,互斥效果只能是手動用代碼設置并根據選中與非選中狀態來更換對應的展示效果。
假設,當前選中了“內容1”的自定義Widget,此時需要在Widget中鼠標按下響應中觸發一個消息,通知外界,當前自定義Widget做了按下操作,需要做特殊的處理
void QCustomWidget::mousePressEvent(QMouseEvent *event) { this->SetWidgetStyle(Style_Down); emit Msg_SendClicked(); QWidget::mousePressEvent(event); }
在調用自定義Widget的父類中響應對應的槽函數做特殊處理。
總結
到這里實現自定義Widget互斥效果就簡單實現了。
對于互斥操作的實現很簡單,最最需要掌握的就是如何設置widget的背景。
很多情況下子窗口與父窗口嵌套層級過多時,這種問題最容易出現了,因為我們在每次創建一個新widget對象時,最好的方式每次都不沿用父窗口的樣式。
原文鏈接:https://juejin.cn/post/7055446282013245471
相關推薦
- 2022-04-18 ASP.Net?Core?MVC基礎系列之獲取配置信息_基礎應用
- 2022-09-06 C語言超詳細講解指向函數的指針_C 語言
- 2022-09-08 Pytorch中expand()的使用(擴展某個維度)_python
- 2022-07-19 SpringCloud服務拆分初探與案例解析
- 2022-03-06 Android系統服務概覽_Android
- 2023-06-03 C/C++中#define的妙用分享_C 語言
- 2022-03-23 C語言實現貪吃蛇小黑窗_C 語言
- 2022-09-25 React組件的生命周期函數
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支