QTableview常用几种代理总结

[1] QTableview常用几种代理总结

原文链接:https://blog.csdn.net/hu_linux/article/details/52791665

在项目中,我们经常使用到QTableview,由于业务需要,经常需要在QTableview中嵌入很多常用的控件,如:QSpinBox、QComboBox、QProcess、QDateTime、QPushButton、QLabel等。编写了一个小demo,先贴图看效果。

在这里插入图片描述

1、QCheckBox和QRadioButton的嵌入

QCheckBox可以直接在model中设置setCheckable(true)属性;

QRadionButton的嵌入可设置QTableview中setIndexWidget(const QModelIndex &, QWidget *)属性

 for(QList<CModelData *>::const_iterator iter = m_pModelDataList->begin(); iter != m_pModelDataList->end(); iter++){
        QRadioButton *radioBtn = new QRadioButton("unjoin");
        connect(radioBtn, SIGNAL(toggled(bool)), this, SLOT(OnRadioButton(bool)));
 
        CModelData *pModel = *iter;
        m_pModel->setRowCount(m_pModel->rowCount() + 1);
        int iNumber = m_pModel->rowCount();
        m_pModel->setData(m_pModel->index(iNumber-1, 0, QModelIndex()),iNumber);
        m_pModel->setData(m_pModel->index(iNumber-1, 1, QModelIndex()),pModel->getAge());
        m_pModel->setData(m_pModel->index(iNumber-1, 2, QModelIndex()),pModel->getSex());
        ui->tableView->setIndexWidget(m_pModel->index(iRow, 3), radioBtn); //添加RadioButton
        m_pModel->setData(m_pModel->index(iNumber-1, 4, QModelIndex()),pModel->getTime().toString());
        m_pModel->setData(m_pModel->index(iNumber-1, 5, QModelIndex()),pModel->getProcess());
        m_pModel->setData(m_pModel->index(iNumber-1, 6, QModelIndex()),pModel->getProcess());
        m_pModel->setData(m_pModel->index(iNumber-1, 7, QModelIndex()),"111");
 
        m_pModel->item(iNumber-1, 0)->setCheckable(true); //添加CheckBox
        m_pModel->item(iNumber-1, 0)->setTextAlignment(Qt::AlignCenter);
        m_pModel->item(iNumber-1, 1)->setTextAlignment(Qt::AlignCenter);
        m_pModel->item(iNumber-1, 2)->setTextAlignment(Qt::AlignCenter);
        m_pModel->item(iNumber-1, 4)->setTextAlignment(Qt::AlignCenter);
        m_pModel->item(iNumber-1, 5)->setEnabled(false);
        iRow++;
    }

2、QHeadView中嵌入QCheckBox类

CCheckBoxHeaderView::CCheckBoxHeaderView(int checkBoxColumnId, Qt::Orientation orientation, QWidget * parent)
    : QHeaderView(orientation, parent)
{
    m_checkBoxColumnId = checkBoxColumnId;
    m_checkBoxIsOn = false;
}
 
CCheckBoxHeaderView::~CCheckBoxHeaderView()
{
 
}
 
void CCheckBoxHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
    painter->save();
    QHeaderView::paintSection(painter, rect, logicalIndex);
    painter->restore();
    if (logicalIndex == m_checkBoxColumnId)
    {
        QStyleOptionButton option;
        int width = 3;
        for (int i=0; i<logicalIndex; ++i)
            width += sectionSize( i );
        option.rect = QRect(width, 5, 15, 15);
        if (m_checkBoxIsOn)
            option.state = QStyle::State_On;
        else
            option.state = QStyle::State_Off;
        this->style()->drawControl(QStyle::CE_CheckBox, &option, painter);
    }
}
 
void CCheckBoxHeaderView::mousePressEvent(QMouseEvent *event)
{
    if (visualIndexAt(event->pos().x()) == m_checkBoxColumnId)
    {
        if (m_checkBoxIsOn)
            m_checkBoxIsOn = false;
        else
            m_checkBoxIsOn = true;
        this->updateSection(m_checkBoxColumnId);
        emit sig_AllChecked(m_checkBoxIsOn);
    }
 
    QHeaderView::mousePressEvent(event);
}

3、QCombobox的嵌入

CComboBoxDelegate::CComboBoxDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{
 
}
 
QWidget* CComboBoxDelegate::createEditor(QWidget *parent,  const QStyleOptionViewItem &option,
                                         const  QModelIndex &index)  const
{
    Q_UNUSED(option);
    Q_UNUSED(index);
    QComboBox *editor =  new QComboBox(parent);
    editor->addItem("MAN");
    editor->addItem("WOMAN");
    editor->setCurrentIndex(0);
    //editor->setEditable(true);
    return  editor;
}
 
