在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列会让数据按照百分比来绘制不同的长度最后加上百分号数值:
//重写这个函数来改变表项自定义的显示方式,可以插入控件,绘图等等。
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();
}
效果就是上面图这样子,灵活性真的很大,能够实现很完全的自定的显示的界面的东西。看下上面说的两个参考的地址,也举了很多种方案的例子了。