在qt数据的显示中经常有用到数据显示的model/view结构,简单说一下就是简单的数据我们可以直接用类似于listwidget之类的已经实现好的类来操作,但是当数据我们想要有比较好的分离控制的时候,会把数据和显示分开来,用model来存储和修改数据,view只是用来显示这些数据,而在两者之间,我们可以通过delegate代理类在两者之间充当一个中间层进行数据的过滤之类的操作,或者是让数据按照我们的想法来显示。

 

这次举例用的是比较通用的tableview ,tablemodel。首先是数据的model类,那么需要继承一个QAbstractTableModelcolumnCount,rowCount这两个获取行列数量的,还有两个获取数据的,headerData用于view来获取表格的行列的标题,然后data则是获取表格项的数据了。简单的代码例子:

两个函数一起来了:

QVariant xxxModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    //横向的标题
    if(orientation == Qt::Horizontal) {
        if (role == Qt::TextAlignmentRole) {
                return int(Qt::AlignHCenter | Qt::AlignVCenter);
            }
        //section列数小于存储的标题list(HheaderStr) 的长度的时候返回标题字串
        if(role == Qt::DisplayRole && section < HheaderStr.count())
        {
            if(section!=0)
                return HheaderStr.at(section);
            else
                return "";
        }
        //为第一行添加icon的装饰
        if(role==Qt::DecorationRole && section ==0)
            return QIcon(":/image/image/xxx.ico");
    }else
        //纵向的标题
        if(orientation == Qt::Vertical)
        {
            if(role == Qt::DisplayRole ) {
                return section+1;
            }
        }
    return QAbstractTableModel::headerData(section, orientation, role);
}
//表项数据的处理
QVariant xxxModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
    {
        return QVariant();
    }
    if (role == Qt::TextAlignmentRole) {
            return int(Qt::AlignHCenter | Qt::AlignVCenter);
        }
    else if (role == Qt::DisplayRole)
    {
        if(index.column() < HheaderStr.count())
        {   //这里就是你定下的数据的返回
            return xxxList.at(index.row()).at(index.column());
        }
        else
            return QVariant();
    }
    return QVariant();
}

注释都比较清楚了。看一下大概。因为我只是对于数据的显示形式做一个变化,所以基本model类除了保存返回数据,基本不需要在做什么。大部分的操作都是在继承自QStyledItemDelegate的类里面操作。大概的代码就是:

class xxxDelegate : public  QStyledItemDelegate
{
public:
    xxxDelegate(QObject * parent=0);
    virtual ~ xxxDelegate(){}

    void paint(QPainter * painter,
        const QStyleOptionViewItem & option,
        const QModelIndex & index) const;
};

在重写的paint函数里面完成你自己想做的操作就可以了。比如我这里是在第0列,会放一个图标,在第3列会让数据按照百分比来绘制不同的长度最后加上百分号数值:

table template_ico

//重写这个函数来改变表项自定义的显示方式,可以插入控件,绘图等等。
void xxxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //不需要特许处理的表项,返回
    if(index.column()!=0&&index.column()!=3)
    {
        return QStyledItemDelegate::paint(painter,option,index);
    }
    //保存一下原本的painter便于操作完后恢复,减少影响
    painter->save();
    if(index.column()==0)
    {//第一栏设置图片
        painter->drawImage(option.rect,QImage(":/image/image/icon_14.png"));
    }else
    {//百分比栏
        //按照百分比绘制长条和百分比的文字信息。
        int textW = option.fontMetrics.width("100.00%");
//取出数据
QString text = index.model()->data(index, Qt::DisplayRole).toString();
        int maxNum = ( (VideoStatisticsModel*)index.model() )->maxNum;
        double percent = text.toDouble();
        QRect optionRect=option.rect;
        int rectMaxW = optionRect.width()-textW;
        int paintRecWidth = 0;
        if(maxNum>0)
            paintRecWidth = (int)percent*rectMaxW/maxNum;
//画矩形
painter->fillRect(optionRect.x(),optionRect.y(),paintRecWidth,optionRect.height(),Qt::gray);
        text +="%";
//后面附加文字
painter->drawText(optionRect.x()+paintRecWidth,optionRect.y(),textW,optionRect.height(),Qt::AlignCenter,text);
    }
    painter->restore();
}

效果就是上面图这样子,灵活性真的很大,能够实现很完全的自定的显示的界面的东西。看下上面说的两个参考的地址,也举了很多种方案的例子了。