天天看點

Qt之自定義檢索框

文章目錄

    • 1、效果展示
    • 2、功能分析
    • 3、思路講解
    • 4、相關文章
    • 5、demo下載下傳連結

1、效果展示

今天這篇文章主要講解的是自定義搜尋框,不僅僅支援搜尋,而且可以支援搜尋預覽,具體請看效果圖1。網上也有一些比較簡單明了的自定義搜尋框,比如Qt之自定義搜尋框 ,講的也比較詳細,不過本文的側重點不僅僅是搜尋,而且包括了檢索功能。有興趣的小夥伴可以看下步驟3的思路講解。

圖1 自定義搜尋框

Qt之自定義檢索框

2、功能分析

這個自定義搜尋框支援輸入一定的資料源,然後通過檢索視窗進行搜尋資料,比對到的資料會優先展示到預覽下拉框,預覽視窗支援hover高亮整行。仔細閱讀demo源碼的同學可能就會發現其實這個搜搜框的左側又一個按鈕是可以點選的,但是目前還沒有添加具體的點選功能。了解了這個控件的功能之後,如果覺得對你有用,那麼就可以接着繼續往下看實作流程。

3、思路講解

問題分析:

1、資料源存儲在哪兒?怎麼實作檢索

2、彈出式下拉框顯示和隐藏控制?位置同步?

3、滑鼠hover狀态的顔色設定?

首先在講解源碼之前,我抛出了3個問題,有精力的同學可以先思考下這幾個問題,然後在接着往下看,下邊我也會逐一說明這個些問題。

源碼講解:

1、使用到的類:

  • StockSortFilterProxyModel:過濾資料源,該model上的資料索引直接供視圖展示
  • StockTableView:自定義視圖,用于顯示預覽資料
  • StockListWidget:自定義搜尋框
  • StockItemDelegate:自定義委托,提供自定義繪圖

上邊4個類是完成自定義搜尋框的自定義類,當然除了上述4個類以外,還用到了qt自帶的一些類,更好的了解這些類,那麼這個自定義控件的思路也就顯得異常好了解。

2、頭檔案說明

委托:負責視圖繪制

class IView;

struct StockItemDelegatePrivate
{
    int column = 1;//進度條所在列,下标從0開始
    QTableView * parent = nullptr;
    IView * view = nullptr;
};

class StockItemDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    StockItemDelegate(QTableView * parent = nullptr);
    ~StockItemDelegate(){};

public:
    void setView(IView * view);

protected:
    virtual void paint(QPainter * painter
        , const QStyleOptionViewItem & option
        , const QModelIndex & index) const Q_DECL_OVERRIDE;

    virtual QSize sizeHint(const QStyleOptionViewItem &option,
        const QModelIndex &index) const Q_DECL_OVERRIDE;

private:
    QScopedPointer<StockItemDelegatePrivate> d_ptr;
};
           

視窗布局:StockTableView是專門用來展示檢索後的資料,StockListWidget是視窗布局

class IView
{
public:  
    virtual void SetMouseOver(int) = 0;
};

class StockTableView : public QTableView, public IView 
{
    Q_OBJECT
public:   
    StockTableView(QStandardItemModel * model, QWidget * parent = 0);
           
public:
    void SetMouseOver(int);

protected:
    virtual void mouseMoveEvent(QMouseEvent * event) override;
    virtual void leaveEvent(QEvent * event) override;
    virtual void mousePressEvent(QMouseEvent * event) override;

private:
    int currHovered;
    void disableMouseOver();

private:
    QStandardItemModel * m_pSourceModel;
};

struct StockListWidgetPrivate;

class StockListWidget : public QWidget, public QAbstractNativeEventFilter
{
    Q_OBJECT

public:
    StockListWidget(QWidget * parent = nullptr);
    ~StockListWidget();

public slots:
    void NativeParentWindowMove();

protected:
    virtual void moveEvent(QMoveEvent * event) override;
    virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result) override;

private:
    void InitializeUI();

private:
    QScopedPointer<StockListWidgetPrivate> d_ptr;
};
           

資料源:根據模式串比對檢索後的資料,并負責通知視圖進行更新展示

class StockSortFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT

public:
    StockSortFilterProxyModel(QObject *parent = nullptr);
    ~StockSortFilterProxyModel();

    void SetFilterContext(const QString & pattern);

protected:
    bool lessThan(const QModelIndex &left
                  , const QModelIndex &right) const;
    bool filterAcceptsRow(int source_row
                          , const QModelIndex & source_parent) const;
private:
    size_t sortColumn = 0;
};
           

3、視窗布局:

視窗布局:也就是這個檢索框長什麼樣子,效果展示圖1中就可以看到,在這個dmeo中,也就是StockListWidget類,該類使用了一個水準布局添加了按鈕和文本輸入框。當文本輸入框内容發生變化時,啟動檢索,然後重新整理視圖上的資料,具體看源碼

connect(d_ptr->m_pSearchLineEdit, &QLineEdit::textChanged, this, [this](const QString & text){
        if (d_ptr->m_pFilterModel)
        {
            d_ptr->m_pFilterModel->SetFilterContext(text);//根據檢索内容重新整理model
        }
        if (d_ptr->m_pStockPreviewWidget)
        {
            d_ptr->m_pStockPreviewWidget->move(d_ptr->m_pTitleWidget->mapToGlobal(QPoint(0, d_ptr->m_pTitleWidget->height())));
            int rowHeight = d_ptr->m_pStockPreview->rowHeight(0);
            int rowCount = d_ptr->m_pFilterModel->rowCount();
            d_ptr->m_pStockPreviewWidget->setFixedHeight(rowHeight * rowCount > DropWidgetMaxHeight ? DropWidgetMaxHeight : rowHeight * rowCount);
            d_ptr->m_pStockPreviewWidget->show();//修正view高度,挪動位置并顯示
        }
    });
           

4、資料存儲

qt提供了一些列的model來供我們使用,有可以存放資料的,也有一些隻供我們使用接口的,在這個demo中我使用的是QStandardItemModel,他可以存儲我們所需要檢索的源資料,然後qt還提供了一個檢索model,QSortFilterProxyModel,我繼承該model可以做自己想做的檢索實作,然後把檢索到的資料索引通知到視圖,這樣就完成了資料更新,具體關聯代碼如下:

StockItemDelegate * itemDelegate = new StockItemDelegate(d_ptr->m_pStockPreview);
    d_ptr->m_pStockPreview->setItemDelegate(itemDelegate);
    itemDelegate->setView(d_ptr->m_pStockPreview);//委托關聯到視圖上,負責資料繪制

    d_ptr->m_pStockPreviewWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::Popup);

    d_ptr->m_pFilterModel->setSourceModel(d_ptr->m_pListModel);//檢索model檢索的資料源設定
    d_ptr->m_pStockPreview->setModel(d_ptr->m_pFilterModel);//視圖展示的model為檢索後的model
           

資料檢索實作,我比對的是每一列是否為需要的值,也就是如果這一行中某一列滿足要求都認為該行滿足要求

bool StockSortFilterProxyModel::filterAcceptsRow(int source_row
                                              , const QModelIndex & source_parent) const
{
    QRegExp regExp = filterRegExp();
    bool result = false;
    for (int i = 0; i < sortColumn; ++i)//循環比對所有的列,有一列滿足要求就傳回true
    {
        QModelIndex index = sourceModel()->index(source_row, i, source_parent);
        QString context = sourceModel()->data(index).toString();

        if (regExp.isEmpty() == false)
        {
            QString regExpStr = regExp.pattern();
            result = regExp.exactMatch(context);
        }

        if (result)
        {
            break;
        }
    }

    return result;
}
           

5、視圖顯示

關于視圖顯示,主要是視圖顯示位置和顯示時機

顯示時機:編輯框内容發現變化的時候顯示,編輯框失去焦點的時候隐藏,這樣也就存在一個問題,當主視窗拖動時,視圖位置更新怎麼做?

顯示位置:當主視窗位置移動時,更新視圖位置,這個方法看一參考qt捕獲全局windows消息。

6、視圖背景色

視圖背景色在添加資料源的時候設定了預設背景色,在後hover的時候重新設定背景色,hover失效後再恢複預設背景色,實作行hover代碼如下:

void StockTableView::SetMouseOver(int row)
{
    if (row == currHovered)
    {
        return;
    }

    StockSortFilterProxyModel * sortModel = static_cast<StockSortFilterProxyModel *>(model());
    if (sortModel->rowCount() <= row)
    {
        return;
    }
    for (int col = 0; col < sortModel->columnCount(); col++)//循環周遊,設定指定行中每一個item的背景色
    {
        QModelIndex index = sortModel->index(row, col);
        if (index.isValid())
        {
            if (QStandardItem * item = m_pSourceModel->itemFromIndex(sortModel->mapToSource(index)))
            {
                item->setBackground(QBrush(QColor(43, 92, 151)));
            }
        }
    }

    if (currHovered != -1)
    {
        disableMouseOver();//恢複之前hover的行
    }
    currHovered = row;
}
           

4、相關文章

Qt之自定義搜尋框

qt捕獲全局windows消息

5、demo下載下傳連結

Qt之自定義檢索框

如果您覺得文章不錯,不妨給個 打賞,寫作不易,感謝各位的支援。您的支援是我最大的動力,謝謝!!!

Qt之自定義檢索框
Qt之自定義檢索框

很重要–轉載聲明

  1. 本站文章無特别說明,皆為原創,版權所有,轉載時請用連結的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利于轉載者的目的。

繼續閱讀