Qt Model/View理解(四)---实战

前面讲解了有关Model/View的实现方式,下面将用一个例子,介绍如何构造model和使用Delegate渲染进行混合编程,主要显示学生信息,tableview里面有checkbox,  combBox,  lineEdit等操作控件,最终效果如下。

Qt Model/View理解(四)---实战_第1张图片

1.首先,我们建立2个学生的基本信息(姓名,性别,年龄,分数,是否毕业),并放在链表中。姓名不可编辑,性别combox下拉可选,年龄,分数双击可修改,是否毕业开关可编辑。

enum E_Gender
{
    E_BOY,
    E_GIRL,
};

typedef struct S_Student
{
    bool m_check;
    QString m_name;
    int m_age;
    E_Gender m_gender;
    int m_score;
    bool m_graduate;
}S_STU;
QList StuList;
    StuList.clear();

    S_STU *stu1 = new S_STU;
    stu1->m_check = false;
    stu1->m_name = QString("XiaoMing");
    stu1->m_gender = E_BOY;
    stu1->m_age = 12;
    stu1->m_score = 98;
    stu1->m_graduate = true;

    S_STU *stu2 = new S_STU;
    stu2->m_check = false;
    stu2->m_name = QString("XiaoHong");
    stu2->m_gender = E_GIRL;
    stu2->m_age = 10;
    stu2->m_score = 100;
    stu2->m_graduate = false;

    StuList.append(stu1);
    StuList.append(stu2);
2.构造model模型,重载常用的虚函数。
int	StudentModel::columnCount(const QModelIndex & parent) const
{
    Q_UNUSED(parent);
    return 6;
}

int	StudentModel::rowCount(const QModelIndex & parent) const
{
    Q_UNUSED(parent);
    return StuList.count();
}

QVariant StudentModel::data(const QModelIndex & index, int role) const
{
    if (!index.isValid())
        return QVariant();

    int nRow = index.row();
    int nColumn = index.column();

    S_STU *stu = StuList.at(nRow);
    switch(role){
        case Qt::TextColorRole:
            return QColor(Qt::black);
        case Qt::TextAlignmentRole:
            return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
        case Qt::UserRole+COLUMN_CHECK:
        {
            if (nColumn == COLUMN_CHECK)
                return stu->m_check;
            return "";
        }
        case Qt::DisplayRole:
        {
            if (nColumn == COLUMN_NAME)
                return stu->m_name;
            if (nColumn == COLUMN_AGE)
                return stu->m_age;
            if (nColumn == COLUMN_SCORE)
                return stu->m_score;
            return "";
        }
        case Qt::UserRole+COLUMN_AGE:
        {
            if (nColumn == COLUMN_AGE)
                return stu->m_age;
            return "";
        }
        case Qt::UserRole+COLUMN_SCORE:
        {
            if (nColumn == COLUMN_SCORE)
                return stu->m_score;
            return "";
        }
        case Qt::UserRole+COLUMN_GENDER:
        {
            if (nColumn == COLUMN_GENDER)
                return stu->m_gender;
            return "";
        }
        case Qt::UserRole+COLUMN_GRADUATE:
        {
            if (nColumn == COLUMN_GRADUATE)
                return stu->m_graduate;
            return "";
        }
        default:
            return QVariant();
    }
    return QVariant();
}

bool StudentModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    if (!index.isValid())
        return false;

    int nRow = index.row();

    S_STU *stu = StuList.at(nRow);
    switch(role){
        case Qt::UserRole+COLUMN_CHECK:
        {
            stu->m_check = value.toBool();
            emit dataChanged(index, index);
            return true;
        }
        case Qt::UserRole+COLUMN_GENDER:
        {
            int val = value.toInt();
            if(val==0)
                stu->m_gender = E_BOY;
            else if(val==1)
                stu->m_gender = E_GIRL;

            emit dataChanged(index, index);
            return true;
        }
        case Qt::UserRole+COLUMN_AGE:
        {
            stu->m_age = value.toInt();
            emit dataChanged(index, index);
            return true;
        }
        case Qt::UserRole+COLUMN_SCORE:
        {
            stu->m_score = value.toInt();
            emit dataChanged(index, index);
            return true;
        }
        case Qt::UserRole+COLUMN_GRADUATE:
        {
            stu->m_graduate = value.toBool();
            emit dataChanged(index, index);
            return true;
        }
        default:
            return false;
    }
    return setData(index,value,role);
}

QVariant StudentModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    switch(role)
    {
        case Qt::TextAlignmentRole:
            return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
        case Qt::DisplayRole:
        {
            if(orientation == Qt::Horizontal){
                if (section == COLUMN_CHECK)
                    return QStringLiteral("Operate");
                if (section == COLUMN_NAME)
                    return QStringLiteral("Name");
                if (section == COLUMN_GENDER)
                    return QStringLiteral("Gender");
                if (section == COLUMN_AGE)
                    return QStringLiteral("Age");
                if (section == COLUMN_SCORE)
                    return QStringLiteral("Score");
                if (section == COLUMN_GRADUATE)
                    return QStringLiteral("Graduate");
            }
        }
        default:
            return QVariant();
    }
    return QVariant();
}

