Давайте начнем с реализации виджета и сначала приведем заголовочный файл:
01 #ifndef SPREADSHEET_H
02 #define SPREADSHEET_H
03 #include <QTableWidget>
04 class Cell;
05 class SpreadsheetCompare;
Заголовочный файл начинается с предварительных объявлений классов Cell и SpreadsheetCompare.
Рис. 4.1. Деревья наследования для классов Spreadsheet и Cell.
Такие атрибуты ячейки QTableWidget, как ее текст и выравнивание, хранятся в QTableWidgetltem. В отличие от QTableWidget, класс QTableWidgetltem не является виджетом; это обычный класс данных. Класс Cell наследует QTableWidgetltem, и мы рассмотрим этот класс в последнем разделе данной главы, где представим его реализацию.
06 class Spreadsheet : public QTableWidget
07 {
08 Q_OBJECT
09 public:
10 Spreadsheet(QWidget *parent = 0);
11 bool autoRecalculate() const { return autoRecalc; }
12 QString currentLocation() const;
13 QString currentFormula() const;
14 QTableWidgetSelectionRange selectedRange() const;
15 void clear();
16 bool readFile(const QString &fileName);
17 bool writeFile(const QString &fileName);
18 void sort(const SpreadsheetCompare &compare);
Функция autoRecalculate() реализуется как встроенная (inline), поскольку она лишь показывает, задействован или нет режим автоматического перерасчета.
В мы опирались на использование некоторых открытых функций класса электронной таблицы Spreadsheet при реализации MainWindow Например, из MainWindow::newFile() мы вызывали функцию clear() для очистки электронной таблицы. Кроме того, мы вызывали некоторые функции, унаследованные от QTableWidget, а именно setCurrentCell() и setShowGrid().
19 public slots:
20 void cut();
21 void copy();
22 void paste();
23 void del();
24 void selectCurrentRow();
25 void selectCurrentColumn();
26 void recalculate();
27 void setAutoRecalculate(bool recalc);
28 void findNext(const QString &str, Qt::CaseSensitivity cs);
29 void findPrevious(const QString &str, Qt::CaseSensitivity cs);
30 signals:
31 void modified();
Класс Spreadsheet содержит много слотов, которые реализуют действия пунктов меню Edit, Tools и Options, и он содержит один сигал modified() для уведомления о возникновении любого изменения.
32 private slots:
33 void somethingChanged();
Мы определяем один закрытый слот, который используется внутри класса Spreadsheet.
34 private:
35 enum { MagicNumber = 0x7F51C883, RowCount = 999, ColumnCount = 26 };
36 Cell *cell(int row, int column) const;
37 QString text(int row, int column) const;
38 QString formula(int row, int column) const;
39 void setFormula(int row, int column, const QString &formula);
40 bool autoRecalc;
41 };
В закрытой секции этого класса мы объявляем три константы, четыре функции и одну переменную.
42 class SpreadsheetCompare
43 {
44 public:
45 bool operator()(const QStringList &row1, const QStringList &row2) const;
46 enum { KeyCount = 3 };
47 int keys[KeyCount];
48 bool ascending[KeyCount];
49 };
50 #endif
Заголовочный файл заканчивается определением класса SpreadsheetCompare. Мы объясним назначение этого класса при рассмотрении функции Spreadsheet::sort().
Теперь мы рассмотрим реализацию:
01 #include <QtGui>
02 #include "cell.h"
03 #include "spreadsheet.h"
04 Spreadsheet::Spreadsheet(QWidget *parent)
05 : QTableWidget(parent)
06 {
07 autoRecalc = true;
08 setItemPrototype(new Cell);
09 setSelectionMode(ContiguousSelection);
пользовательских данных. В Qt используется более естественный подход с применением setData() для типа QVariant, однако если требуется иметь указатель void, это можно сделать просто путем создания подкласса для класса элемента, который будет содержать переменнуюуказатель на член типа void.
Для данных, к которым предъявляются повышенные требования, например для больших наборов данных, для сложных элементов данных, для интеграции баз данных и для множественных представлений данных, Qt предоставляет набор классов «модель/представление», в которых данные отделены от их визуального представления. Эти классы рассматриваются в .
01 Cell *Spreadsheet::cell(int row, int column) const
02 {
03 return static_cast<Cell *>(item(row, column));
04 }
Закрытая функция cell() возвращает для заданной строки и столбца объект Cell. Она работает почти так же, как QTableWidget::item(), но возвращает указатель на Cell, а не указатель на QTableWidgetltem.
01 QString Spreadsheet::text(int row, int column) const
02 {
03 Cell *c = cell(row, column);
04 if (с) {
05 return c->text();
06 } else {
07 return "";
08 }
09 }
Закрытая функция text() возвращает формулу заданной ячейки. Если cell() возвращает нулевой указатель, то это означает, что ячейка пустая, и поэтому мы возвращаем пустую строку.
01 QString Spreadsheet::formula(int row, int column) const
02 {
03 Cell *c = cell(row, column);
04 if (с) {
05 return c->formula();
06 } else {
07 return "";
08 }
09 }
Функция formula() возвращает формулу ячейки. Во многих случаях формула и текст совпадают; например формула «Hello» соответствует строке «Hello», поэтому при вводе пользователем в ячейку строки «Hello» и нажатии клавиши Enter в ячейке отобразится текст «Hello». Но имеется несколько исключений: