上一篇文章Qt之QComboBox定制讲到了qt实现自定义的下拉框,该篇文章主要实现了列表式的下拉框,这一节我还将继续讲解QComboBox的定制,而这一节我将会讲述更高级的用法,不仅仅是下拉列表框,而可以实现下拉框为表格,原理其实上一篇文章中的列表框类似,不过在这篇文章我将会重点讲述一下不同的地方,好了,下边我先截取一下demo中的运行效果图,如图1所示,效果并不是那么美观,不过确实有很大的用处。

Qt之QComboBox定制(二)

图1 表格下拉框

    看了上图中的展示,是不是觉得很眼熟,是的,同学你说对了,其实这个界面时仿照铁道部的地区选组框做出来的,只不过是效果上有所差异,而功能上基本差不多,上图中的标题栏我是为了实现透明的表头而故意设置透明的,设置透明也是我后边重点要说的,怎么实现下拉框的背景色透明。

    在文章的讲解开始前,我先截取下其他两个下拉框的截取,让有所期待的同学一睹为快。说实话,现在的下拉框并不是那么好看,不过用好了qss,这个就不是那么重要了,重要的是下拉框的交互功能,如图2是下拉框列表框,如图3是下拉框表格,不同于图1,图3是不支持根据表头切换内容的下拉框表格。

Qt之QComboBox定制(二)

图2 下拉框列表

Qt之QComboBox定制(二)

图3 下拉框表格

    首先声明一下,在看这篇文章的时候我默认同学们已经看过Qt之QComboBox定制这篇文章,我的代码都是在这个demo的基础上重构出来的,如果有什么疑问可以去这篇文章中看看,或者直接私信我。

    说起这个demo,我主要是按照两个路线来实现下拉框界面定制,列表和表格,所以我在实现的时候会分出这两个类来进行封装,然后在把他们的一些公有的操作提取出来,作为一层父类,也就是上文中所提到的博客中的combobox类。

    接下来就是代码时刻,demo我会在文章最后给出下载链接,因此文章中我只贴出关键的代码段,

1、首先先来理解下文章中关键的类,理解了这几个类,这个demo的骨架就清楚了

CComboBox:下拉框父类,实现了大多数的数据添加接口

CListPopupComboBox:下拉框列表,如图2

CCheckBoxHeaderView:水平表头,主要是自绘表头

CTablePopupComboBox:下拉框表格,如图3

CTableRowHeaderView:列表头

CCityComboBox:城市选择下拉框,如图1

2、demo中的注释也是主要集中在接口中,不过在这里我还是要在不厌其烦的说一下接口相关的东西,毕竟接口就像是人的眼睛,接口弄明白了才能正确使用。

 1 class CComboBox : public QWidget
 2 {
 3 public:
 4     CComboBox(CustomPopupComboBox::ItemType type, QWidget * parent = nullptr);
 5     ~CComboBox(){}
 6 
 7 public:
 8     //设置分隔符  默认为'|'
 9     void SetSeparatorSymbol(char symbol);
10     char GetSeparatorSymbol() const { return m_SeparatorSymbol; }
11 
12     //新增数据
13     void AddText(const QString & text);
14     void AddTexts(const QVector<QString> & items);
15 
16     //设置下拉框属性
17     void SetItemWidth(int width);
18     void SetItemHeight(int height);
19 
20     //设置最多可见条目数
21     void SetMaxVisibleCount(int count);
22 
23     //设置下拉框中项模式
24     void SetItemType(CustomPopupComboBox::ItemType type){ m_Type = type; }
25     CustomPopupComboBox::ItemType GetItemType() const { return m_Type; }
26 
27 protected:
28     virtual bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
29 
30 protected:
31     virtual void AddItem(const QString & text) = 0;
32     virtual void ResetItemWidth(int width) = 0;
33     virtual void ResetItemHeight(int height) = 0;
34 
35 protected:
36     QWidget * NewItem(const QString & text);
37 
38 protected:
39     CustomPopupComboBox::ItemType m_Type = CustomPopupComboBox::LabelItem;
40     char m_SeparatorSymbol = '|';//表格选择项分隔符
41     int m_ItemCount = 0;//表格总的项数
42     QString m_CurrentMemory;//当前选择字符串
43     QComboBox * m_ComboBox = nullptr;
44     QWidget * m_BottomWidget = nullptr;
45     QWidget * m_PopupWidget = nullptr;
46 
47     //定制项信息    
48     int m_ItemWidth = 150;
49     int m_ItemHeight = 45;//需要和css文件中的QComboBox QAbstractItemView::item{height:45px;}对应
50 
51 private:
52     void InitializeUI();
53 };

    上述代码中有几个保护的纯虚函数,这几个接口主要是在具体的下拉框类中实现,而该接口会在父类中被调用,其他public接口都是含有注释的,直接看代码应该也能看懂。