void  CComboBoxDelegate::setEditorData(QWidget *editor,  const  QModelIndex &index)  const
{
    QString text = index.model()->data(index, Qt::EditRole).toString();
    QComboBox *comboBox =  static_cast <QComboBox*>(editor);
    int  tindex = comboBox->findText(text);
    comboBox->setCurrentIndex(tindex);
}
 
void  CComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                      const  QModelIndex &index)  const
{
    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    QString strData = comboBox->currentText();
    model->setData(index, strData, Qt::EditRole);
}
 
void  CComboBoxDelegate::updateEditorGeometry(QWidget *editor,
                                              const  QStyleOptionViewItem &option,  const  QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect);
}

4、 QCombox + QCheckBox类

CComboCheckBoxDelegate::CComboCheckBoxDelegate(QObject *parent)
    : QStyledItemDelegate(parent), m_pComboBox(NULL)
{
    QPair<QString, Qt::CheckState> list;
    list.first = "111"; list.second = Qt::Unchecked;
    QPair<QString, Qt::CheckState> list2;
    list2.first = "222"; list.second = Qt::Unchecked;
    QPair<QString, Qt::CheckState> list3;
    list3.first = "333"; list.second = Qt::Unchecked;
    m_lstComboCheckBoxItems.append(list);
    m_lstComboCheckBoxItems.append(list2);
    m_lstComboCheckBoxItems.append(list3);
 
    m_strCurrentText.clear();
}
 
CComboCheckBoxDelegate::~CComboCheckBoxDelegate()
{
 
}
 
QWidget* CComboCheckBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                              const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);
    QListWidget* pListWidget = new QListWidget;
    for (int i = 0; i < m_lstComboCheckBoxItems.size(); i++)
    {
        QListWidgetItem* pItem = new QListWidgetItem(pListWidget);
        pItem->setData(Qt::UserRole, i);
        pListWidget->addItem(pItem);
 
        QCheckBox* pCheckBox = new QCheckBox;
        pCheckBox->setText(m_lstComboCheckBoxItems.at(i).first);
        pCheckBox->setCheckState(m_lstComboCheckBoxItems.at(i).second);
        connect(pCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnStateChanged(int)));
        pListWidget->setItemWidget(pItem, pCheckBox);
    }
 
    m_pComboBox = new QComboBox(parent);
    m_pComboBox->setModel(pListWidget->model());
    m_pComboBox->setView(pListWidget);
    m_pComboBox->setEditable(true);
 
    return m_pComboBox;
}
 
 
void CComboCheckBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QString strText = index.model()->data(index, Qt::EditRole).toString();
    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    comboBox->setEditText(strText);
}
 
 
void CComboCheckBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    QString strData = comboBox->currentText();
    model->setData(index, strData, Qt::EditRole);
}
 
 
void CComboCheckBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
                                                  const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect);
}
 
 
void CComboCheckBoxDelegate::OnStateChanged(int iState)
{
    m_strCurrentText.clear();
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    int iCount = m_lstComboCheckBoxItems.size();
    for (int i = 0; i < iCount; i++)
    {
        if (pCheckBox->text().compare(m_lstComboCheckBoxItems.at(i).first) == 0)
        {
            if (iState == 0)
            {
                m_lstComboCheckBoxItems[i] = qMakePair(m_lstComboCheckBoxItems.at(i).first, Qt::Unchecked);
            }
            else if (iState == 1)
            {
                m_lstComboCheckBoxItems[i] = qMakePair(m_lstComboCheckBoxItems.at(i).first, Qt::PartiallyChecked);
            }
            else if (iState == 2)
            {
                m_lstComboCheckBoxItems[i] = qMakePair(m_lstComboCheckBoxItems.at(i).first, Qt::Checked);
            }
        }
 
        if (m_lstComboCheckBoxItems.at(i).second == Qt::Checked)
        {
            m_strCurrentText += m_lstComboCheckBoxItems.at(i).first;
            m_strCurrentText += ";";
        }
    }
 
    if (m_strCurrentText.right(1) == ";")
    {
        m_strCurrentText.chop(1);
    }
 
    if (m_pComboBox != NULL)
    {
        m_pComboBox->setEditText(m_strCurrentText);
    }
}

5、SpinBox的嵌入类

/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
 
/*
    delegate.cpp
    A delegate that allows the user to change integer values from the model
    using a spin box widget.
*/
 
#include "CSpinBoxDelegate.h"
#include <QSpinBox>
 
//! [0]
CSpinBoxDelegate::CSpinBoxDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{
}
//! [0]
 
//! [1]
QWidget *CSpinBoxDelegate::createEditor(QWidget *parent,
    const QStyleOptionViewItem &/* option */,
    const QModelIndex &/* index */) const
{
    QSpinBox *editor = new QSpinBox(parent);
    editor->setFrame(false);
    editor->setAlignment(Qt::AlignCenter);
    editor->setMinimum(0);
    editor->setMaximum(100);
 
    return editor;
}
//! [1]
 
