现在的位置: 首页 > 综合 > 正文

(转)4.2从QTableWidget继承(Subclassing QTableWidget)

2013年02月02日 ⁄ 综合 ⁄ 共 6193字 ⁄ 字号 评论关闭
类Spreadsheet从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_OBJECT
public:
    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
Figure 4.1. Inheritance trees for Spreadsheet and Cell
文本,对齐等这个QTableWidget单元格的属性存储在QTableWidgetItem类里。QTableWidgetItem类不是一个控件类,而是一个单纯保存数据的类。类Cell从QTableWidgetItem继承的,将在下一节介绍。
在第三章我们实现MainWindow类的时候我们用到了Spreadsheet的一些公有函数。如在MainWindow::newFile中调用clear()将表格置空。我们也用到了QTableWidget继承来的一些函数,如setCurrentCell()和setShowGrid()就多次调用过。
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(
00);
}
Cell 
*Spreadsheet::cell(int row, int column) const
{
    
return static_cast<Cell *>(item(row, column));
}
QString Spreadsheet::text(
int row, int column) const
{
    Cell 
*= cell(row, column);
    
if (c) {
        
return c->text();
    } 
else {
        
return "";
    }
}
QString Spreadsheet::formula(
int row, int column) const
{
    Cell 
*= cell(row, column);
    
if (c) {
        
return c->formula();
    } 
else {
        
return "";
    }
}
void Spreadsheet::setFormula(int row, int column,
                             
const QString &formula)
{
    Cell 
*= 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() 函数中的项目。
在构造函数中,我们设置选择方式QAbstractItemView::ContiguousSelection允许单一的矩形选择。连接表格控件的信号itemChanged()和私有的somethingChanged()槽函数,这样当用户编辑了一个单元格时,somethingChanged()能够被调用。最后,我们调用clear()清空表格,设置列标头。
在构造函数中调用 clear()用来初始化表格。在MainWindow::newFile() 中也调用了这个函数。本来可以使用函数QTableWidget::clear()清除所有项和选择,但这样不能改变当前大小的标题头。因此我们首先把表格重新定义为 0×0,这样全部清除了表格和标题头。然后把表格重新定义为ColumnCount×RowCount26× 999),让水平标题头为QTableWidgetItem 类型,文本为"A""Z "。垂直标题栏会自动设置为12,到999。最后把光标移动到 A1
QTableWidget由几个子控件组成。它在最上面有一个水平的QHeaderView,最左边有一个垂直的QHeaderView和两个QScrollBars。中间区域是一个特殊的viewport控件,这个控件可以显示网格。这些子控件可以通过QTableViewQAbstractScrollArea的函数进行操作。QAbstractScrollArea提供了一个可以滚动的viewport和两个滚动条。它的子类 QScrollArea会在第六章介绍到。
Figure 4.2. QTableWidget 's constituent widgets
************************************
Items中保存数据:
Spreadsheet应用程序中,每一个非空的单元格都作为一个独立的 QTableWidgetItem对象被存放在内存中。这种在 Item中保存数据的方法被QListWidget QTreeWidget所采用,对应这两个控件的Item类分别为QListWidgetItemQTreeWidgetItem
QtItem类还可以作为数据存储器使用。比如,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、如果公式由等号"="开头,代表一个数学公式。如果A112 A26,那么公式"=A1+A2 "就是18
把公式转换为值的任务是由类 Cell完成的。此时需要记住的是单元格中显示的文本是经过公式计算的结果,而不是公式本身。
私有函数 setFormula()用来给一个指定的单元格设置公式。如果该单元格有 Cell对象,那就使用这个对象。否则,我们创建一个新的 Cell对象,然后我们调用QTableWidget::setItem() 函数把它插入到表格中,最后调用单元格自己的setFormula()函数,在单元格上显示公式结果。我们不用删除Cell对象,在适当的时候,QTableWidget会自动删除这些对象。
函数 currentLocation()返回当前单元格的位置,字母显示的列和行号,被 MainWindow::updateStatusBar()调用在状态条上显示位置。
函数 currentFormula()返回当前单元格的公式。 MainWindow::updateStatusBar()调用了这个函数。
私有槽函数 somethingChanged()中,如果 auto-recalculate为真,那么重新计算整个表格。然后发送 modified()信号。

抱歉!评论已关闭.