在《C++ Gui Programming with Qt4》中第4章,SpreadSheet例子中,Cell继承自QTableWidgetItem类,SpreadSheet继承自QTableWidget类,在SpreadSheet中通过调用setItemPrototype方法设置SpreadSheet的项类--Cell,保证在用户点击时,自动生成Cell实例(instance)来保存用户输入的数据。
SpreadSheet::SpreadSheet(QWidget *parent) : QTableWidget(parent), pActionActive(new QAction(this)), mIsSaved(false), mAutoRecalculated(false) { setActionActive(); //设置Cell类为SpreadSheet的项类. setItemPrototype(new Cell()); connect(this, static_cast<void (SpreadSheet::*)(QTableWidgetItem*)>(&SpreadSheet::itemChanged), this, static_cast<void (SpreadSheet::*)()>(&SpreadSheet::somethingChanged)); clear(); }
当用户在生成的类excel表格中点击项,则会自动生成Cell实例,保存用户的输入内容。
但是在第十章的CoordinateSettor例子中,在根据系统录入的10组坐标中,则是在后台直接创建item实例,填入在表格中的位置,然后再将坐标信息填写到item中,
将item实例填到表格中。
void TestTableWidget::addRow(){ //pTableWidget为QTableWidget实例。 int row(pTableWidget->rowCount()); pTableWidget->insertRow(row); QTableWidgetItem* item0(new QTableWidgetItem()); item0->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft); pTableWidget->setItem(row, 0, item0); QTableWidgetItem* item1(new QTableWidgetItem()); item1->setTextAlignment(Qt::AlignBaseline | Qt::AlignRight); pTableWidget->setItem(row, 1, item1); pTableWidget->setCurrentCell(row, 0); }
如果想向SpreadSheet那样自动生成item项,则必须调用其setItemPrototype方法。
TestTableWidget::TestTableWidget(const QList<QPointF>* coord, QWidget *parent) : QWidget(parent), pTableWidget(new QTableWidget(0, 2, this)) { pCoordinates = coord; QStringList strList; strList.append(tr("X")); strList.append(tr("Y")); pTableWidget->setHorizontalHeaderLabels(strList); pTableWidget->setItemPrototype(new QTableWidgetItem()); for (int row(0); row != pCoordinates->count(); ++row) { QPointF point = pCoordinates->at(row); addRow(); pTableWidget->item(row, 0)->setText(QString::number(point.x())); pTableWidget->item(row, 1)->setText(QString::number(point.y())); } QVBoxLayout* vBoxLayout(new QVBoxLayout(this)); vBoxLayout->addWidget(pTableWidget); setLayout(vBoxLayout); }
发现执行到
pTableWidget->item(row, 0)->setText(QString::number(point.x()));
就会报告异常,怀疑setItemPrototype方法中只是制定当用户点击项时,系统自动创建项,而程序要往表格中填写内容时,必须创建项实例并添加到表格中。 后查看QTableWidget的api,setItemPrototype方法中要求实现QTableWidgetItem的derived class。感觉不能直接调用QTableWidgetItem的实例,故在此处创建class ItemClone,并实现clone方法。
QTableWidgetItem* ItemClone::clone() const{ return new ItemClone(); }
然后将ItemClone 放到setItemPrototype方法中。这时候再运行程序就一切正常了。当表格中没有创建项实例时,用户手动点击表格,自动就会有项实例生成,保存信息。
以下是具体实现code
main
#include <QtWidgets> #include "coordinatesetter.h" #include "testtablewidget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QList<QPointF> coordinates; coordinates << QPointF(0.0, 0.9) << QPointF(0.2, 11.0) << QPointF(0.4, 15.4) << QPointF(0.6, 12.9) << QPointF(0.8, 8.5) << QPointF(1.0, 7.1) << QPointF(1.2, 4.0) << QPointF(1.4, 13.6) << QPointF(1.6, 22.2) << QPointF(1.8, 22.2); //CoordinateSetter coordinateSetter(&coordinates); //coordinateSetter.show(); TestTableWidget coordinateSetter(&coordinates); coordinateSetter.show(); return app.exec(); }
显示表格的类:头文件
#ifndef TESTTABLEWIDGET_H#define TESTTABLEWIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE class QTableWidget; QT_END_NAMESPACE class TestTableWidget : public QWidget { Q_OBJECT public: explicit TestTableWidget(const QList<QPointF>* coord, QWidget *parent = 0); private: void addRow(); private: QTableWidget* pTableWidget; const QList<QPointF>* pCoordinates; }; #endif // TESTTABLEWIDGET_H
显示表格的类:实现文件
#include "testtablewidget.h" #include <QTableWidget> #include <QStringList> #include <QTableWidgetItem> #include <QVBoxLayout> #include "itemclone.h" TestTableWidget::TestTableWidget(const QList<QPointF>* coord, QWidget *parent) : QWidget(parent), pTableWidget(new QTableWidget(0, 2, this)) { pCoordinates = coord; QStringList strList; strList.append(tr("X")); strList.append(tr("Y")); pTableWidget->setHorizontalHeaderLabels(strList); pTableWidget->setItemPrototype(new ItemClone()); //set pTableWidget to be disabled for changing item. //pTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); for (int row(0); row != pCoordinates->count(); ++row) { QPointF point = pCoordinates->at(row); addRow(); //pTableWidget->item(row, 0)->setData(Qt::DisplayRole, QString::number(point.x())); pTableWidget->item(row, 0)->setText(QString::number(point.x())); pTableWidget->item(row, 1)->setText(QString::number(point.y())); } QVBoxLayout* vBoxLayout(new QVBoxLayout(this)); vBoxLayout->addWidget(pTableWidget); setLayout(vBoxLayout); } void TestTableWidget::addRow() { //pTableWidget为QTableWidget实例。 int row(pTableWidget->rowCount()); pTableWidget->insertRow(row); ItemClone* item0(new ItemClone()); item0->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft); pTableWidget->setItem(row, 0, item0); ItemClone* item1(new ItemClone()); item1->setTextAlignment(Qt::AlignBaseline | Qt::AlignRight); pTableWidget->setItem(row, 1, item1); pTableWidget->setCurrentCell(row, 0); }
QTableWidgetItem的derived类:头文件
#ifndef ITEMCLONE_H#define ITEMCLONE_H #include <QTableWidgetItem> class ItemClone : public QTableWidgetItem { public: ItemClone(); virtual QTableWidgetItem* clone() const; }; #endif // ITEMCLONE_H
QTableWidgetItem的derived类:实现文件
#include "itemclone.h" ItemClone::ItemClone() { } QTableWidgetItem* ItemClone::clone() const { return new ItemClone(); }
如coder要测试是否自动创建项实例,而不是程序写的
可以将addRow方法修改为:
void TestTableWidget::addRow() { //pTableWidget为QTableWidget实例。 int row(pTableWidget->rowCount()); pTableWidget->insertRow(row); }
这样只是对表格插入行,但是每行中的项实例没有创建,只有运行程序,用户在表格中点击输入时,才会生成项对象。