//! [2]
void CSpinBoxDelegate::setEditorData(QWidget *editor,
                                    const QModelIndex &index) const
{
    int value = index.model()->data(index, Qt::EditRole).toInt();
 
    QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
    spinBox->setValue(value);
}
//! [2]
 
//! [3]
void CSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                   const QModelIndex &index) const
{
    QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
    spinBox->interpretText();
    int value = spinBox->value();
 
    model->setData(index, value, Qt::EditRole);
}
//! [3]
 
//! [4]
void CSpinBoxDelegate::updateEditorGeometry(QWidget *editor,
    const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
    editor->setGeometry(option.rect);
}
//! [4]

6、QProcess的嵌入类

//-------------------
//-------------------
CProcess2Delegate::CProcess2Delegate(QObject *parent) :
    QItemDelegate(parent)
{
 
}
 
void CProcess2Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    int value = index.model()->data(index).toInt();
    QStyleOptionProgressBarV2 progressBarOption;
    progressBarOption.rect = option.rect.adjusted(4, 4, -4, -4);
    progressBarOption.minimum = 0;
    progressBarOption.maximum = 1000;
    progressBarOption.textAlignment = Qt::AlignRight;
    progressBarOption.textVisible = true;
    progressBarOption.progress = value;
    progressBarOption.text = tr("%1%").arg(progressBarOption.progress / 10);
 
    painter->save();
    if (option.state & QStyle::State_Selected) {
        painter->fillRect(option.rect, option.palette.highlight());
        painter->setBrush(option.palette.highlightedText());
    }
    QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
 
    painter->restore();
}
 

7、QProcess绘制版本的嵌入类

CProcessDelegate::CProcessDelegate(QObject *parent) :
    QItemDelegate(parent)
{
 
}
 
CProcessDelegate::~CProcessDelegate()
{
 
}
 
void CProcessDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if( option.state & QStyle::State_Selected )
        painter->fillRect( option.rect, option.palette.highlight() );
 
    // 数据是存储在QStandardItemModel的QStandardItem,会自动根据当前行进行匹配(我认为)
    int value = index.model()->data( index, Qt::DisplayRole ).toInt(); // 这句,取得当前行的数据
    double factor = double(value)/1000.0; // 计算比例因子
 
    painter->save(); // 保存旧画板(我认为)
    // 进度条背景色
    if( factor > 0.8 )
    {
        painter->setBrush( Qt::red ); // 超过0.8画纯红色
        factor = 1;
    }
    else
        painter->setBrush( QColor( 0, int(factor*255), 255-int(factor*255) ) ); // 否则颜色依次变淡
 
    painter->setPen( Qt::black ); // 画笔颜色(这里没用到,我认为)
    // 前面都是准备工作,这里才是真正画进度条
    painter->drawRect( option.rect.x()+2, option.rect.y()+2, int(factor*(option.rect.width()-5)), option.rect.height()-5 );
    painter->restore(); // 恢复新画板(我认为)
 
}
 
 
QWidget *CProcessDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);
    QSlider *slider = new QSlider( parent );
 
    slider->setAutoFillBackground( true );
    slider->setOrientation( Qt::Horizontal );
    slider->setRange( 0, 1000 );
    slider->installEventFilter( const_cast<CProcessDelegate*>(this) );
 
    return slider;
}
 
void CProcessDelegate::updateEditorGeometry( QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
 
    editor->setGeometry( option.rect );
}
 
void CProcessDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
{
    int value = index.model()->data( index, Qt::DisplayRole ).toInt();
    static_cast<QSlider*>( editor )->setValue( value );
}
 
void CProcessDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
{
    model->setData( index, static_cast<QSlider*>( editor )->value() );
}

8、QPushButton/QLabel/QImage的嵌入类

CPixBtnDelegate::CPixBtnDelegate(QObject *parent) :
    QItemDelegate(parent)
{
    m_pBtns = new QMap<QModelIndex, QStyleOptionButton *>();
    pixPath = QString("");
}
 
CPixBtnDelegate::~CPixBtnDelegate()
{
    foreach (QStyleOptionButton *pBtn, m_pBtns->values()) {
        if (NULL != pBtn) {
            delete pBtn;
            pBtn = NULL;
        }
    }
    m_pBtns->clear();
    if (NULL != m_pBtns) {
        delete m_pBtns;
        m_pBtns = NULL;
    }
}
 
void CPixBtnDelegate::setPixPath(const QString &path)
{
    pixPath = path;
}
 
void CPixBtnDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
                             const QModelIndex &index) const
{
    QStyleOptionButton * pBtn = m_pBtns->value(index);
    if (NULL == pBtn) {
        pBtn = new QStyleOptionButton();
        pBtn->state |= QStyle::State_Enabled;
        (const_cast<CPixBtnDelegate *>(this))->m_pBtns->insert(index, pBtn);
    }
    int dx1 = 46; int dy1 = 4;
    int dx2 = 30-(option.rect.width()/2 + 16); int dy2 = -4;
    pBtn->rect = option.rect.adjusted(dx1, dy1, dx2, dy2); //设置按钮的大小
 
    const QPixmap &pixmap = QPixmap(pixPath);
    int width=pixmap.width();
    int height=pixmap.height();
    int x=pBtn->rect.x()+pBtn->rect.width()/2-width/2;
    int y=pBtn->rect.y()+pBtn->rect.height()/2-height/2;
 
    painter->save();
    if (option.state & QStyle::State_Selected) {
        painter->fillRect(option.rect, option.palette.light());
    }
    painter->drawPixmap(x,y,pixmap);  //设置按钮的背景图片
    painter->restore();
    QApplication::style()->drawControl(QStyle::CE_PushButtonLabel, pBtn, painter);
 
}
 
bool CPixBtnDelegate::editorEvent(QEvent *event,QAbstractItemModel *model,
                                   const QStyleOptionViewItem &option,const QModelIndex &index)
{
    if (event->type() == QEvent::MouseButtonPress) {
        QMouseEvent * ev = static_cast<QMouseEvent*>(event);
        if (m_pBtns->contains(index)) {
            QStyleOptionButton * pBtn = m_pBtns->value(index);
            if (pBtn->rect.contains(ev->x(), ev->y())) {
                pBtn->state |= QStyle::State_Sunken;
            }
        }
    }
    if (event->type() == QEvent::MouseButtonRelease) {
        QMouseEvent * ev = static_cast<QMouseEvent*>(event);
        if (m_pBtns->contains(index)) {
            QStyleOptionButton * pBtn = m_pBtns->value(index);
            if (pBtn->rect.contains(ev->x(), ev->y())) {
                pBtn->state &= (~QStyle::State_Sunken);
                emit sig_buttonClicked(index);
            }
        }
    }
    return QItemDelegate::editorEvent(event, model, option, index);
}

[2] QTableView详细使用说明

原文链接:https://blog.csdn.net/u010031316/article/details/116886567

创建QTableView

QTableView是一种View/Model模式在创建QTableView表格的时,除了创建QTableView对象还需要创建对应的Model对象,Model对象负责表格中的数据单元添加、单元格删除和设置表格标题等操作,一般常见的就是QStandardItemModel模型。

使用时需要包含#include 和#include ,创建一个QTableView对象和QStandardItemModel并使用QTableView的setModel()函数将视图和模型对象进行绑定。下面以继承QTableView为示例,代码如下所示:

// .h
#include <QTableView>
#include <QStandardItemModel>

class DBTableView
    : public QTableView
{
public:
    explicit DBTableView(QWidget * _parent_widget = nullptr);
    ~DBTableView() override;

private:
    QStandardItemModel*                             db_table_model_;
};

// .cpp
#include "db_table_view.h"

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
    db_table_model_ = new QStandardItemModel();
    setModel(db_table_model_);
}

DBTableView::~DBTableView()
{

}

表格标题

设置表格的标题
表格最重要的就是标题对于一个表格控件而言标题分为水平标题和垂直标题,可以使用model对象提供的setHorizontalHeaderLabels()函数和setVerticalHeaderLabels()函数进行表格标题的设置,前者是对水平标题的设置而后者是对垂直标题的设置,示例代码和效果如下所示:

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
    // ......

    QStringList table_h_headers;
    table_h_headers << "设施ID" << "设施名称" << "设施等级" << "人员配置"<< "数据采集日期";

    db_table_model_->setHorizontalHeaderLabels(table_h_headers);

    QStringList table_v_headers;
    table_v_headers << "测试1" << "测试2" << "测试3" << "测试4"<< "测试5";

    db_table_model_->setVerticalHeaderLabels(table_v_headers);
}

在这里插入图片描述
表格控件上的所有单元格都是item对象表格标题也不例外,因此可以单独创建item对象然后通过model的setHorizontalHeaderItem()函数和setVerticalHeaderItem()函数依次对表格进行的标题进行设置,示例代码如下:

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
	// ......

    QStringList table_h_headers;
    table_h_headers << "设施ID" << "设施名称" << "设施等级" << "人员配置"<< "数据采集日期";

    for (int index = 0; index < table_h_headers.count(); ++index) {
        QStandardItem * header_item = new QStandardItem(table_h_headers[index]);
        db_table_model_->setHorizontalHeaderItem(index, header_item);
    }
}

这种做法适用于对表格标题需要添加一些数据的时候,例如,当前的模型描述的数据库中的数据表,标题的显示文字可以写成中文,然后将其对应的数据库字段作为附加信息通过setData()函数写道对象中,示例代码如下:

#include "db_table_view.h"

