4-2 从QTableWidget继承(Subclassing QTableWidget)

 
4-2 从QTableWidget继承(Subclassing QTableWidget)
类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(
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 
* =  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 × RowCount 26 × 999 ),让水平标题头为 QTableWidgetItem 类型,文本为 " A " " Z " 。垂直标题栏会自动设置为 1 2 ,到 999 。最后把光标移动到 A1
QTableWidget 由几个子控件组成。它在最上面有一个水平的 QHeaderView ,最左边有一个垂直的 QHeaderView 和两个 QScrollBars 。中间区域是一个特殊的 viewport 控件,这个控件可以显示网格。这些组成控件可以通过 QTableView QAbstractScrollArea 的函数进行操作。 QAbstractScrollArea 提供了一个可以滚动的 viewport 和两个滚动条。它的子类 QScrollArea 会在第六章介绍到。
Figure 4.2. QTableWidget 's constituent widgets
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 对象。最后我们调用 Cell 自己的 setFormula() 函数,在网格上显示公式结果。我们不用删除 Cell 对象,在适当的时候, QTableWidget 会自动删除这些对象。
函数 currentLocation() 返回当前网格的位置,字母显示的列和行号。在 MainWindow::updateStatusBar() 调用在状态条上显示位置。
函数 currentFormula() 返回当前网格的公式。 MainWindow::updateStatusBar() 调用了这个函数。
私有槽函数 somethingChanged() 中,如果 auto-recalculate 为真,那么重新计算整个表格。然后发送 modified() 信号。
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值