关于QTableWidgetItem::setItemPrototype的理解

在《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(thisstatic_cast<void (SpreadSheet::*)(QTableWidgetItem*)>(&SpreadSheet::itemChanged),
            thisstatic_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* coord,                                 QWidget *parent) :
    QWidget(parent),
    pTableWidget(new QTableWidget(02, 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(row0)->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 
#include "coordinatesetter.h"
#include "testtablewidget.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QList coordinates;
    coordinates << QPointF(0.00.9)
                << QPointF(0.211.0)
                << QPointF(0.415.4)
                << QPointF(0.612.9)
                << QPointF(0.88.5)
                << QPointF(1.07.1)
                << QPointF(1.24.0)
                << QPointF(1.413.6)
                << QPointF(1.622.2)
                << QPointF(1.822.2);
    //CoordinateSetter coordinateSetter(&coordinates);
    //coordinateSetter.show();
    TestTableWidget coordinateSetter(&coordinates);
    coordinateSetter.show();

    return app.exec();
}

显示表格的类:头文件

#ifndef TESTTABLEWIDGET_H#define TESTTABLEWIDGET_H

#include 

QT_BEGIN_NAMESPACE
class QTableWidget;
QT_END_NAMESPACE

class TestTableWidget : public QWidget
{
    Q_OBJECT
public:
    explicit TestTableWidget(const QList* coord, QWidget *parent = 0);

private:
    void addRow();

private:
    QTableWidget* pTableWidget;
    const QList* pCoordinates;
};

#endif // TESTTABLEWIDGET_H

显示表格的类:实现文件

#include "testtablewidget.h"
#include 
#include 
#include 
#include 

#include "itemclone.h"

TestTableWidget::TestTableWidget(const QList* coord,
                                 QWidget *parent) :
    QWidget(parent),
    pTableWidget(new QTableWidget(02, 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 

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

这样只是对表格插入行,但是每行中的项实例没有创建,只有运行程序,用户在表格中点击输入时,才会生成项对象。

你可能感兴趣的:(Qt)