詳解QListWidget如何實(shí)現(xiàn)自定義Item效果
首先,我們來看以下實(shí)現(xiàn)的最終效果吧!
我覺得這并不是一個很難得問題,最近新招了一個應(yīng)屆生,發(fā)現(xiàn)在實(shí)現(xiàn)上述效果時,被困擾住了,是不是剛剛接觸Qt的這種稍微有難度的界面時,都會有些無頭緒呢?
所以,我打算分享給大家實(shí)現(xiàn)的思路,以及會出現(xiàn)的問題,就我一個開發(fā)5年C++的員工而言,針對新手會遇到哪些不懂的問題。
當(dāng)前的開發(fā)環(huán)境:win10 VS2017 + Qt5.14.2 x64
在實(shí)現(xiàn)過程中新手會出現(xiàn)的難點(diǎn),如下
1:如何在QListWidget中添加帶有按鈕、文本等其它控件的一條數(shù)據(jù)?
2:選中每一條之后如何響應(yīng)?QListWidget自帶的item響應(yīng)為什么不生效?
3:如何選中刪除按鈕并通知QListWidget做出具體的響應(yīng)?
就根據(jù)上述三個問題,邊講述問題邊實(shí)現(xiàn)帶有自定義控件的Item內(nèi)容吧!
在使用QListWidget插入一條數(shù)據(jù)時,默認(rèn)的方式,如下:
ui.listWidget->insertItem(0, "Text Content"); //方法1 ui.listWidget->addItem("Text Content"); //方法2
使用上述代碼是無法實(shí)現(xiàn)的,因?yàn)閰?shù)中只能添加QString類型的字符串,那么該如何實(shí)現(xiàn)添加自定義項(xiàng)呢?
在QListWidget類中提供了叫做QListWidgetItem的子類,用于實(shí)現(xiàn)自定義的item。
這時,我們就需要重新定義一個類,并且將該類與ListWidgetItem進(jìn)行綁定,就可以實(shí)現(xiàn)每一行的item上展示屬于我們自定義的格式了。
例子中展示的item中顯示了一個選擇框、文件名稱以及刪除按鈕。
在這里,采用了QCheckBox以及QPushButton兩個按鈕實(shí)現(xiàn)的。
有人會詢問:文件名稱不應(yīng)該使用QLabel控件表示嗎?
回答是:當(dāng)前可以使用QLabel控件顯示文件名稱,這里采用QCheck主要是想要展示文件的圖標(biāo),根據(jù)不同的文件名后綴顯示不同的圖標(biāo)。
自定義Widget
該類繼承自QWidget。假設(shè)叫做:CustomItem
有些新手會直接創(chuàng)建一個純的C++類,這樣做肯定是有問題的,當(dāng)我們在外部使用當(dāng)前自定義類時,你會發(fā)現(xiàn),為什么新創(chuàng)建的類會單獨(dú)分出來呢?
如果直接使用純C++類,還有另一個至關(guān)重要的問題,當(dāng)前類需要進(jìn)行消息交互時,你該如何傳遞給外部調(diào)用者呢?回調(diào)嗎?是不是有點(diǎn)大材小用呢?
class CustomItem : public QWidget { Q_OBJECT public: CustomItem(QWidget *parent); ~CustomItem(); private: QCheckBox* m_checkName; //文件名 QCheckBox* m_checkSelect; //選擇 QPushButton* m_btnDelete; //刪除 };
自定義類CustomItem中創(chuàng)建了三個控件變量,分別表示了:選擇框、文件名稱以及刪除按鈕。
就是文章開始顯示效果圖的三個控件了。
接下來,需要定義一個外部調(diào)用接口,插入一條有效數(shù)據(jù),假設(shè)接口名稱是:AddINewtemData
class CustomItem : public QWidget { Q_OBJECT public: CustomItem(QWidget *parent); ~CustomItem(); public: //對外開放接口 void AddINewtemData(int nRow, QString qsFileName); //添加一條新數(shù)據(jù) private: int m_nRow; QCheckBox* m_checkName; //附件名 QCheckBox* m_checkSelect; //選擇 QPushButton* m_btnDelete; //刪除 };
AddINewtemData 參數(shù)
參數(shù)1:代表的是當(dāng)前自定義widget屬于QListWidget的行編號,用于后續(xù)消息傳遞使用。
參數(shù)2:需要展示的文件名稱
根據(jù)用戶傳入的文件名稱,根據(jù)文件后綴展示不同的圖標(biāo)。
void CustomItem::AddINewtemData(int nRow, QString qPath) { m_nRow = nRow; //記錄當(dāng)前自定義widget對應(yīng)的QListWidget的行號 //根據(jù)路徑名,獲取文件名稱,并設(shè)置 QFileInfo info(qPath); QString qsFileName = info.fileName(); m_checkName->setText(qsFileName); //獲取文件后綴 QString qsCheckStyle = ""; if (info.suffix() == "mp4") //視頻文件 { //自定義QCheckBox風(fēng)格 } else if (info.suffix() == "png") //圖片文件 { //自定義QCheckBox風(fēng)格 } else if (info.suffix() == "xlsx") //表格文件 { //自定義QCheckBox風(fēng)格 } else if (info.suffix() == "pdf") { //自定義QCheckBox風(fēng)格 } else //文檔文件 { //自定義QCheckBox風(fēng)格 } m_checkName->setStyleSheet(qsCheckStyle); }
構(gòu)造完自定義widget類之后,接下來就需要將該類與QListWidgetItem進(jìn)行綁定,顯示到QListWidget上去。
外部調(diào)用方法,如下:
int nCount = ui.listWidget->count(); CustomItem* widget = new CustomItem(this); widget->AddINewtemData(nCount, qsFileName); widget->show(); QListWidgetItem* item = new QListWidgetItem; item->setSizeHint(QSize(48, 48)); ui.listWidget->addItem(item); ui.listWidget->setItemWidget(item, widget);
自定義CustomItem響應(yīng)
上述功能可以實(shí)現(xiàn)QListWidget中展示自定義的widget之后,該如何點(diǎn)擊QListWidget中的每一條做出不同的響應(yīng)呢?
此時,我們對每一行的QListWigetItem綁定自定義類之后,是無法響應(yīng)QListWidget自身的選擇消息的!這一點(diǎn)需要大家記清楚了。
那么,該怎么觸發(fā)呢?
針對于每一個QWidget類,只要是繼承自QWidget,都會有鼠標(biāo)的四大響應(yīng):
virtual void mousePressEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseDoubleClickEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event);
當(dāng)鼠標(biāo)在自定義類做了點(diǎn)擊效果后,肯定可以在鼠標(biāo)按下事件中獲取點(diǎn)擊響應(yīng)的。
所以,在自定義類CustomItem中需要重寫QWidget的系統(tǒng)消息:mousePressEvent
void CustomItem::mousePressEvent(QMouseEvent *event) { QWidget::mousePressEvent(event); }
斷點(diǎn)設(shè)在該響應(yīng)函數(shù)中時,肯定是會觸發(fā)的,如果不可以肯定是當(dāng)前widget處于禁用狀態(tài),或者是被遮蓋住了。
這里還有一個隱藏問題:有些同學(xué)在點(diǎn)擊自定義窗口時會發(fā)現(xiàn)這樣一個奇怪的現(xiàn)象,為什么點(diǎn)擊有些區(qū)域是響應(yīng)mousePressEvent消息的,而點(diǎn)擊有些區(qū)域是不響應(yīng)呢?
以下是重中之重了??!
這就是前一段話提到的內(nèi)容了,當(dāng)前widget不觸發(fā)時,肯定是禁用或者是被遮擋住了。
在我們這個自定義Widget中有三個活躍的控件,兩個QCheck,一個QPushButton,當(dāng)我們的鼠標(biāo)在任意控件上點(diǎn)擊時,此時的點(diǎn)擊響應(yīng)應(yīng)該是響應(yīng)到子控件上,而不是自定義的Widget(CustomItem)上。
為了讓鼠標(biāo)點(diǎn)擊任何控件時,所有的響應(yīng)都響應(yīng)到父類Widget,也就是CustomItem上時,我們應(yīng)該對支持鼠標(biāo)響應(yīng)操作的控件做特殊處理
setAttribute(Qt::WA_TransparentForMouseEvents)
每個控件都要設(shè)置以上的操作,當(dāng)前控件只是用來顯示,不做任何消息處理,是當(dāng)前窗口做的消息處理
自定義Widget控件響應(yīng)并通知外界處理
下面,來說一說第三個重點(diǎn)問題,如何通知外界處理。
我們使用了自定義的Widget之后就不能再使用QListWidget的內(nèi)部選中消息了,為了讓外部窗口獲取內(nèi)部Widget的消息時,此時我們需要采用發(fā)信號的方式,通知外界,模擬QListWidget消息。
signals: void Msg_SendDeleteItemData
外部窗口直接操作該消息,使用方法跟普通的方法一致,這里就不再過多介紹Qt中消息機(jī)制了。
以上實(shí)現(xiàn)QListWidget內(nèi)嵌自定義窗口的核心功能就說清楚了。
到此這篇關(guān)于詳解QListWidget如何實(shí)現(xiàn)自定義Item效果的文章就介紹到這了,更多相關(guān)QListWidget自定義Item內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Eclipse對printf()不能輸出到控制臺的快速解決方法
Eclipse對printf()不能輸出到控制臺的快速解決方法。需要的朋友可以過來參考下,希望對大家有所幫助2013-10-10