您的位置:首页 > 编程语言 > Qt开发

qt中的委托-简单的应用

2016-06-07 19:24 399 查看
qt中表格的数据默认是无法编辑的,当在model的flag()函数中设置其可编辑后,双击数据可以通过lineEdit(qt默认的编辑器是一个有边框的lineEdit)对数据进行编辑,但有时我们希望数据可以通过用下拉框来选择或者其他的编辑器来编辑数据,或者我们希望通过鼠标点击此数据来触发某个事件达到修改数据的目的或者其他的什么目的。这时就要用到委托QstyleItemDelegate。

qt默认的编辑器的效果:



如果我们想要达到下拉框的效果:



必须要重写三个函数:

1.QWidget*createEditor()  告诉model用的是那个编辑器进行数据的编辑和选择

2.voidsetEditorData()        从model中读取数据,设置编辑器显示的数据

3.voidsetModelData( )        从编辑器中读取当前显示的数据,设置model中的数据源

代码如下:

#include <QStyledItemDelegate>

class QModelIndex;
class QPainter;
class QStyleOptionViewItem;

class ItemDelegate : public QStyledItemDelegate
{
Q_OBJECT

public:
explicit ItemDelegate(QObject *parent=0)
: QStyledItemDelegate(parent) {}

QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor,
const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
};
对应的.cpp 文件中:

QWidget *ItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
static QStringList usStates;
if (usStates.isEmpty())
usStates << "(Unknown)" << "Alabama" << "Alaska"
<< "Arizona" << "Arkansas" << "California"
<< "Colorado" << "Connecticut" << "Delaware"
<< "District Of Columbia" << "Florida" << "Georgia";

QComboBox *editor = new QComboBox(parent);
//设置好对应的编辑器,添加好其中的内容及其大小的边界限制等
editor->addItems(usStates);
return editor;
}


void ItemDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
//获取model数据源中的数据
QString state = index.model()->data(index).toString();
//获取编辑器-下拉框
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
Q_ASSERT(comboBox);
//设置编辑器的当前数据
comboBox->setCurrentIndex(comboBox->findText(state));
}
void ItemDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model, const QModelIndex &index) const
{
//获取编辑器
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
Q_ASSERT(comboBox);
//将编辑器中的当前数据更改保存到model的数据源中
model->setData(index, comboBox->currentText());
}


当表格中不同的地方要用不同的编辑器时,如下,zipcode列用自定义的ZipcodeSpinBox ,state列用下拉框。
代码如下:

QWidget *ItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
static QStringList usStates;
if (usStates.isEmpty())
usStates << "(Unknown)" << "Alabama" << "Alaska"
<< "Arizona" << "Arkansas" << "California"
<< "Colorado" << "Connecticut" << "Delaware"
<< "District Of Columbia" << "Florida" << "Georgia"
<< "Hawaii" << "Idaho" << "Illinois" << "Indiana"
<< "Iowa" << "Kansas" << "Kentucky" << "Louisiana"
<< "Maine" << "Maryland" << "Massachusetts"
<< "Michigan" << "Minnesota" << "Mississippi"
<< "Missouri" << "Montana" << "Nebraska" << "Nevada"
<< "New Hampshire" << "New Jersey" << "New Mexico"
<< "New York" << "North Carolina" << "North Dakota"
<< "Ohio" << "Oklahoma" << "Oregon" << "Pennsylvania"
<< "Rhode Island" << "South Carolina"
<< "South Dakota" << "State" << "Tennessee" << "Texas"
<< "Utah" << "Vermont" << "Virginia" << "Washington"
<< "West Virginia" << "Wisconsin" << "Wyoming";

if (index.column() == Zipcode)
return new ZipcodeSpinBox(parent);
if (index.column() == State) {
QComboBox *editor = new QComboBox(parent);
editor->addItems(usStates);
return editor;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}

void ItemDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
if (index.column() == Zipcode) {
int value = index.model()->data(index).toInt();
ZipcodeSpinBox *spinBox =
qobject_cast<ZipcodeSpinBox*>(editor);
Q_ASSERT(spinBox);
spinBox->setValue(value);
}
else if (index.column() == State) {
QString state = index.model()->data(index).toString();
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
Q_ASSERT(comboBox);
comboBox->setCurrentIndex(comboBox->findText(state));
}
else
QStyledItemDelegate::setEditorData(editor, index);
}

void ItemDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model, const QModelIndex &index) const
{
if (index.column() == Zipcode) {
ZipcodeSpinBox *spinBox =
qobject_cast<ZipcodeSpinBox*>(editor);
Q_ASSERT(spinBox);
spinBox->interpretText();
model->setData(index, spinBox->value());
}
else if (index.column() == State) {
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
Q_ASSERT(comboBox);
model->setData(index, comboBox->currentText());
}
else
QStyledItemDelegate::setModelData(editor, model, index);
}

mainWindow中:

tableView->setItemDelegate(new ItemDelegate(this));


还有一种是分开写的:
#ifndef COMBODELEGATE_H
#define COMBODELEGATE_H

#include <QItemDelegate>

class ComboDelegate : public QItemDelegate
{
Q_OBJECT
public:
ComboDelegate(QObject *parent = 0);

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex	&index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const  QModelIndex &index) const;
};

