![]() |
![]() |
很重要--轉載聲明
- 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
- 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。
今天這篇文章主要講解的是自定義搜索框,不單單支持搜索,並且能夠支持搜索預覽,具體請看效果圖1。網上也有一些比較簡單明瞭的自定義搜索框,好比Qt之自定義搜索框 ,講的也比較詳細,不過本文的側重點不單單是搜索,並且包括了檢索功能。有興趣的小夥伴能夠看下步驟3的思路講解。html
圖1 自定義搜索框windows
這個自定義搜索框支持輸入必定的數據源,而後經過檢索窗口進行搜索數據,匹配到的數據會優先展現到預覽下拉框,預覽窗口支持hover高亮整行。仔細閱讀demo源碼的同窗可能就會發現其實這個搜搜框的左側又一個按鈕是能夠點擊的,可是目前尚未添加具體的點擊功能。瞭解了這個控件的功能以後,若是以爲對你有用,那麼就能夠接着繼續往下看實現流程。less
問題分析:ide
一、數據源存儲在哪兒?怎麼實現檢索佈局
二、彈出式下拉框顯示和隱藏控制?位置同步?post
三、鼠標hover狀態的顏色設置?this
首先在講解源碼以前,我拋出了3個問題,有精力的同窗能夠先思考下這幾個問題,而後在接着往下看,下邊我也會逐一說明這個些問題。url
源碼講解:spa
一、使用到的類:.net
StockSortFilterProxyModel:過濾數據源,該model上的數據索引直接供視圖展現
StockTableView:自定義視圖,用於顯示預覽數據
StockListWidget:自定義搜索框
StockItemDelegate:自定義委託,提供自定義繪圖
上邊4個類是完成自定義搜索框的自定義類,固然除了上述4個類之外,還用到了qt自帶的一些類,更好的理解這些類,那麼這個自定義控件的思路也就顯得異常好理解。
二、頭文件說明
1 class IView; 2 3 struct StockItemDelegatePrivate 4 { 5 int column = 1;//進度條所在列,下標從0開始 6 QTableView * parent = nullptr; 7 IView * view = nullptr; 8 }; 9 10 class StockItemDelegate : public QStyledItemDelegate 11 { 12 Q_OBJECT 13 14 public: 15 StockItemDelegate(QTableView * parent = nullptr); 16 ~StockItemDelegate(){}; 17 18 public: 19 void setView(IView * view); 20 21 protected: 22 virtual void paint(QPainter * painter 23 , const QStyleOptionViewItem & option 24 , const QModelIndex & index) const Q_DECL_OVERRIDE; 25 26 virtual QSize sizeHint(const QStyleOptionViewItem &option, 27 const QModelIndex &index) const Q_DECL_OVERRIDE; 28 29 private: 30 QScopedPointer<StockItemDelegatePrivate> d_ptr; 31 };
1 class IView 2 { 3 public: 4 virtual void SetMouseOver(int) = 0; 5 }; 6 7 class StockTableView : public QTableView, public IView 8 { 9 Q_OBJECT 10 public: 11 StockTableView(QStandardItemModel * model, QWidget * parent = 0); 12 13 public: 14 void SetMouseOver(int); 15 16 protected: 17 virtual void mouseMoveEvent(QMouseEvent * event) override; 18 virtual void leaveEvent(QEvent * event) override; 19 virtual void mousePressEvent(QMouseEvent * event) override; 20 21 private: 22 int currHovered; 23 void disableMouseOver(); 24 25 private: 26 QStandardItemModel * m_pSourceModel; 27 }; 28 29 struct StockListWidgetPrivate; 30 31 class StockListWidget : public QWidget, public QAbstractNativeEventFilter 32 { 33 Q_OBJECT 34 35 public: 36 StockListWidget(QWidget * parent = nullptr); 37 ~StockListWidget(); 38 39 public slots: 40 void NativeParentWindowMove(); 41 42 protected: 43 virtual void moveEvent(QMoveEvent * event) override; 44 virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result) override; 45 46 private: 47 void InitializeUI(); 48 49 private: 50 QScopedPointer<StockListWidgetPrivate> d_ptr; 51 };
1 class StockSortFilterProxyModel : public QSortFilterProxyModel 2 { 3 Q_OBJECT 4 5 public: 6 StockSortFilterProxyModel(QObject *parent = nullptr); 7 ~StockSortFilterProxyModel(); 8 9 void SetFilterContext(const QString & pattern); 10 11 protected: 12 bool lessThan(const QModelIndex &left 13 , const QModelIndex &right) const; 14 bool filterAcceptsRow(int source_row 15 , const QModelIndex & source_parent) const; 16 private: 17 size_t sortColumn = 0; 18 };
三、窗口布局:
窗口布局:也就是這個檢索框長什麼樣子,效果展現圖1中就能夠看到,在這個dmeo中,也就是StockListWidget類,該類使用了一個水平佈局添加了按鈕和文本輸入框。當文本輸入框內容發生變化時,啓動檢索,而後刷新視圖上的數據,具體看源碼
1 connect(d_ptr->m_pSearchLineEdit, &QLineEdit::textChanged, this, [this](const QString & text){ 2 if (d_ptr->m_pFilterModel) 3 { 4 d_ptr->m_pFilterModel->SetFilterContext(text);//根據檢索內容刷新model 5 } 6 if (d_ptr->m_pStockPreviewWidget) 7 { 8 d_ptr->m_pStockPreviewWidget->move(d_ptr->m_pTitleWidget->mapToGlobal(QPoint(0, d_ptr->m_pTitleWidget->height()))); 9 int rowHeight = d_ptr->m_pStockPreview->rowHeight(0); 10 int rowCount = d_ptr->m_pFilterModel->rowCount(); 11 d_ptr->m_pStockPreviewWidget->setFixedHeight(rowHeight * rowCount > DropWidgetMaxHeight ? DropWidgetMaxHeight : rowHeight * rowCount); 12 d_ptr->m_pStockPreviewWidget->show();//修正view高度,挪動位置並顯示 13 } 14 });
四、數據存儲
qt提供了一些列的model來供咱們使用,有能夠存放數據的,也有一些只供咱們使用接口的,在這個demo中我使用的是QStandardItemModel,他能夠存儲咱們所須要檢索的源數據,而後qt還提供了一個檢索model,QSortFilterProxyModel,我繼承該model能夠作本身想作的檢索實現,而後把檢索到的數據索引通知到視圖,這樣就完成了數據更新,具體關聯代碼以下:
1 StockItemDelegate * itemDelegate = new StockItemDelegate(d_ptr->m_pStockPreview); 2 d_ptr->m_pStockPreview->setItemDelegate(itemDelegate); 3 itemDelegate->setView(d_ptr->m_pStockPreview);//委託關聯到視圖上,負責數據繪製 4 5 d_ptr->m_pStockPreviewWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::Popup); 6 7 d_ptr->m_pFilterModel->setSourceModel(d_ptr->m_pListModel);//檢索model檢索的數據源設置 8 d_ptr->m_pStockPreview->setModel(d_ptr->m_pFilterModel);//視圖展現的model爲檢索後的model
數據檢索實現,我匹配的是每一列是否爲須要的值,也就是若是這一行中某一列知足要求都認爲該行知足要求
1 bool StockSortFilterProxyModel::filterAcceptsRow(int source_row 2 , const QModelIndex & source_parent) const 3 { 4 QRegExp regExp = filterRegExp(); 5 bool result = false; 6 for (int i = 0; i < sortColumn; ++i)//循環匹配全部的列,有一列知足要求就返回true 7 { 8 QModelIndex index = sourceModel()->index(source_row, i, source_parent); 9 QString context = sourceModel()->data(index).toString(); 10 11 if (regExp.isEmpty() == false) 12 { 13 QString regExpStr = regExp.pattern(); 14 result = regExp.exactMatch(context); 15 } 16 17 if (result) 18 { 19 break; 20 } 21 } 22 23 return result; 24 }
五、視圖顯示
關於視圖顯示,主要是視圖顯示位置和顯示時機
顯示時機:編輯框內容發現變化的時候顯示,編輯框失去焦點的時候隱藏,這樣也就存在一個問題,當主窗口拖動時,視圖位置更新怎麼作?
顯示位置:當主窗口位置移動時,更新視圖位置,這個方法看一參考qt捕獲全局windows消息。
六、視圖背景色
視圖背景色在添加數據源的時候設置了默認背景色,在後hover的時候從新設置背景色,hover失效後再恢復默認背景色,實現行hover代碼以下:
1 void StockTableView::SetMouseOver(int row) 2 { 3 if (row == currHovered) 4 { 5 return; 6 } 7 8 StockSortFilterProxyModel * sortModel = static_cast<StockSortFilterProxyModel *>(model()); 9 if (sortModel->rowCount() <= row) 10 { 11 return; 12 } 13 for (int col = 0; col < sortModel->columnCount(); col++)//循環遍歷,設置指定行中每個item的背景色 14 { 15 QModelIndex index = sortModel->index(row, col); 16 if (index.isValid()) 17 { 18 if (QStandardItem * item = m_pSourceModel->itemFromIndex(sortModel->mapToSource(index))) 19 { 20 item->setBackground(QBrush(QColor(43, 92, 151))); 21 } 22 } 23 } 24 25 if (currHovered != -1) 26 { 27 disableMouseOver();//恢復以前hover的行 28 } 29 currHovered = row; 30 }