一、使用项视图
项视图(item view)
item view convenience classes use a clssic item-based interface
rather than a pure model/view approach.
list items are typically used to display text() and an icon()
1.QListWidget
默认是只读的
通过QListWidgetItem *item = new QListWidgetItem()
additem()函数将QListWidgetItem加入到QListWidget显示
2.QTableWidget
默认是可编辑的
QTableWidgetItem类为QTableWidget提供项
setitem()是插入的方法
setVerticalHeaderLabels()
setHorizontalHeaderLabels()
设置表头
3.QTreeWidget
默认是只读的
QListWidgetItem类为QTreeWidget提供项
上面三个类是为视图提供了一个简便的方法,因为它们已经有了默认的或者预置的model
我们只要将相应的项编辑然后加进去即可
二、下面介绍使用MV/D方法视图
model代表数据,它对数据的存取负责,为视图提供相同的API
view代表面向用户的数据
delegate,用于对项的显示和编辑提供精细控制。
Qt对每种类型的视图提供默认的委托。
model与view分开,可以让一个model支持多个同步的view,而且各自修改,互不影响。
model和view通过QModelIndex类实例连接起来。
QModelIndex主要是为了指明model中项的位置。QModelIndex实例有自己的行,列信息,有
父对象,兄弟对象,和子对象信息
还能携带有关model位置项的data(),flag(),internalId()的信息。还有一个
internalPointer()指针。
一般常用的只有位置信息了。
QStringListModel
一般类中会有两个成员:QListView和QStringListModel两个实例
使用实例:
model = new QStringListModel(this);
model->setStringList(leaders);
listView = new QListView;
listView->setModel(model);
listView->setEditTriggers(QAbstractItemView::AnyKeyPressed
| QAbstractItemView::DoubleClicked);
当要对view中的内容修改时,要修改model
使用实例
int row = listView->currentIndex().row();
model->insertRows(row, 1);
QModelIndex index = model->index(row);
listView->setCurrentIndex(index);
listView->edit(index);
model->removeRows(listView->currentIndex().row(), 1);
QStringListModel封装了QStringList,为view提供了操作接口,它的QModelIndex
最后要注意的是,当使用完可修改的model后,要提供一个返回model修改后内容的方法
return model->stringList();
QDirModel操作实例
model = new QDirModel;
model->setReadOnly(false);
model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name);
treeView = new QTreeView;
treeView->setModel(model);
treeView->header()->setStretchLastSection(true);
treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
treeView->header()->setSortIndicatorShown(true);
treeView->header()->setClickable(true);
model->mkdir(index, dirName);
model->fileInfo(index);
model->rmdir(index);
model->remove(index);
QSortFilterProxyModel
The QSortFilterProxyModel class provides support for sorting and filtering data
passed between another model and a view.
(也就是,它必须要依赖一个model或者view才能使用)
QSortFilterProxyModel can be used for sorting items, filtering out items, or both.
The model transforms the structure of a source model by mapping the model indexes
it supplies to new indexes, corresponding to different locations, for views to
use. This approach allows a given source model to be restructured as far as views
are concerned without requiring any transformations on the underlying data, and
without duplicating the data in memory.
使用eg:
sourceModel = new QStringListModel(this);
sourceModel->setStringList(QColor::colorNames());
proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterKeyColumn(0);
listView = new QListView;
listView->setModel(proxyModel);
listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
QRegExp::PatternSyntax syntax =
QRegExp::PatternSyntax(syntaxComboBox->itemData(
syntaxComboBox->currentIndex()).toInt());
QRegExp regExp(filterLineEdit->text(), Qt::CaseInsensitive, syntax);
proxyModel->setFilterRegExp(regExp);
自定义model
QAbstractTableModel
根据subclassing介绍,要重新实现rowCount(),columnCount()和data()三个函数
修改表头:headerData()
如果要让QAbstractTableModel变得可编辑,就要重新实现
setData()和flags()
setData()主要是将view中取得的数据在底层更新,注意在数据更新完后,要发射
dataChanged()信号
data()主要是将底层的数据取出返回给view
flags()主要是将Qt::ItemIsEditable标志加到flags里。
QAbstractItemModel
它不是方便的子类,继承这个model除了要实现rowCount(),columnCount()和data()三个函数
外,还要实现index(), parent()这两个函数。
如果要实现层次模型,在创建index()时,可将index的内部指针指向一个内部的节点
三、delegate
QItemDelegate
它能够为QAbstractItemView子类提供个性化的显示特性和编辑部件。能够让显示和编辑在
model和view中独立。
QStyledItemDelegate已经接管了QItemDelegate的工作,所以在创建新的delegates时建议使
用QStyledItemDelegate。
在标准view中显示model项时,可以简单地让model返回正确角色值。如果想有更多地控制就需
要用户自己创建delegate
QAbstractItemDelegate已经提供了 paint() ,sizeHint()虚函数。用户要重新实现它们。
当view被编辑时,要有一个编辑部件。使用QItemEditorFactory创建编辑部件,
QItemDelegate中已有了默认的编辑部件,用户可以使用setItemEditorFactory()来设置自己
的编辑部件,或 QItemEditorFactory::setDefaultFactory()设置默认的编辑部件。
被编辑的model中的数据是放在Qt::EditRole角色里。
可重新实现的函数
createEditor()返回一个编辑部件。
setEditorData()提供给编辑部件数据
updateEditorGeometry(),保证编辑部件有一个正确的显示位置和大小
setModelData(),将数据更新到model中。
closeEditor()信号表示数据编辑完成,可以销毁编辑部件
使用eg:
//为窗口部件设置一个delegate
tableWidget= newQTableWidget(tracks->count(),2);
tableWidget->setItemDelegate(new TrackDelegate(1));
实现自定义的delegate
void TrackDelegate::paint(QPainter*painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.column() == durationColumn) {
int secs = index.model()->data(index, Qt::DisplayRole).toInt();
QString text = QString("%1:%2")
.arg(secs / 60, 2, 10, QChar('0'))
.arg(secs % 60, 2, 10, QChar('0'));
QStyleOptionViewItem myOption = option;
myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
drawDisplay(painter, myOption, myOption.rect, text);
drawFocus(painter, myOption, myOption.rect);
} else{
QItemDelegate::paint(painter, option, index);
}
}
//当用户初始化编辑的时候,会调用createEditor(),然后调用setEditorData()
//初始化编辑器的数据。当用户按下了enter键,或者单击了编辑框以外的空间,
//就会调用setModelData()函数
QWidget *TrackDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.column() == durationColumn) {
QTimeEdit *timeEdit = new QTimeEdit(parent);
timeEdit->setDisplayFormat("mm:ss");
connect(timeEdit, SIGNAL(editingFinished()),
this, SLOT(commitAndCloseEditor()));
return timeEdit;
} else {
return QItemDelegate::createEditor(parent, option, index);
}
}
void TrackDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
if (index.column() == durationColumn) {
int secs = index.model()->data(index, Qt::DisplayRole).toInt();
QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);
timeEdit->setTime(QTime(0, secs / 60, secs % 60));
} else {
QItemDelegate::setEditorData(editor, index);
}
}
void TrackDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
if (index.column() == durationColumn) {
QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);
QTime time = timeEdit->time();
int secs = (time.minute() * 60) + time.second();
model->setData(index, secs);
} else {
QItemDelegate::setModelData(editor, model, index);
}
}
void TrackDelegate::commitAndCloseEditor()
{
QTimeEdit *editor = qobject_cast<QTimeEdit *>(sender());
emit commitData(editor);//通知视图用被编辑的数据替换已经存在的数据
emit closeEditor(editor);//通知视图删除编辑器
}
自定义view
继承QAbstractItemView中的所有纯虚函数都必须进行声明,这些必须声明的纯虚函数包括
visualRect(),scrollTo(),indexAt(),moveCursor(),horizontalOffset(),verticalOffset
(),isIndexHidden(),setSelection()和visualRegionForSelecion(),这些函数并不一实都要
实现,根据功能要求选择实现。
保用paintEvent()实现自定义view的绘制工作。
创建绘图设备
QPainter painter(viewport());
数据来源:
QModelIndex index = model()->index(row, 0, rootIndex());
QString dep = model()->data(index).toString();
if (selections->isSelected(index))
{
}
选择区的处理
重现mousePressEvent,根据mouse的position,画一个小矩形,
然后判断小矩形和index关联的矩形是否有交集,如果有,就返回
一个index.
调用:selections->select(selectedIndex,flags);确定选择的索引
indexAt()
根据viewport在位置,返回一个index