主要功能:利用QListview显示自定的model数据和内容;显示内容包括QCheckbox, QLabel。

 

实现原理:QCheckbox在页面显示,就是根据model数据中的按钮的选中状态来显示对应图片, 然后画出对应的图片;同样道理,我们可以添加各种自定义button,自定义button的各种状态图片。

效果如图:

代码:

头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QAbstractListModel>
#include <QStyledItemDelegate>
#include <QListView>

struct CustomData
{
    bool m_isSelect;
    QString m_txt;
};

class CustomListModel : public QAbstractListModel
{
    Q_OBJECT

public:
    CustomListModel();
    ~CustomListModel();

    void insertData(CustomData data);

    //必须实现的函数
    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
    QList<CustomData> m_listData;
};


class CustomDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    CustomDelegate();
    ~CustomDelegate();

    //描绘画面显示
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

    //处理鼠标事件
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QListView *m_list;
    CustomListModel *m_model;
    CustomDelegate * m_delegate;
};

#endif // MAINWINDOW_H

cpp文件:

#include <QPainter>
#include <QDebug>
#include <QMouseEvent>
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setGeometry(200,200,800,480);


    m_list = new QListView(this);
    m_list->setGeometry(0,0,300,200);

    m_model = new CustomListModel();
    //添加测试数据库
    for(int i = 0; i < 5; i++)
    {
        CustomData data;
        data.m_isSelect = (i%2==0);
        data.m_txt = QString("This is %1").arg(QString::number(i+1));
        m_model->insertData(data);
    }

    m_delegate = new CustomDelegate();

    m_list->setModel(m_model);
    m_list->setItemDelegate(m_delegate);
    m_list->setMouseTracking(true);

}

MainWindow::~MainWindow()
{

}

CustomListModel::CustomListModel()
{

}

CustomListModel::~CustomListModel()
{

}

void CustomListModel::insertData(CustomData data)
{
    m_listData.push_back(data);
}

int CustomListModel::rowCount(const QModelIndex &parent) const
{
    return m_listData.size();
}

QVariant CustomListModel::data(const QModelIndex &index, int role) const
{
    QVariant ret;
    int row = index.row();

    if(row>=m_listData.size()||(!index.isValid()))
    {
        return QVariant();
    }

    CustomData tmpData = m_listData.at(row);

    // 下面的role要和setData中的role一一对应;
    switch(role) {
    case Qt::UserRole+1:
        ret = tmpData.m_isSelect;
        break;
    case Qt::UserRole+2:
        ret = tmpData.m_txt;
        break;
    default :
        break;

    }
    return ret;
}

bool CustomListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    bool ret = false;
    int row = index.row();

    if(row>=m_listData.size()||(!index.isValid()))
    {
        return false;
    }
    CustomData tmpData = m_listData.at(row);

    switch(role) {
    case Qt::UserRole+1:
        tmpData.m_isSelect = value.toBool();
        ret = true;
        break;
    case Qt::UserRole+2:
        tmpData.m_txt = value.toString();
        ret = true;
        break;
    default :
        break;
    }
    m_listData.replace(row, tmpData);
    return ret;
}

CustomDelegate::CustomDelegate()
{

}

CustomDelegate::~CustomDelegate()
{

}

void CustomDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QRect retc = option.rect;

    //这里取的数据 对应model里面的role
    bool isSelect = index.data(Qt::UserRole+1).toBool();
    QString txt = index.data(Qt::UserRole+2).toString();

    //qDebug() << "paint data isSelect" << isSelect << "txt" << txt;

    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);


    //画按钮
    {
        QRect checboxRec(retc.left() + 10, retc.top() + (retc.height()-20)/2, 20, 20); //左边距10,竖直方向居中

        if(isSelect)
        {
            QPixmap pix("G:\\QT_Project\\listViewModelDelegate\\fxk_not.png");
            painter->drawPixmap(checboxRec, pix);
        }
        else
        {
            QPixmap pix("G:\\QT_Project\\listViewModelDelegate\\fxk_ok.png");
            painter->drawPixmap(checboxRec, pix);
        }
    }


    //画txt
    {
        painter->save();

        //设置字体,颜色
        QFont font;
        font.setFamily("Microsoft YaHei");
        font.setPixelSize(10);
        painter->setFont(font);

        QRect txtRec(retc.left() + 50, retc.top(), retc.width()-100, retc.height());
        painter->drawText(txtRec, Qt::AlignCenter, txt);

        painter->restore();
    }
}

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

    //对应上面画的checkbox的retc
    QRect checboxRec(retc.left() + 10, retc.top() + (retc.height()-20)/2, 20, 20);

    //按钮点击事件;
    QMouseEvent *mevent = static_cast<QMouseEvent*>(event);
    if(checboxRec.contains(mevent->pos()) && event->type() == QEvent::MouseButtonPress)
    {
        bool value = model->data(index, Qt::UserRole+1).toBool();
        model->setData(index, !value, Qt::UserRole+1);
        model->dataChanged(index, index);

        //此处可以添加自定义信号,即使checbox点击信号;
    }

    return QStyledItemDelegate::editorEvent(event, model, option, index);
}

总结:

按钮的显示,归根到底就是根据鼠标事件选择显示对应的图片;主要函数就是delegate中的paint函数和editorEvent函数;paint负责渲染,editorEvent负责鼠标事件;根据此框架,可以满足绝大部分的定制需求;

 

转载请注明出处;

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