關于Subclassing QTableWidget中QTableWidget繼承
對于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繼承的內容介紹完了。希望本文對你有幫助!
【編輯推薦】