#define DATABASE_FIELD_CODE         Qt::UserRole + 100

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
    // ......

    QStringList table_h_headers;
    table_h_headers << "设施ID" << "设施名称" << "设施等级" << "人员配置"<< "数据采集日期";

    QStringList table_h_fields;
    table_h_fields << "id" << "name" << "level" << "config"<< "date";

    for (int index = 0; index < table_h_headers.count(); ++index) {
        QStandardItem * header_item = new QStandardItem(table_h_headers[index]);
        header_item->setData(table_h_fields[index], DATABASE_FIELD_CODE);
        db_table_model_->setHorizontalHeaderItem(index, header_item);
    }
}

获取表格的标题

设置表格标题后就是获取标题内容,可以通过model的columnCount()函数获取数量,配合model的headerData()函数获取当前列的文字内容,示例代码如下:

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
	// ......
    QStringList table_h_headers;
    table_h_headers << "设施ID" << "设施名称" << "设施等级" << "人员配置"<< "数据采集日期";
    db_table_model_->setHorizontalHeaderLabels(table_h_headers);

    for (int index = 0; index < db_table_model_->columnCount(); ++index) {
        qInfo() << db_table_model_->headerData(index, Qt::Horizontal, Qt::DisplayRole).toString();
    }
}

headerData()的第一个参数是列的索引号,第二个参数是获取水平方向还是垂直方向的表头,第三个参数是模型数据编号,该编号与setData()函数在设置时的一致,而这里使用的Qt::DisplayRole是内置的一个编号,用于获取显示的文字内容。

数据操作

插入数据
设置好标题后就可以对表格进行添加数据了,可以使用model的setItem()函数和appendRow()函数,其中setItem()函数需要指定设置的行和列,而appendRow()函数可以先将一行item的对象添加一个list中然后一次性插入,示例代码如下:

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
    // ......

    db_table_model_->setItem(0, 0, new QStandardItem("1"));
    db_table_model_->setItem(0, 1, new QStandardItem("2"));
    db_table_model_->setItem(0, 2, new QStandardItem("3"));
    db_table_model_->setItem(0, 3,new QStandardItem("4"));
    db_table_model_->setItem(0, 4,new QStandardItem("5"));

    QList<QStandardItem*> add_items;
    for (int index = 0; index < table_h_headers.count(); ++index) {
        add_items << new QStandardItem(QString::number(index));
    }
    db_table_model_->appendRow(add_items);
}


删除数据

删除数据时同样也是依赖model对象,model对象提供了一个clear()函数,该函数可以一次将表格内容和表格标题都删掉,如果只是想将表格内容清空则可以使用model的rowCount()函数配合model的removeRows()函数完成,示例代码如下:

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
    // ......
    db_table_model_->removeRows(0, db_table_model_->rowCount());
}

删除某一列数据可以使用model的removeColumn()函数,示例如下:

DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
    // ......
    db_table_model_->removeColumn(0);
}

属性设置

对于表格而言可以对其样式进行调整,常见的设置如下:

设置表格的对齐方式

horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
verticalHeader()->setDefaultAlignment(Qt::AlignBottom);

设置表格的宽高

// 固定表格宽度不可扩展,不可手动调整宽度
horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
// 表格宽度随内容自动扩展
horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
// 表格宽度自动根据UI进行计算,不可手动调整宽度
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);


// 固定表格高度不可扩展,不可手动调整高度
verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
// 表格高度随内容自动扩展
verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
// 表格高度自动根据UI进行计算,不可手动调整高度
verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);

设置表格的线属性

// 隐藏网格线
setShowGrid(false);
// 显示网格线
setShowGrid(true);
// 线的样式
setGridStyle(Qt::DotLine);

自定义菜单

eventFilter方法

重载eventFilter()
对于表格控件常见的操作就是弹出菜单,当鼠标点击控件时会触发一个QEvent::ContextMenu类型的事件,通过重载eventFilter()事件过滤器函数,并捕获该类型事件来实现菜单的弹出,具体步骤如下:

// .h
// ......
#include <QEvent>
#include <QMenu>

class DBTableView
    : public QTableView
{
    Q_OBJECT
	// ......
protected:
    bool eventFilter(QObject *object, QEvent *event) override;
};

启用事件监听

// .cpp
DBTableView::DBTableView(QWidget *_parent_widget)
    : QTableView(_parent_widget)
{
	// ......
    installEventFilter(this);

}

实现事件过滤函数

bool DBTableView::eventFilter(QObject *object, QEvent *event) {
    if(object == this  &&  event->type() == QEvent::ContextMenu) {
        if(currentIndex().isValid()) {
            QMenu * menu = new QMenu();

            menu->addAction("添加数据");
            menu->addAction("删除数据");

            QAction * action = menu->exec(cursor().pos());    // 弹出菜单
            if (action->text().compare("删除数据") == 0) {
                db_table_model_->removeRow(currentIndex().row());
            }
        }
    }

    return QAbstractItemView::eventFilter(object, event);
}

效果如下:
在这里插入图片描述

设置菜单属性方法

除了直接监听eventFilter之外还有一个简单一些的方式调用QTableView的setContextMenuPolicy()函数,示例代码如下:

