如何使用Model View delegate自定义列表
1个回答
2015-12-29
展开全部
如何使用Model View delegate自定义列表
简介
这是一个演示Model/View Programming 中自定义model,自定义delegate用法的程序。 通过自定义的model,delegate,实现自定义的列表元素。目标是构造一个列表,其中每个列表元素包含若干图片,文字, 按钮等。要实现这样的功能,第一反应是 自己定义一个widget,把图片文字控件放在里面加上layout, 然后再用使用void QAbstractItemView::setIndexWidget,加LlistView或TableView里面。 当界面元素固定,少量的时候,这是首选,但是要看到setIndexWidget帮助文档里面的警告,这样做是有效率代价的,如果列表有100项,那么就要加入100个widget, 很大的消耗。 使用delegate的话你可以只是paint 每个元素, 在需要操作的时候才构建真正的控件,而画控件可以用QStyle::drawControl() 画出来,当然这样做你需要构造,自己的model,delegate, 自己做数据绑定。 这样做效率很高,因为只有当前的控件是真的,其他都是画上去的! 好了动机大概是这样,下面详细介绍如何做。
开始
关于Model/View Programming的使用,最好的文档当然是Qt自己的帮助,建议先通读一遍, 同时参考Qt中的例子:
StringListModel :位于doc\src\snippets\stringlistmodel, 这个例子的代码都在帮助的 Creating New Models这一章,建议阅读的时候顺手做一下,而我下面的例子是在这个例子基础上改成的。
SpinBoxDelegate:这个例子用以演示 如何自定义delegate, 来实现自定义的表元素,每个列表元是个spinbox, 可以编辑。这个例子解释了自定义delegate 的方方面面,但是用的model 是框架自带的
PixelDelegate: 这是个很漂亮的例子,演示了model view delegate的强大威力,其model 和delegate的自定义程度很高,演示了model和delegate之间的数据交互。遗憾的是这是个只读的例子,就是说并不能通过model改变data。
StarDelegate: 这个例子演示了如何定制delegate, 使用了自定义的数据结构,和编辑器,效果很强大,我们的自定义控件也期望这个目标。遗憾是没有定制model。
我们期望自己的StarDelegatedelegate能画上图片等元素 如StarDelegate,PixelDelegate, 又能支持一些系统控件(button,checkbox...)如SpinBoxDelegate,但是上面三个强大的例子都没能完全达到这个目标,所以才写这篇文章。
下面开始新建一个QT工程,选Mobile QT Application, 在ui中拖入一个ListView。
自定义model
为了说明问题,这里用最简单的数据结构,一个QStringList, model 是 数据的直接接口,有了String, 我们可以显示文字,也可以作为路径读取图片,在这个小例子中足够了。按照帮助中 Creating New Models的顺序,首先我们做一个只读的model, 在mainWindow.cpp中 对listview 加载model:
parserModel *model = new parserModel(strings, this);
ui->listView->setModel(model);
只读的model
只读的model 只需要实现rowCount ,data 两个方法, 这里为ListView服务,所以我们继承QAbstractListModel, 如果用TableView的话,可以像PixelDelegate那样使用QAbstractTableModel。
class parserModel : public QAbstractListModel
{
Q_OBJECT
public:
parserModel(const QStringList &strings, QObject *parent = 0);
//basic function for a read-only model
int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
private:
//simple data source just a QStringList, if need can add other list of QString, int, bool, struct or class
QStringList stringList;
};
想要 rowCount 能返回string list 中string的个数,所以我们这样写:
int parserModel::rowCount(const QModelIndex &parent) const
{
return stringList.count();
}
接下来关键的 data 函数,这个函数是 View 或 Delegate 获取数据的主要接口,我们想要显示文字,图片,都是从model中直接获得,我们这样写:
QVariant parserModel::data(const QModelIndex &index, int role) const
{
if ( (!index.isValid()) || (index.row() >= stringList.size()))
return QVariant();
if(role == Qt::UserRole)
{
return stringList.at(index.row());
}
else if( role == Qt::UserRole+1)
{
QPixmap pixmap;
pixmap.load(stringList.at(index.row()));
return pixmap.scaled(80, 80,Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
}
else if( role == Qt::UserRole+2)
{
QPixmap pixmap;
pixmap.load(stringList.at(index.row()));
return pixmap.scaled(20, 20,Qt::KeepAspectRatio, Qt::FastTransformation);
}
return QVariant();
}
这里默认是返回QVariant(), 关键是看中间返回的东西,必须结合后面的Delegate实现来一起看。 当delegate 或 view 询问数据的时候会传给data方法两个参数,就是问model要 位于 index这个地方的具有role数据,enum Qt::ItemDataRole 中常见的role是
Qt::DisplayRole 返回 QString 文字
Qt::DecorationRole 返回 QPixmap 图片
但是如果你想要返回另一幅图的话,就要用其他的role了,所以这里我全用 Qt::UserRole,来解释这个问题。 一个解释Qt::ItemDataRole 的例子是 Color Editor Factory,在这个例子中列表显示颜色和颜色名,都是从颜色名字符串中读数据,但是显示的时候一个是颜色方块,和名字,这就是同一个数据的两种表现形式,两个role。更进一步的,你可以在model中再引用一个struct 或者class Data, 当被询问不同的role的时候返回 Data.str1,或 Data.int2, 这样同一个index可以返回不同的数据,不同的数据类型。也可以是SQL查询的结果,在选择语句中传入不同的查询参数,这取决于你的数据结构,总之data被model 包装隔离了。不清楚没关系,下面我们看delegate如何数据。
自定义delegate
QT 4.6以后推荐自定义delegate 继承自QStyledItemDelegate,使用styleSheet来显示。不失一般性,这里先用QItemDelegate来说明问题。在mainWindow.cpp中 对listview 加载delegate:
MyDelegate *delegate = new MyDelegate(this);
ui->listView->setItemDelegate(delegate);
只读的delegate
先做只读的功能,需要重写 paint,和sizeHint 这个函数
class MyDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit MyDelegate(QObject *parent = 0);
简介
这是一个演示Model/View Programming 中自定义model,自定义delegate用法的程序。 通过自定义的model,delegate,实现自定义的列表元素。目标是构造一个列表,其中每个列表元素包含若干图片,文字, 按钮等。要实现这样的功能,第一反应是 自己定义一个widget,把图片文字控件放在里面加上layout, 然后再用使用void QAbstractItemView::setIndexWidget,加LlistView或TableView里面。 当界面元素固定,少量的时候,这是首选,但是要看到setIndexWidget帮助文档里面的警告,这样做是有效率代价的,如果列表有100项,那么就要加入100个widget, 很大的消耗。 使用delegate的话你可以只是paint 每个元素, 在需要操作的时候才构建真正的控件,而画控件可以用QStyle::drawControl() 画出来,当然这样做你需要构造,自己的model,delegate, 自己做数据绑定。 这样做效率很高,因为只有当前的控件是真的,其他都是画上去的! 好了动机大概是这样,下面详细介绍如何做。
开始
关于Model/View Programming的使用,最好的文档当然是Qt自己的帮助,建议先通读一遍, 同时参考Qt中的例子:
StringListModel :位于doc\src\snippets\stringlistmodel, 这个例子的代码都在帮助的 Creating New Models这一章,建议阅读的时候顺手做一下,而我下面的例子是在这个例子基础上改成的。
SpinBoxDelegate:这个例子用以演示 如何自定义delegate, 来实现自定义的表元素,每个列表元是个spinbox, 可以编辑。这个例子解释了自定义delegate 的方方面面,但是用的model 是框架自带的
PixelDelegate: 这是个很漂亮的例子,演示了model view delegate的强大威力,其model 和delegate的自定义程度很高,演示了model和delegate之间的数据交互。遗憾的是这是个只读的例子,就是说并不能通过model改变data。
StarDelegate: 这个例子演示了如何定制delegate, 使用了自定义的数据结构,和编辑器,效果很强大,我们的自定义控件也期望这个目标。遗憾是没有定制model。
我们期望自己的StarDelegatedelegate能画上图片等元素 如StarDelegate,PixelDelegate, 又能支持一些系统控件(button,checkbox...)如SpinBoxDelegate,但是上面三个强大的例子都没能完全达到这个目标,所以才写这篇文章。
下面开始新建一个QT工程,选Mobile QT Application, 在ui中拖入一个ListView。
自定义model
为了说明问题,这里用最简单的数据结构,一个QStringList, model 是 数据的直接接口,有了String, 我们可以显示文字,也可以作为路径读取图片,在这个小例子中足够了。按照帮助中 Creating New Models的顺序,首先我们做一个只读的model, 在mainWindow.cpp中 对listview 加载model:
parserModel *model = new parserModel(strings, this);
ui->listView->setModel(model);
只读的model
只读的model 只需要实现rowCount ,data 两个方法, 这里为ListView服务,所以我们继承QAbstractListModel, 如果用TableView的话,可以像PixelDelegate那样使用QAbstractTableModel。
class parserModel : public QAbstractListModel
{
Q_OBJECT
public:
parserModel(const QStringList &strings, QObject *parent = 0);
//basic function for a read-only model
int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
private:
//simple data source just a QStringList, if need can add other list of QString, int, bool, struct or class
QStringList stringList;
};
想要 rowCount 能返回string list 中string的个数,所以我们这样写:
int parserModel::rowCount(const QModelIndex &parent) const
{
return stringList.count();
}
接下来关键的 data 函数,这个函数是 View 或 Delegate 获取数据的主要接口,我们想要显示文字,图片,都是从model中直接获得,我们这样写:
QVariant parserModel::data(const QModelIndex &index, int role) const
{
if ( (!index.isValid()) || (index.row() >= stringList.size()))
return QVariant();
if(role == Qt::UserRole)
{
return stringList.at(index.row());
}
else if( role == Qt::UserRole+1)
{
QPixmap pixmap;
pixmap.load(stringList.at(index.row()));
return pixmap.scaled(80, 80,Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
}
else if( role == Qt::UserRole+2)
{
QPixmap pixmap;
pixmap.load(stringList.at(index.row()));
return pixmap.scaled(20, 20,Qt::KeepAspectRatio, Qt::FastTransformation);
}
return QVariant();
}
这里默认是返回QVariant(), 关键是看中间返回的东西,必须结合后面的Delegate实现来一起看。 当delegate 或 view 询问数据的时候会传给data方法两个参数,就是问model要 位于 index这个地方的具有role数据,enum Qt::ItemDataRole 中常见的role是
Qt::DisplayRole 返回 QString 文字
Qt::DecorationRole 返回 QPixmap 图片
但是如果你想要返回另一幅图的话,就要用其他的role了,所以这里我全用 Qt::UserRole,来解释这个问题。 一个解释Qt::ItemDataRole 的例子是 Color Editor Factory,在这个例子中列表显示颜色和颜色名,都是从颜色名字符串中读数据,但是显示的时候一个是颜色方块,和名字,这就是同一个数据的两种表现形式,两个role。更进一步的,你可以在model中再引用一个struct 或者class Data, 当被询问不同的role的时候返回 Data.str1,或 Data.int2, 这样同一个index可以返回不同的数据,不同的数据类型。也可以是SQL查询的结果,在选择语句中传入不同的查询参数,这取决于你的数据结构,总之data被model 包装隔离了。不清楚没关系,下面我们看delegate如何数据。
自定义delegate
QT 4.6以后推荐自定义delegate 继承自QStyledItemDelegate,使用styleSheet来显示。不失一般性,这里先用QItemDelegate来说明问题。在mainWindow.cpp中 对listview 加载delegate:
MyDelegate *delegate = new MyDelegate(this);
ui->listView->setItemDelegate(delegate);
只读的delegate
先做只读的功能,需要重写 paint,和sizeHint 这个函数
class MyDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit MyDelegate(QObject *parent = 0);
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询