#endif // COMBODELEGATE_H
#include "combodelegate.h"
#include <QComboBox>

ComboDelegate::ComboDelegate(QObject *parent) :
QItemDelegate(parent)
{
}

QWidget *ComboDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &/*option*/,const QModelIndex &/*index*/) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem("工人");
editor->addItem("农民");
editor->addItem("医生");
editor->addItem("律师");
editor->addItem("军人");
editor->installEventFilter(const_cast<ComboDelegate*>(this));
return editor;
}

void ComboDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
QString str =index.model()->data(index).toString();

QComboBox *box = static_cast<QComboBox*>(editor);
int i=box->findText(str);
box->setCurrentIndex(i);
}

void ComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *box = static_cast<QComboBox*>(editor);
QString str = box->currentText();
model->setData(index,str);
}

void ComboDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
editor->setGeometry(option.rect);
}
</pre><pre name="code" class="cpp"><pre name="code" class="cpp">#ifndef DATEDELEGATE_H
#define DATEDELEGATE_H

#include <QItemDelegate>

class DateDelegate : public QItemDelegate
{
Q_OBJECT
public:
DateDelegate(QObject *parent = 0);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

#endif // DATEDELEGATE_H




#include "datedelegate.h"
#include <QDateTimeEdit>

DateDelegate::DateDelegate(QObject *parent) :
QItemDelegate(parent)
{
}

QWidget *DateDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &/*option*/,const QModelIndex &/*index*/) const
{
QDateTimeEdit *editor = new QDateTimeEdit(parent);
editor->setDisplayFormat("yyyy-MM-dd");
editor->setCalendarPopup(true);
editor->installEventFilter(const_cast<DateDelegate*>(this));
return editor;
}

void DateDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
QString dateStr= index.model()->data(index).toString();
QDate date = QDate::fromString(dateStr,Qt::ISODate);

QDateTimeEdit *edit=static_cast<QDateTimeEdit*>(editor);
edit->setDate(date);
}

void DateDelegate::setModelData(QWidget *editor,QAbstractItemModel *model, const QModelIndex &index) const
{
QDateTimeEdit *edit=static_cast<QDateTimeEdit*>(editor);
QDate date = edit->date();
model->setData(index,QVariant(date.toString(Qt::ISODate)));
}

void DateDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}

#ifndef SPINDELEGATE_H
#define SPINDELEGATE_H

#include <QItemDelegate>

class SpinDelegate : public QItemDelegate
{
Q_OBJECT
public:
SpinDelegate(QObject *parent = 0);

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex  &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

#endif // SPINDELEGATE_H
#include "spindelegate.h"
#include <QSpinBox>

SpinDelegate::SpinDelegate(QObject *parent):
QItemDelegate(parent)
{
}

QWidget *SpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &/*option*/,const QModelIndex &/*index*/) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setRange(0,10000);
editor->installEventFilter(const_cast<SpinDelegate*>(this));

return editor;
}

void SpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
int value =index.model()->data(index).toInt();
QSpinBox *box = static_cast<QSpinBox*>(editor);
box->setValue(value);
}

void SpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const
{
QSpinBox *box = static_cast<QSpinBox*>(editor);
int value = box->value();

model->setData(index,value);
}

void SpinDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
editor->setGeometry(option.rect);
}


main函数中:

QStandardItemModel model(4,4);
QTableView tableView;
tableView.setModel(&model);
DateDelegate dateDelegate;
tableView.setItemDelegateForColumn(1,&dateDelegate);
ComboDelegate comboDelegate;
tableView.setItemDelegateForColumn(2,&comboDelegate);
SpinDelegate spinDelegate;
tableView.setItemDelegateForColumn(3,&spinDelegate);


最后说一下paint功能和editEvent
paint可以绘制一些Qt没有提供的图形,下面举例:获取模型的数据,通过数据来改变进度条的显示

void ProgressBarDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
//绘制进度条
if(index.column() == 2)
{
//数据
int progress = index.model ()->data(index, Qt::DisplayRole).toInt ();
//进度条
QStyleOptionProgressBarV2 progressBarOption;
progressBarOption.state = QStyle:: State_Enabled;
progressBarOption.direction = QApplication:: layoutDirection ();
progressBarOption.rect = option.rect;
progressBarOption.fontMetrics = QApplication:: fontMetrics ();
progressBarOption.minimum = 0;
progressBarOption.maximum = 100;
progressBarOption.textAlignment = Qt:: AlignCenter;
progressBarOption.textVisible = true;
progressBarOption.progress = progress;
progressBarOption.text = QString("%1%").arg(progressBarOption.progress);
//上面的进度条是QtyleOption,需要通过此纯虚函数绘制
QApplication:: style ()->drawControl(QStyle::CE_ProgressBar,
&progressBarOption, painter);
} else {
return QItemDelegate::paint (painter, option, index);
}
}

显示效果:



更具体的介绍可查看:http://qimo601.iteye.com/blog/1539147

委托中的editEvent用的比较少,主要是处理要通过像通过鼠标点击等来达到编辑的不同效果时用,但是事件是通过view后再传下来的,一般直接写到view的Event()中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息