设置属性

void TestTable::initUI() {
	QTableView * table_view = new QTableView();
	table_view->setContextMenuPolicy(Qt::CustomContextMenu);
}

关联信号槽
在创建完QTableView对象后设置使用自定义菜单策略,然后进行信号槽关联,示例代码如下:

void TestTable::tableViewMenu(const QPoint & _pos) {
	// 相应数据处理
}

void TestTable::initUI() {
	// ......
	connect(table_view, &QTableView::customContextMenuRequested, this, &TestTabel::tableViewMenu);
}

[3] 基于QTableView中的MVD代理添加总结

原文链接:https://blog.csdn.net/qq_36939187/article/details/130158719

开发过程中进程使用MVD模型,添加各种代理控件,本文在此基础上整理一些数据模型代理,包括:QPushbutton、QLineEdit、QPixmap、QChecledBox、QComboBox、QSpinBox、QProcessBar、只读列、自定义窗口等共13种代理方式,如图所示:

在此之前,先来说明一下对MVD做一简单说明:

1、Qt中MVD说明

    在传统的MVC模型中,view用于向用户展示model数据。但是,Qt提供的并不是MVC架构,而是一个model/view的设计(也就是说,没有包含一个完整而独立的组件用于管理用户的交互)。一般来说,view仅仅是作用于model数据的展示和用户输入的处理,而不应该去做其他的工作。在这种结构中,为了获得对用户输入控制的灵活性,就将这种交互工作交给了delegate完成(也就是“委托”)。简单来说,就是view将用户输入委托给delegate处理,而不自己去处理。这些组件提供一种输入能力,并且能够在某些view中提供这种交互情形下的渲染,比如在table中双击某单元格进行编辑等。

1.1 View
QListView、QTreeView、QTableView

1.2 Delegate
Delegate可以用于渲染内容,这是通过paint() 和sizeHint()函数来完成的。但是对于一些简单的基于组件的delegate,可以通过继承QItemdelegate或者QStyledItemDelegate 来实现,而不需要重写虚函数。

Qt提供的标准组件中使用QItemDelegate提供编辑功能的支持。这种默认的实现被用在QListView,QTableView和QTreeView中。View实用的delegate可以通过itemDelegate()函数获得,其中,setItemDelegate()函数则可以为一个标准组件设置自定义的delegate.

在Qt4.4之后提供QItemDelegate/QStyledItemDelegate ,可以把控件设置成只读、表格的某一列制定自己需要的控件。默认的委托是QStyledItemDelegate。这两个类可以被相互替代,给view组件提供绘制和编辑功能。主要区别在于,QStyledItemDelegate使用当前的风格(style)去绘制组件,所以当需要设置 qt style sheet时建议使用QStyleItemDelegaet作为父类。使用这两个类的代码是一样的,除了需要使用style进行绘制的部分。

*注意:绘制和向视图提供编辑器的方式,但使用起来感觉区别不是很大,之前使用过代理第一时间想到的是重写代理,实现虚函数,在虚函数中创建自己想要的控件并返回就OK了,但是运行程序时发现并没有默认显示出来,只有在编辑的时候显示(也就是双击的时候),这种方式用在输入限制的时候感觉比较合适(对此,官方文档是这样解释的:The QStyledItemDelegate class provides display and editing facilities for data items from a model.)。也就是说,如果想要在load的时候就显示出来控件,必须写在void paint(QPainter painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;里;如果控件需要有相应的动作,就需要写在editorEvent中

如果delegate没有支持为你的数据类型进行绘制,或者你希望自己绘制item,那么就可以继承QStyleItemDelegate类,并且重写paint()或者还需要重写sizeHit()函数。paint()函数会被每一个item独立调用,而sizeHint()函数则可以定义每一个item的大小。在重写paint()函数的时候,通常需要用if语句找到你需要进行渲染的诗句类型并进行绘制,其他的数据类型需要调用父类的实现进行绘制。

继承QStyledItemDelegate需要实现以下函数:

class MyDelegate: public QStyledItemDelegate
{
    //创建你编辑时候的控件,返回修改数据的组件
    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const  QModelIndex &index) const;
 
    //编辑的时候设置数据到上面创建的editor中。
    void setEditorData(QWidget *editor, const QModelIndex &index) const; 
 
    //编辑完成,保存数据到model中
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
 
    //设置编辑控件的位置和大小、样式等(保证editor显示在item view的合适位置以及大小)
    void updateEditorGeometry ( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
}
 

例如,添加一个进度条控件:

void WidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.column() == 1) {
        int progress = index.data().toInt();
        QStyleOptionProgressBar progressBarOption;
        progressBarOption.rect = option.rect;
        progressBarOption.minimum = 0;
        progressBarOption.maximum = 100;
        progressBarOption.progress = progress;
        progressBarOption.text = QString::number(progress) + "%";
        progressBarOption.textVisible = true;
        QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
      } else
        QStyledItemDelegate::paint(painter, option, index);
}

