Qt之自定義檢索框

一、效果展現

    今天這篇文章主要講解的是自定義搜索框,不單單支持搜索,並且能夠支持搜索預覽,具體請看效果圖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 };
  • 窗口布局:StockTableView是專門用來展現檢索後的數據,StockListWidget是窗口布局
 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 }

四、相關文章

五、demo下載連接:

     Qt之自定義檢索框

若是您以爲文章不錯,不妨給個 打賞,寫做不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。 

相關文章
相關標籤/搜索