Qt::ItemFlags	StudentModel::flags(const QModelIndex & index) const
{
    if (!index.isValid())
        return QAbstractItemModel::flags(index);

    Qt::ItemFlags flags = QAbstractItemModel::flags(index);

    if(index.column() == COLUMN_CHECK){
        flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    }else if(index.column() == COLUMN_GENDER){
        flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    }else if(index.column() == COLUMN_AGE || index.column() == COLUMN_SCORE){
        flags |= Qt::ItemIsEditable;
    }else if(index.column() == COLUMN_GRADUATE){
        flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
    }

    return flags;
}
3.添加StudentDelegate类,继承于QStyledItemDelegate.同样重载需要使用的虚函数。在这里面,combox和lineEdit控件通过创建编辑器createEditor函数创建,checkbox和开关图标通过paint函数创建。editorEvent函数主要处理checkbox和开关图标的点击处理。
QWidget *	StudentDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    if(index.column() == COLUMN_GENDER){
        QComboBox *combox = new QComboBox(parent);
        combox->addItem("Boy");
        combox->addItem("Girl");
        return combox;
    }else if(index.column() == COLUMN_AGE || index.column() == COLUMN_SCORE ){
        QLineEdit *lineEdit = new QLineEdit(parent);
        return lineEdit;
    }
    return 0;
}

void	StudentDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
{
    if(index.column() == COLUMN_GENDER){
        QComboBox *comboBox = static_cast(editor);
        int value = index.model()->data(index, Qt::UserRole+COLUMN_GENDER).toUInt();
        comboBox->setCurrentIndex(value);
    }else if(index.column() == COLUMN_AGE || index.column() == COLUMN_SCORE){
        QLineEdit *lineEdit = static_cast(editor);
        QString value;
        if(index.column() == COLUMN_AGE)
            value = index.model()->data(index, Qt::DisplayRole).toString();
        else if(index.column() == COLUMN_SCORE)
            value = index.model()->data(index, Qt::DisplayRole).toString();
        lineEdit->setText(value);
    }
}

void	StudentDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
    if(index.column() == COLUMN_GENDER){
        QComboBox *comboBox = static_cast(editor);
        model->setData(index, comboBox->currentIndex(), Qt::UserRole+COLUMN_GENDER);
    }else if(index.column() == COLUMN_AGE || index.column() == COLUMN_SCORE ){
        QLineEdit *lineEdit = static_cast(editor);
        if(index.column() == COLUMN_AGE)
            model->setData(index, lineEdit->text(), Qt::UserRole+COLUMN_AGE);
        else if(index.column() == COLUMN_SCORE)
            model->setData(index, lineEdit->text(), Qt::UserRole+COLUMN_SCORE);
    }
}

void StudentDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem viewOption(option);
    initStyleOption(&viewOption, index);
    if (option.state.testFlag(QStyle::State_HasFocus))
        viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
    QStyledItemDelegate::paint(painter, viewOption, index);

    if (index.column() == COLUMN_CHECK)
    {
        bool data = index.model()->data(index, Qt::UserRole + COLUMN_CHECK).toBool();

        QStyleOptionButton checkBoxStyle;
        checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;
        checkBoxStyle.state |= QStyle::State_Enabled;
        checkBoxStyle.iconSize = QSize(20, 20);
        checkBoxStyle.rect = option.rect;

        QCheckBox checkBox;
        QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &checkBox);
    }
    else if(index.column() == COLUMN_GRADUATE)
    {
        bool data = index.model()->data(index, Qt::UserRole + COLUMN_GRADUATE).toBool();
        QPixmap pixmap;
        if(data)
            pixmap = QPixmap(":/checked.png");
        else
            pixmap = QPixmap(":/unchecked.png");

        int height = (viewOption.rect.height() - 22) / 2;
        QRect decorationRect = QRect(viewOption.rect.left() + viewOption.rect.width() - 90, viewOption.rect.top() + height, 36, 22);
        painter->drawPixmap(decorationRect, pixmap);
    }
}

bool StudentDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    QRect decorationRect = option.rect;

    QMouseEvent *mouseEvent = static_cast(event);
    if (event->type() == QEvent::MouseButtonPress && decorationRect.contains(mouseEvent->pos()))
    {
        if (index.column() == COLUMN_CHECK)
        {
            bool data = model->data(index, Qt::UserRole+COLUMN_CHECK).toBool();
            model->setData(index, !data, Qt::UserRole+COLUMN_CHECK);
        }else if(index.column() == COLUMN_GRADUATE){
            bool data = model->data(index, Qt::UserRole+COLUMN_GRADUATE).toBool();
            model->setData(index, !data, Qt::UserRole+COLUMN_GRADUATE);
        }
    }
    return QStyledItemDelegate::editorEvent(event, model, option, index);
}

4.最后调整各个控件里的参数,然后获取一下数据,点击sure按钮测试,可以看到数据是否写入链表中。

打印内容顺序:姓名    是否选中    性别    年龄    分数    是否毕业  

Qt Model/View理解(四)---实战_第2张图片

Qt Model/View理解(四)---实战_第3张图片





你可能感兴趣的:(QT)