1.3 Model/View的基本原理
1、数据(Data)是实际的数据,如数据库的一个数据表或 SQL查询结果,内存中的一个StringList,或磁盘文件结构等。

2、视图或视图组件(View)是屏幕上的界面组件,视图从数据模型获得每个数据项的模型索引(model index),通过模型索引获取数据,然后为界面组件提供显示数据,Qt提供一些现成的数据视图组件,如QListView、QTreeView 和QTableView等。

3、模型或数据模型(Model)与实际数据通信,并为视图组件提供数据接口。它从原始数据提取需要的内容,用于视图组件进行显示和编辑。Qt中有一些预定义的数据模型,如QStringListModel
可作为StringList的数据模型,QSqlTableModel 可以作为数据库中一个数据表的数据模型。

    模型(Model)与数据源(Data)通信;视图(View)从模型(Model)中获取模型索引;在标准视图中,代理(delegate)渲染数据项。编辑项时,代理将直接使用模型索引(model index)与模型通信。模型、视图和代理之间使用信号和槽通信。当源数据发生变化时,数据模型发射信号通知视图组件:当用户在界面上操作数据时,视图组件发射信号表示这些操作信息;当编辑数据时,代理发射信号告知数据模型和视图组件编辑器的状态。

所有的基于项数据(item data)的数据模型(Model)都基于QAbstractltemModel类,此类定义了视图和代理访问数据的接口。数据本身不必存储在模型中;它可以保存在由单独的类、文件、数据库或其他应用程序组件提供的数据结构或存储库中。QabstracteModel提供了一个数据接口,该接口足够灵活,可以处理以table、list和tree的形式表示数据的视图。

Qt提供了一些现成的模型,可用于处理数据项:

  • QStringListModel 用于处理QString列表的数据模型类
  • QStandardItemModel 标准的基于项数据的数据模型类,管理更复杂的树结构,每个项数据内都可以包含任意类型的数据
  • QFileSystemModel 提供有关本地文件系统中的文件和目录的信息,文件系统模型类
  • QSqlQueryModel 用于数据库sql查询结果的数据模型类
  • QSqlTableModel 用于数据库中一个数据表的数据模型类
  • QSqlRelationalTableModel 用于关系型数据表的数据模型类
  • QSortFilterProxyModel 与其他数据模型结合,提供排序和过滤功能的数据模型类
    如果这些标准模型不符合您的要求,您可以将QAbstractItemModel、QAbstractListModel或QAbstractTableModel子类化,以创建自己的自定义模型。

一般需要实现的子类为:
//获得模型的行数
int rowCount(const QModelIndex &parent) const;
//获得模型的列数
int columnCount(const QModelIndex &parent) const;
//向模型中设置数据
bool setData(const QModelIndex &index, const QVariant &value, int role );
//获得模型的数据
QVariant data(const QModelIndex &index, int role) const;
//设置模型的标题
QVariant headerData(int section, Qt::Orientation orientation, int role ) const;

2、代码是现实示例

2.1 设置样式文件

QString qssData = nullptr;
QFile fileqss(":/qss/QSSUITableView");
if(fileqss.open(QFile::ReadOnly))
{
        qssData = fileqss.readAll();
        fileqss.close();
}
ui->tableView->setStyleSheet(qssData);

2.2 set base attribute

    ui->tableView->verticalHeader()->hide();                                                   // 隐藏垂直头
    ui->tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);                       // 隐藏水平头
    //ui->tableView->horizontalHeader()->setStretchLastSection(true);                          // 设置随后一列拉伸
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);         // 设置列平均分配
    //ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);  // 设置TreeWidget水平滚动和自适应宽度
    //ui->tableView->setColumnWidth(headersList.count() - 1, TITLE_FIXED_HEIGHT);              // 设置最后一列固定
    //ui->tableView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);      // 行单选
    ui->tableView->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);         // 行多选 (单选QAbstractItemView::SingleSelection 多选:QAbstractItemView::MultiSelection)
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);                         // 不可编辑
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);                        // 设置选中模式为整行
    ui->tableView->setShowGrid(false);                                                         // 显示/隐藏网格线
    setFocusPolicy(Qt::FocusPolicy::NoFocus);                                                  // 设置选中之后无虚线焦点
    //horizontalHeader()->setMinimumSectionSize(100);                                          // 设置最小列宽
    //horizontalHeader()->setMaximumSectionSize(100);                                          // 设置最大列宽
    ui->tableView->verticalHeader()->setDefaultSectionSize(25);                                 // 可以设置tableview所有列的默认行高为15。
    //horizontalHeader()->setDefaultSectionSize(15);                                            // 可以设置tableview所有行的默认列宽为15。
    ui->tableView->setWordWrap(false);                                                         // 设置不自动换行
    setMouseTracking(true);                                                                     // 设置鼠标追踪
 
    // 设置第0列固定宽度
    /*
    ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setSectionResizeMode(5, QHeaderView::Fixed);
    ui->tableView->setColumnWidth(0, 50);
    ui->tableView->setColumnWidth(2, 150);
    ui->tableView->setColumnWidth(3, 150);
    ui->tableView->setColumnWidth(4, 150);
    ui->tableView->setColumnWidth(5, 150);
    */

2.3 设置model

    model = new QStandardItemModel;
    ui->tableView->setModel(model);

2.4 设置表头

    QStringList headerList;
    headerList<<"姓名"<<"QSpinBox"<<"QComboBox"<<"QPushButton"<<"CheckBox"<<"QPixmap"<<"QLineEdit"<<"ReadOnly"<<"Text"<<"ProcessBar"<<"DateEdit"<<"CustomWidget"<<"pDoubleProcessBar";
    model->setHorizontalHeaderLabels(headerList);

2.5 设置数据

    model->setItem(0,0,new QStandardItem("张三"));
    model->setItem(1,0,new QStandardItem("李四"));
    model->setItem(2,0,new QStandardItem("王二"));
    model->setItem(3,0,new QStandardItem("小明同学"));
 
    model->setItem(0,1,new QStandardItem("1"));
    model->setItem(1,1,new QStandardItem("2"));
    model->setItem(2,1,new QStandardItem("3"));
 
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);         // 选择一行

2.6 添加代理控件

2.6.1 添加 QSpinBox 代理

    CUISpinBoxDelegate *pSpinBox = new CUISpinBoxDelegate(this);
    ui->tableView->setItemDelegateForColumn(1, pSpinBox);

2.6.2 添加 QComboBox 代理

    CUIComboBoxDelegate *pComboBox = new CUIComboBoxDelegate(this);
    ui->tableView->setItemDelegateForColumn(2, pComboBox);

2.6.3 添加 QPushButton 代理

    CUIMutipleButtonDeleagate *pMutipleBtn = new CUIMutipleButtonDeleagate(QStringList() << "修改" << "删除", this);
 
    ui->tableView->setItemDelegateForColumn(3, pMutipleBtn);
 
    connect(pMutipleBtn, &CUIMutipleButtonDeleagate::editData, [&](){
        QMessageBox::information(this, "提示", "这是一个编辑按钮");
    });
    connect(pMutipleBtn, &CUIMutipleButtonDeleagate::deleteData, [&](){
        QMessageBox::information(this, "提示", "这是一个删除按钮");
    });

2.6.4 添加 CheckBox 代理

    /*CUITableHeaderView **/pTableHeaderView = new CUITableHeaderView(Qt::Horizontal, ui->tableView);
 
    connect(pTableHeaderView, &CUITableHeaderView::stateChanged, this, &MainWindow::headerStateChangedSlot);
    connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(itemChangedSlot(QStandardItem*)));
 
    ui->tableView->setHorizontalHeader(pTableHeaderView);
 
    CUICheckBoxDelegate *pCheckedBox = new CUICheckBoxDelegate(this);
    ui->tableView->setItemDelegateForColumn(4, pCheckedBox);

2.6.5 添加 Pixmap 代理

    CUIPixmapDelegate *pPixmap = new CUIPixmapDelegate(this);
    ui->tableView->setItemDelegateForColumn(5, pPixmap);

2.6.6 添加 LineEdit 代理

CUILineEditDelegate *pLineEdit = new CUILineEditDelegate(this);

2.6.7 添加 ReadOnly 代理

    CUIOnlyReadDelegate *pReadOnly = new CUIOnlyReadDelegate(this);
    ui->tableView->setItemDelegateForColumn(7, pReadOnly);

2.6.8 添加 Text 代理

    CUITextDelegate *pLabel = new CUITextDelegate(this);
    ui->tableView->setItemDelegateForColumn(8, pLabel);

2.6.9 添加 QProcessBar 代理

    CUIProcessBarDelegate *pProcessBar = new CUIProcessBarDelegate();
    ui->tableView->setItemDelegateForColumn(9, pProcessBar);
    
    QModelIndex index = model->index(0, 9, QModelIndex());
    model->setData(index,29);

2.6.10 添加 DateEdit 代理

    CUIDateEditDelegate *pDateEdit = new CUIDateEditDelegate();
    ui->tableView->setItemDelegateForColumn(10, pDateEdit);

2.6.11 添加 添加自定义窗口 代理

    CUICustomDelegate *pCustomWidget = new CUICustomDelegate(this);
    ui->tableView->setItemDelegateForColumn(11, pCustomWidget);

2.6.12 添加 DoubleProcessBar 代理

    CUIDoubleProcessBarDelegate *pDoubleProcessBar = new CUIDoubleProcessBarDelegate(this);
    ui->tableView->setItemDelegateForColumn(12, pDoubleProcessBar);

2.7 获取某一单元格数据

    //model->index(0, 1).data();
  • 2
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值