Qt之QComboBox 自定义实现多个ComboBox实时同步数据

      Qt自带的QComboBox只是给我们提供一个普遍性的控件,但是在实际的应用中往往根据不同的需求要求对控件做出不同的处理,这时候Qt自带控件往往满足不了我们的,所以我们可以根据自己的需求对控件进行重载,以下就是我对ComboBox的重载,先看实例:

Qt之QComboBox 自定义实现多个ComboBox实时同步数据_第1张图片

         对于QComboBox的重新定义,其实是利用到了QListWidget提供了一个接口:

 void setItemWidget(QListWidgetItem *item, QWidget *widget);

         在QComboBox中我们把QListWidget的model与view重新设置到ComboBox中去,这样我们只需要对QListWidget里面的数据进行修改后在ComboBox就可以看得到:

// 设置新的View Model
m_pList = new QListWidget;
this->setModel(m_pList->model());
this->setView(m_pList);

        如果我们想要实现不同的ComboBox实现数据的同步就需要在下拉框弹出来之前把数据准备好,这就需要我们对ComboBox的虚函数showPopup()进行重载了:

void MyComboBox::showPopup()
{
    QSettings ini(SettingPath, QSettings::IniFormat);

    // 先打开组,然后查找组里面所有的关键字再读取
    ini.beginGroup(group());

    // 读取标定数据
    MyComboBoxItem *item = NULL;
    QListWidgetItem *listItem = NULL;
    foreach (QString key, ini.allKeys())
    {
        listItem = new QListWidgetItem(m_pList);
        item = new MyComboBoxItem(key);
        connect(item, SIGNAL(deleteItem(QString)), this, SLOT(deleteItem(QString)));
        connect(item, SIGNAL(selectItem(QString)), this, SLOT(selectItem(QString)));

        m_pList->setItemWidget(listItem, item);
    }

    ini.endGroup();
    QComboBox::showPopup();
}

        因为我们每次都是在showPopup()进行数据的准备,所以我们也需要对虚函数hidePopup()进行重写,以便把内存释放,这两个刚好是一个相反的操作:

void MyComboBox::hidePopup()
{
    QComboBox::hidePopup();

    // 移除旧item
    QListWidgetItem *item = NULL;
    int iCount = m_pList->count();
    for (int i = iCount - 1; i >= 0 ; i--)
    {
        item = m_pList->takeItem(i);
        delete item;
    }    

    // 收起的时候编辑框数据会消失,所以需要重新设置
    setEditText(m_sText);
}

        而对于void setItemWidget(QListWidgetItem *, QWidget *)可以这样理解:在原本的QListWidgetItem 基础上不能满足我们的需求,所以需要对QListWidgetItem进行替换,替换为我们自定义的Widget也就是以上提到的MyComboBoxItem,至于这个类怎么样其实也很简单:

#ifndef MYCOMBOBOXITEM_H
#define MYCOMBOBOXITEM_H

#include 

class QLabel;
class QHBoxLayout;
class MyComboBoxItem : public QWidget
{
    Q_OBJECT
public:
    explicit MyComboBoxItem(QString text, QWidget *parent = 0);
    ~MyComboBoxItem();

    QString text();

signals:
    void deleteItem(QString text);
    void selectItem(QString text);

protected:
    void mousePressEvent(QMouseEvent *event);

private:
    QLabel      *m_pText;
    QLabel      *m_pDelete;
    QHBoxLayout *m_pLayout;
};

#endif // MYCOMBOBOXITEM_H
#include "MyComboBoxItem.h"

#include 
#include 
#include 


MyComboBoxItem::MyComboBoxItem(QString text, QWidget *parent) :
    QWidget(parent)
{    
    // 文本
    m_pText = new QLabel(text);

    // 删除
    QString style = "QLabel{border-image: url(:/Thumbnail/Thumbnail/delete.png)}"
                    "QLabel:hover{border-image: url(:/Thumbnail/Thumbnail/delete-hover.png)}";

    m_pDelete = new QLabel;
    m_pDelete->setFixedSize(16, 16);
    m_pDelete->setStyleSheet(style);

    // 布局
    m_pLayout = new QHBoxLayout;
    m_pLayout->addWidget(m_pText);
    m_pLayout->addStretch();
    m_pLayout->addWidget(m_pDelete);
    m_pLayout->setContentsMargins(5, 5, 5, 5);
    this->setLayout(m_pLayout);
}

MyComboBoxItem::~MyComboBoxItem()
{
    // 内存释放
    delete m_pText;
    delete m_pDelete;
    delete m_pLayout;
}

QString MyComboBoxItem::text()
{
    return m_pText->text();
}

void MyComboBoxItem::mousePressEvent(QMouseEvent *event)
{
    if (m_pDelete->geometry().contains(event->pos()))
    {
        // 点在删除上
        emit deleteItem(text());
    }
    else
    {
        // 选中这一项
        emit selectItem(text());
    }

    QWidget::mousePressEvent(event);
}

        在选中的时候我们发了一个选中信号也就是在showPopup()函数关联的,具体的操作我们只是把当前选中的显示出来然后关闭下拉框:

void MyComboBox::selectItem(QString text)
{
    m_sText = text;

    // 收起下拉项
    hidePopup();
}

        在删除的时候也是发了一个删除信号也就是在showPopup()函数关联的:

void MyComboBox::deleteItem(QString text)
{    
    // 从配置文件从移除这一项
    erase(text);

    // 删除的是否是当前选中的
    if (m_sText == text)
    {
        m_sText = QString();
    }

    // 收起下拉项
    hidePopup();
}

        erase()表示需要从文件中擦出某一项,因为删除了肯定要从文件中擦出,不然就达不到同步效果了:

void MyComboBox::erase(QString text)
{
    QSettings ini(SettingPath, QSettings::IniFormat);

    // 先打开组,然后查找组里面所有的关键字再读取
    ini.beginGroup(group());
    ini.remove(text);
    ini.endGroup();
    ini.sync();
}

        接着就是当我们编辑完毕后,我们需要把当前编辑的数据保存到文件中已达到同步效果,但在这之前我们怎么知道什么时候会编辑结束呢? 这就需要再分析一下了,虽然我们用的是ComboBox控件,但是ComboBox本身就是由几部分组成的其中编辑框控件就是其中一个,所以要知道什么时候编辑结束我们还需要从QComboBox里的QLineEdit控件着手,所以我找到了一个信号:

void editingFinished();

        所以我们需要添加一个相对应的槽函数:

connect(this->lineEdit(), SIGNAL(editingFinished()), this, SLOT(editingFinished()));
void MyComboBox::editingFinished()
{
    // 如果为空就不添加
    QString text = lineEdit()->text();
    if (text.isEmpty()) return;

    // 如果存在就不添加
    // 先打开组,然后查找组里面所有的关键字
    QStringList list;
    QSettings ini(SettingPath, QSettings::IniFormat);
    ini.beginGroup(group());
    list = ini.allKeys();
    ini.endGroup();
    if (list.contains(text)) return;

    // 写入数据
    write(text);
    setEditText(text);
}

        最后就是把新添加的数据写入文件了,达到实时同步的效果:

void MyComboBox::write(QString text)
{
    QSettings ini(SettingPath, QSettings::IniFormat);

    // 以当前标定名作为关键字
    ini.beginGroup(group());
    ini.setValue(text, QVariant());
    ini.endGroup();
    ini.sync();
}

        如有需要可自行扩展 ... ... 

        想要源码的朋友可以到这里下载: https://download.csdn.net/download/ilson_/11046413

你可能感兴趣的:(Qt)