3、列表下拉框

 1 ///    说明:combobox定制  下拉框为单列数据,支持文本、单选和复选
 2 class CListPopupComboBox : public CComboBox
 3 {
 4     Q_OBJECT
 5 
 6 public:
 7     CListPopupComboBox(CustomPopupComboBox::ItemType type = CustomPopupComboBox::RadioItem, QWidget * parent = nullptr);
 8     ~CListPopupComboBox();
 9 
10 protected:
11     virtual bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
12 
13     //新增数据 CComboBox
14     virtual void AddItem(const QString & text) Q_DECL_OVERRIDE;
15     virtual void ResetItemWidth(int width) Q_DECL_OVERRIDE;
16     virtual void ResetItemHeight(int height) Q_DECL_OVERRIDE;
17 
18 private:
19     virtual void ConstructView();//列表定制
20 };

    实现了CComboBox类中的3个纯虚接口,主要是重置下拉框项的高度和宽度,还有增加项等接口。列表框增加项代码如下:

 1 void CListPopupComboBox::AddItem(const QString & text)
 2 {
 3     if (QListWidget * listWidget = dynamic_cast<QListWidget *>(m_PopupWidget))
 4     {
 5         QWidget * itemWidget = NewItem(text);
 6         //itemWidget->setStyleSheet(QString("QCheckBox {background-color:lightgray;}"
 7         //    "QCheckBox:checked{background-color:white;}"));
 8 
 9         itemWidget->setFixedSize(m_ItemWidth, m_ItemHeight);
10 
11         int pos = listWidget->count() - 1 < 0 ? 0 : listWidget->count() - 1;
12         listWidget->insertItem(pos, new QListWidgetItem());
13         listWidget->setItemWidget(listWidget->item(pos), itemWidget);
14     }
15 }

4、表格行表头定制

 1 ///    说明:table列表头定制
 2 class CCheckBoxHeaderView : public QHeaderView
 3 {
 4     Q_OBJECT
 5 public:
 6     CCheckBoxHeaderView(int checkColumnIndex,
 7         Qt::Orientation orientation,
 8         QWidget * parent = 0) :
 9         QHeaderView(orientation, parent)
10     {
11         m_checkColIdx = checkColumnIndex;
12     }
13 
14 public:
15     void UpdateSelectColumn(int);
16 
17 signals:
18     void SectionClicked(int);
19 
20 protected:
21     virtual void paintSection(QPainter * painter, const QRect &rect, int logicalIndex) const;
22     virtual void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE;
23 
24 private:
25     int m_checkColIdx;
26 };

    主要实现了表格行表头自绘制,绘制代码在paintSection接口中实现,具体绘制方式如下:

 1 void CCheckBoxHeaderView::paintSection(QPainter * painter, const QRect &rect, int logicalIndex) const
 2 {
 3     QRect r = rect;
 4     r.setTop(r.top() + 20);
 5     r.setLeft(r.left() - 35);
 6     painter->fillRect(r, Qt::white);
 7 
 8     if (logicalIndex == 0)
 9     {
10         r.setTop(r.top() - 20);
11         r.setHeight(20);
12         painter->drawPixmap(rect, QPixmap(QStringLiteral(":/combobox/Resources/bg.png")));
13     }
14     
15 
16     QString text = model()->headerData(logicalIndex, this->orientation(),
17         Qt::DisplayRole).toString();
18 
19     painter->setPen(QColor(239, 241, 241));
20     painter->drawLine(rect.bottomLeft(), rect.bottomRight());
21 
22     painter->setPen(QPen(QColor(Qt::red), 2));
23     if (logicalIndex == m_checkColIdx)
24     {
25 
26         QLine line(rect.bottomLeft() + QPoint(rect.width() / 3, 0), rect.bottomRight() - QPoint(rect.width() / 3, 0));
27         painter->drawLine(line);
28 
29         QFont font = painter->font();
30         font.setBold(true);
31         painter->setFont(font);
32     }
33 
34     painter->drawText(rect, Qt::AlignCenter, text);
35 }
View Code

相关文章: