Qt之自定义检索框

1、效果展示

今天这篇文章主要讲解的是自定义搜索框,不仅仅支持搜索,而且可以支持搜索预览,具体请看效果图1。网上也有一些比较简单明了的自定义搜索框,比如Qt之自定义搜索框,讲的也比较详细,不过本文的侧重点不仅仅是搜索,而且包括了检索功能。有兴趣的小伙伴可以看下步骤3的思路讲解。

图1 自定义搜索框

2、功能分析

这个自定义搜索框支持输入一定的数据源,然后通过检索窗口进行搜索数据,匹配到的数据会优先展示到预览下拉框,预览窗口支持hover高亮整行。仔细阅读demo源码的同学可能就会发现其实这个搜搜框的左侧又一个按钮是可以点击的,但是目前还没有添加具体的点击功能。了解了这个控件的功能之后,如果觉得对你有用,那么就可以接着继续往下看实现流程。

3、思路讲解

问题分析:

1、数据源存储在哪儿?怎么实现检索

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

3、鼠标hover状态的颜色设置?

首先在讲解源码之前,我抛出了3个问题,有精力的同学可以先思考下这几个问题,然后在接着往下看,下边我也会逐一说明这个些问题。

源码讲解:

1、使用到的类:

StockSortFilterProxyModel:过滤数据源,该model上的数据索引直接供视图展示
StockTableView:自定义视图,用于显示预览数据
StockListWidget:自定义搜索框
StockItemDelegate:自定义委托,提供自定义绘图

上边4个类是完成自定义搜索框的自定义类,当然除了上述4个类以外,还用到了qt自带的一些类,更好的理解这些类,那么这个自定义控件的思路也就显得异常好理解。

2、头文件说明

  • 委托:负责视图绘制
 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 };

3、窗口布局:

窗口布局:也就是这个检索框长什么样子,效果展示图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     });

4、数据存储

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 }

5、视图显示

关于视图显示,主要是视图显示位置和显示时机

显示时机:编辑框内容发现变化的时候显示,编辑框失去焦点的时候隐藏,这样也就存在一个问题,当主窗口拖动时,视图位置更新怎么做?

显示位置:当主窗口位置移动时,更新视图位置,这个方法看一参考qt捕获全局windows消息

6、视图背景色

视图背景色在添加数据源的时候设置了默认背景色,在后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 }

4、相关文章

5、demo下载链接:

Qt之自定义检索框

时间: 2024-10-03 10:55:47

Qt之自定义检索框的相关文章

Qt之自定义搜索框——QLineEdit里增加一个Layout,还不影响正常输入文字(好像是一种比较通吃的方法)

简述 关于搜索框,大家都经常接触.例如:浏览器搜索.Windows资源管理器搜索等. 当然,这些对于Qt实现来说毫无压力,只要思路清晰,分分钟搞定. 方案一:调用QLineEdit现有接口 void addAction(QAction * action, ActionPosition position) 在QLineEdit的前/后添加部件,ActionPosition表示部件所在方位. QAction * addAction(const QIcon & icon, ActionPosition

qt之自定义提示框(不规则提示框,右下角弹窗)

http://blog.sina.com.cn/s/blog_a6fb6cc90101e4r8.html http://blog.sina.com.cn/s/blog_a6fb6cc90101dtav.html

Qt之自定义托盘(二)

上一篇文章讲述了自定义Qt托盘,不过不是使用QSystemTrayIcon这个类,而是我们自己完全自定义的一个类,我们只需要处理这个类的鼠标hover.鼠标左键点击.鼠标右键点击和鼠标左键双击,就可以完全模拟出qq的托盘样式来.文章的最后我也是提供了一个demo的下载链接,那是一个可以完全运行的demo,处理了鼠标hover事件,并模拟出了鼠标离开和进入事件,这一节我将一步一步讲解怎么实现一个完美的托盘,包括托盘菜单的显示.托盘tooltip和托盘hover时的弹框显示. 看本片文章之前,同学们

自定义提示框

思路 利用VA_LIST可变参数,自定义欲提醒信息. 1 // 信息提示框 2 void CDECL AlertBox(TCHAR *Format, ...) 3 { 4 TCHAR buf[1024]; 5 va_list pArglist; 6 va_start(pArglist, Format); 7 _vsntprintf_s(buf, sizeof(buf)/sizeof(TCHAR), Format, pArglist); 8 va_end(pArglist); 9 MessageB

101在检索框中添加一个书签按钮(扩展知识:在检索框中添加一个范围条)

效果如下: ViewController.h 1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UITableViewController<UISearchBarDelegate> 4 @property (strong, nonatomic) UISearchBar *searchBar; 5 @property (strong, nonatomic) NSMutableArray *mArrDataSourceO

098在屏幕中实现一个检索框效果

效果如下: ViewController.h 1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UITableViewController<UISearchBarDelegate> 4 @property (strong, nonatomic) UISearchBar *searchBar; 5 @property (strong, nonatomic) NSMutableArray *mArrDataSourceO

简单的自定义弹框

作为初学者,很多人都是用的系统自带的弹框,非常的简单,完全不能满足用户的交互,所以这里,我们需要自定义一个弹框,把输入框.图片.按钮等添加到弹框里面.为了避免重复冗余的代码,参考了别人的代码,自己做了一个自定义弹框,可以在项目中使用到.给大家一个思路. 这是代码的接口定义,只需要调用一行代码就可以弹出一个自定义的视图啦.还会添加一些动画效果,让弹框弹出跟消失更美观. + (void)showPromptBoxWithCustomView:(UIView *)customView; + (void

“商城项目”自定义搜索框

1.要实现搜索的效果图如下:<功能:当输入关键字点击搜索按钮的时候在list上显示出来,点击商品进入商品详情页即可> 2>自定义搜索框,在导航栏视图上添加搜索视图,代码如下: 3>搜索结果的tableView,定义一个数组将解析数据的内容存取到数组中,将数组的个数加一,最后多得一行作为清除历史记录的一行 4>重要的一点就是:点击清除历史记录的时候,将保存到NSuserdefault的内容remove掉 5>最后将数据解析的内容传过去就行了,自定义搜索框就完成了. 注意点

swift 自定义弹框

// //  ViewController.swift //  animationAlert // //  Created by su on 15/12/9. //  Copyright © 2015年 tian. All rights reserved. // import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //灰色的遮挡板 let o