计算机系统应用教程网站

网站首页 > 技术文章 正文

Qt编程进阶(83):利用特定控件进行表项编辑(Delegate方式)

btikc 2024-10-20 05:04:28 技术文章 8 ℃ 0 评论

在表格中嵌入各种不同控件,可通过控件对编辑的内容进行限定。在本文实例中,利用Delegate的方式嵌入控件,且控件只在需要编辑数据项时才出现,如下图所示(为简洁起见三图合成)。

表格中有3种不同的控件,分别是用于生日输入的日历编辑框QDateLineEdit、下拉列表框QComboBox和一个QSpinBox,因此需实现3个Delegate对象:DateDelegate、ComboDelegate和SpinDelegate,这3个Delegate都是Widget类型的控件,因此都采用继承QltemDelegate的方式实现。下面分别对3个Delegate的实现进行介绍。

一、DateDelegate的实现

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;
};

DateDelegate继承自QltemDelegate类,实现一个自定义的Delegate,一般需要重定义声明中的几个虚函数。createEditor()函数完成创建控件的工作,创建由参数中QModellndex对象指定的表项数据的编辑控件,并对控件的内容进行限定;setEditorData()函数设置控件显示的数据,把Model中的数据更新至Delegate中,相当于一个初始化的工作;setModelData()函数把Delegate中对数据的改变更新至Model中。updateEditor()函数更新控件区的显示。

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

其中:

  • (a):新建一个QDateTimeEdit对象作为编辑时的输入控件。
  • (b):设置此QDateTimeEdit对象的显示格式为yyyy-MM-dd,此显示方式为ISO方式。日期显示的格式可以有很多种,以QString的方式设置,可根据需要进行设定,如:
yy.MM.dd 08.01.01
d.MM.yyyy 1.01.2008

其中,y表示年,M表示月份,d表示日,需要注意的是表示月的M一定要大写。

  • (c):设置日历选择的显示以Popup的方式,即下拉显示的方式。
  • (d):调用QObject类的installEventFilter()函数安装事件过滤器,使DateDelegate能捕获QDateTimeEdit对象的事件。
void DateDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
  QString dateStr=index.model()->data(index).toString(); // (e)
  QDate date=QDate::fromString(dateStr,Qt::ISODate); // (f)
  QDateTimeEdit *edit=static_cast<QDateTimeEdit*>(editor); // (g)
  edit->setDate(date); // 设置控件的显示数据
}

其中:

  • (e):获取指定index数据项的数据,调用QModellndex的model()可获得提供此index的Model对象,data()函数返回的是一个QVariant对象,把它转换成一个QString类型数据。
  • (f):通过QDate的fromString()函数把以QString类型表示的日期数据转换成QDate类型,Qt::ISODate表示QString类型的日期是以ISO格式保存的,这样最终转换获得的QDate数据也是ISO格式,使控件显示与表格显示保持一致。
  • (g):把参数中的editor转换成QDateTimeEdit对象,以获得编辑控件的对象指针。
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))); // (h)
}

其中:

  • (h):调用setData()把数据修改更新到Model中。

二、ComboDelegate 的实现

ComboDelegate的类声明与DateDelegate的类似,需要重定义的函数也一样,此处只列出了重定义的函数。

在createEditor()函数中创建一个QComboBox控件,并插入可显示的条目,并安装事件过滤器。

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

更新Delegate控件的数据显示:

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);
}

更新Model中的数据:

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);
}

三、SpinDelegate的实现

与ComboDelegate的实现类似,此处不再赞述,仅给出代码函数。

QWidget* SpinDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
  QSpinBox *editor=new QSpinBox(parent);
  editor->setRange(1000,10000);
  editor->setSingleStep(500);
  editor->installEventFilter(const_cast<SpinDelegate*>(this));
  return editor;
}
void SpinDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
  int val=index.model()->data(index).toInt();
  QSpinBox *box=static_cast<QSpinBox*>(editor);
  box->setValue(val);
}
void SpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
  QSpinBox *box=static_cast<QSpinBox*>(editor);
  QString str=QString::number(box->value());
  model->setData(index,str);
}
void SpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
  editor->setGeometry(option.rect);
}

四、Delegate的应用

在Model/View结构的显示中应用准备好的Delegate:

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  QStandardItemModel model(4,4); //新建一个QStandardltemModel对象
  QTableView tableView;
  tableView.setModel(&model); // 用QTableView以表格的方式进行显示
  DateDelegate dateDelegate;
  ComboDelegate comboDelegate;
  SpinDelegate spinDelegate; // (a)
  tableView.setItemDelegateForColumn(1,&dateDelegate);
  tableView.setItemDelegateForColumn(2,&comboDelegate);
  tableView.setItemDelegateForColumn(3,&spinDelegate); // (a)
  model.setHeaderData(0,Qt::Horizontal,"姓名");
  model.setHeaderData(1,Qt::Horizontal,"生日");
  model.setHeaderData(2,Qt::Horizontal,"工作");
  model.setHeaderData(3,Qt::Horizontal,"收入"); // 对表格的表头显示进行设置
  QFile file("./data.tab"); // (b)
  if(file.open(QFile::ReadOnly | QFile::Text))
  {
    QTextStream stream(&file);
    QString line;
    model.removeRows(0,model.rowCount());
    int row=0;
    do{
      line=stream.readLine();
      if(!line.isEmpty()){
        model.insertRow(row,QModelIndex());
        QStringList pieces=line.split(",",QString::SkipEmptyParts);
        model.setData(model.index(row,0),pieces.value(0));
        model.setData(model.index(row,1),pieces.value(1));
        model.setData(model.index(row,2),pieces.value(2));
        model.setData(model.index(row,3),pieces.value(3)); // (c)
        row++;
      }
    }while(!line.isEmpty());
    file.close();
  }
  tableView.setWindowTitle("Delegate");
  tableView.show(); // 显示
  return a.exec();
}

其中:

  • (a):分别新建3个Delegate,并调用View的setItemDelegateForColumn()函数为指定的列应用指定的Delegate。此处对第1列应用DateDelegate,第2列应用ComboDelegate,第3列应用SpinDelegate。
  • (b):data.tab为事前准备好的文本数据文件,放置在项目目录下,内容如下:
Tom,1977-01-05,工人,1500
Jack,1978-12-23,医生,3000
Alice,1980-04-06,军人,2500
John,1983-09-25,律师,5000
  • (c):从文件中读取数据作为数据源,并把文件中的数据按数据表项的方式进行管理。

——————————————————

对于本文实例完整代码有需要的朋友,可关注并在评论区留言!

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表