对于Qt 类前面已经介绍的很详细了,在本篇文章中就不多介绍了。那么本文讲述的内容是关于Subclassing QTableWidget中QTableWidget继承。QTableWidget是一个表示二维离散数组的表格。它在给定维度里显示当前用户滚动的单元格。当用户在一个空的单元格中输入一些文本时,QTableWidget自动创建一个QTableWidgetItem对象保存输入的文本。
现在我们来实现这个类,首先是头文件spreadsheet.h,首先前向声明两个类Cell和SpreadsheetCompare。
- #ifndef SPREADSHEET_H
- #define SPREADSHEET_H
- #include <QTableWidget>
- class Cell;
- class SpreadsheetCompare;
- class Spreadsheet : public QTableWidget{
- Q_OBJECTpublic:
- Spreadsheet(QWidget *parent = 0);
- bool autoRecalculate() const { return autoRecalc; }//内联函数
- QString currentLocation() const;
- QString currentFormula() const;
- QTableWidgetSelectionRange selectedRange() const;
- void clear();
- bool readFile(const QString &fileName);
- bool writeFile(const QString &fileName);
- void sort(const SpreadsheetCompare &compare);
- public slots:
- void cut();
- void copy();
- void paste();
- void del();
- void selectCurrentRow();
- void selectCurrentColumn();
- void recalculate();
- void setAutoRecalculate(bool recalc);
- void findNext(const QString &str, Qt::CaseSensitivity cs);
- void findPrevious(const QString &str, Qt::CaseSensitivity cs);signals:
- void modified();private slots:
- void somethingChanged();
- private:
- enum { MagicNumber = 0x7F51C883, RowCount = 999, ColumnCount = 26 };
- Cell *cell(int row, int column) const;
- QString text(int row, int column) const;
- QString formula(int row, int column) const;
- void setFormula(int row, int column, const QString &formula);
- bool autoRecalc;};class SpreadsheetCompare{public:
- bool operator()(const QStringList &row1,
- const QStringList &row2) const;
- enum { KeyCount = 3 };
- int keys[KeyCount];
- bool ascending[KeyCount];
- };
- #endif
文本,对齐等这个QTableWidget单元格的属性存储在QTableWidgetItem类里。QTableWidgetItem类不是一个控件类,而是一个单纯保存数据的类。
实现MainWindow类的时候我们用到了Spreadsheet的一些公有函数。如在MainWindow::newFile中调用clear()将表格置空。我们也用到了QTableWidget继承来的一些函数,如setCurrentCell()和setShowGrid()就多次调用过。
#p#
Spreadsheet提供了很多槽函数来相应Edit,Tools和Options等菜单的动作。信号modified()在表格发生变化时给出通知。私有槽函数somethingChanged()在Speadsheet类内部使用。
在类的私有部分,我们声明了三个常数,四个函数和一个变量。在头文件的最后定义了类SpreadsheetCompare
现在我们看一下源文件 spreadsheet.cpp:
- #include <QtGui>
- #include "cell.h"
- #include "spreadsheet.h"
- Spreadsheet::Spreadsheet(QWidget *parent)
- : QTableWidget(parent)
- {
- autoRecalc = true;
- setItemPrototype(new Cell);
- setSelectionMode(ContiguousSelection);
- connect(this, SIGNAL(itemChanged(QTableWidgetItem *)),
- this, SLOT(somethingChanged()));
- clear();
- }
- void Spreadsheet::clear()
- {
- setRowCount(0);
- setColumnCount(0);
- setRowCount(RowCount);
- setColumnCount(ColumnCount);
- for (int i = 0; i < ColumnCount; ++i) {
- QTableWidgetItem *item = new QTableWidgetItem;
- item->setText(QString(QChar('A' + i)));
- setHorizontalHeaderItem(i, item);
- }
- setCurrentCell(0, 0);
- }
- Cell *Spreadsheet::cell(int row, int column) const
- {
- return static_cast<Cell *>(item(row, column));
- }
- QString Spreadsheet::text(int row, int column) const
- {
- Cell *c = cell(row, column);
- if (c) {
- return c->text();
- } else {
- return "";
- }
- }
- QString Spreadsheet::formula(int row, int column) const
- {
- Cell *c = cell(row, column);
- if (c) {
- return c->formula();
- } else {
- return "";
- }
- }
- void Spreadsheet::setFormula(int row, int column,
- const QString &formula)
- {
- Cell *c = cell(row, column);
- if (!c) {
- c = new Cell;
- setItem(row, column, c);
- }
- c->setFormula(formula);
- }
- QString Spreadsheet::currentLocation() const
- {
- return QChar('A' + currentColumn())
- + QString::number(currentRow() + 1);
- }
- QString Spreadsheet::currentFormula() const
- {
- return formula(currentRow(), currentColumn());
- }
- void Spreadsheet::somethingChanged()
- {
- if (autoRecalc)
- recalculate();
- emit modified();
- }
通常,用户在一个空的单元格中输入文本时,QTableWidget将会自动创建 QTableWidgetItem对象来保存这些文本。然而在 spreadsheet程序中,我们通过创建Cell 代替QTableWidgetItem。在构造函数中,通过调用setItemProtoType()来实现。实际上是每次当需要创建一个新的项目时,QTableWidget 拷贝传递给setItemProtoType() 函数中的项目。
#p#
在构造函数中,我们设置选择方式QAbstractItemView::ContiguousSelection允许单一的矩形选择。连接表格控件的信号itemChanged()和私有的somethingChanged()槽函数,这样当用户编辑了一个单元格时,somethingChanged()能够被调用。最后,我们调用clear()清空表格,设置列标头。
在构造函数中调用 clear()用来初始化表格。在MainWindow::newFile() 中也调用了这个函数。本来可以使用函数QTableWidget::clear()清除所有项和选择,但这样不能改变当前大小的标题头。因此我们首先把表格重新定义为 0×0,这样全部清除了表格和标题头。然后把表格重新定义为ColumnCount×RowCount(26× 999),让水平标题头为QTableWidgetItem 类型,文本为"A"到"Z "。垂直标题栏会自动设置为1,2,到999。最后把光标移动到 A1。
QTableWidget由几个子控件组成。它在最上面有一个水平的QHeaderView,最左边有一个垂直的QHeaderView和两个QScrollBars。中间区域是一个特殊的viewport控件,这个控件可以显示网格。这些子控件可以通过QTableView和QAbstractScrollArea的函数进行操作。QAbstractScrollArea提供了一个可以滚动的viewport和两个滚动条。它的子类是 QScrollArea。
在 Items中保存数据:
在 Spreadsheet应用程序中,每一个非空的单元格都作为一个独立的 QTableWidgetItem对象被存放在内存中。这种在 Item中保存数据的方法被QListWidget 和QTreeWidget所采用,对应这两个控件的Item类分别为QListWidgetItem和QTreeWidgetItem。
Qt的Item类还可以作为数据存储器使用。比如,QTableWidgetItem也保存了一些属性如文本,字体,颜色,图标等,还有一个指向QTableWidget的指针。这个Item还可以保存QVariant类型的数据,包括注册的自定义类型。从这个类派生子类,我们还可以提供其他功能。
其他的工具是在它们的 item类中提供一个空指针来保存用户数据。在 Qt中更加好用的方法是使用setData() ,把QVariant类型的数据保存起来。如果需要一个空类型指针,也可以从item类派生,在派生类中添加一个空类型指针成员变量。
对于那些更为复杂的数据处理,如大量的数据,复杂的数据项,数据库数据和多种数据显示方式,Qt提供了一套model/view类将数据和显示分离出来,第十章介绍了这个特性。
私有函数 cell()返回指定的行数和列数的Cell对象。它和QTableWidget::item()是一样的,只是它返回的是Cell类型的指针,QTableWidget::item()返回的是QTableWidgetItem类型的指针。
私有函数 text()返回指定的单元格的文本。如果cell() 返回空指针,该单元格为空,则返回空字符。
函数 formula()返回的是单元格的公式。大多数情况下,单元格的公式和文本是一样的。例如,公式" hello"和字符"hello"是一样的,如果用户输入了"hello",网格的文本就显示为hello。但是下面会是例外:
1、如果公式是一个数字,那么单元格的文本也是数字。
2、如果公式是单引号开头,公式的其他部分就是文本。如公式'12345,等价于串就是"12345" 。
3、如果公式由等号"="开头,代表一个数学公式。如果A1为12, A2为6,那么公式"=A1+A2 "就是18。
把公式转换为值的任务是由类 Cell完成的。此时需要记住的是单元格中显示的文本是经过公式计算的结果,而不是公式本身。
私有函数 setFormula()用来给一个指定的单元格设置公式。如果该单元格有 Cell对象,那就使用这个对象。否则,我们创建一个新的 Cell对象,然后我们调用QTableWidget::setItem() 函数把它插入到表格中,最后调用单元格自己的setFormula()函数,在单元格上显示公式结果。我们不用删除Cell对象,在适当的时候,QTableWidget会自动删除这些对象。
函数 currentLocation()返回当前单元格的位置,字母显示的列和行号,被 MainWindow::updateStatusBar()调用在状态条上显示位置。
函数 currentFormula()返回当前单元格的公式。 MainWindow::updateStatusBar()调用了这个函数。
私有槽函数 somethingChanged()中,如果 auto-recalculate为真,那么重新计算整个表格。然后发送 modified()信号。
小结:想了解Qt更多的类,请到网上搜集就可以。关于Subclassing QTableWidget中从QTableWidget继承的内容介绍完了。希望本文对你有帮助!
【编辑推荐】