05 recalculate;
06 }
Слот setAutoRecalculate соответствует пункту меню Options | Auto—Recalculate. Если эта опция включена, мы сразу же пересчитаем всю электронную таблицу и будем уверены, что она показывает обновленные значения; впоследствии функция recalculate будет автоматически вызываться из somethingChanged.
Нам не нужно реализовывать специальную функцию для пункта меню Options | Show Grid, поскольку в QTableWidget уже содержится слот setShowGrid, который наследуется от базового класса QTableView. Остается только реализовать функцию Spreadsheet::sort, которая вызывается из MainWindow::sort:
01 void Spreadsheet::sort(const SpreadsheetCompare &compare)
02 {
03 QList rows;
04 QTableWidgetSelectionRange range = selectedRange;
05 int i;
06 for (i = 0; i < range.rowCount; ++i) {
07 QStringList row;
08 for (int j = 0; j < range.columnCount; ++j)
09 row.append(formula(range.topRow + i,
10 range.leftColumn + j));
11 rows.append(row);
12 }
13 qStableSort(rows.begin, rows.end, compare);
14 for (i = 0; i < range.rowCount; ++i) {
15 for (int j = 0; j < range.columnCount; ++j)
16 setFormula(range.topRow + i, range.leftColumn + j, rows[i][j]);
17 }
18 clearSelection;
19 somethingChanged;
20 }
Сортировка работает на текущей выделенной области и переупорядочивает строки в соответствии со значениями ключей порядка сортировки, хранящимися в объекте compare. Мы представляем каждую строку данных в QStringList, а выделенную область храним в виде списка строк. Мы используем алгоритм Qt qStableSort и для простоты сортируем по выражениям формул, а не по их значениям. Стандартные алгоритмы и структуры данных Qt рассматривается в главе 11 («Классы—контейнеры»).
Рис. 4.8. Хранение выделенной области в виде списка строк.
В качестве аргументов функции qStableSort используются итератор начала, итератор конца и функция сравнения. Функция сравнения имеет два аргумента (оба имеют тип QStringLists), и она возвращает true, когда первый аргумент «больше, чем» второй аргумент, и false в противном случае. Передаваемый как функция сравнения объект compare фактически не является функцией, но он может использоваться и в таком качестве, в чем мы вскоре сможем убедиться.
Рис. 4.9. Помещение данных в таблицу после сортировки.
После выполнения функции qStableSort мы помещаем данные обратно в таблицу, сбрасываем выделение области и вызываем функцию somethingChanged. Класс SpreadsheetCompare в spreadsheet.h определен следующим образом:
01 class SpreadsheetCompare
02 {
03 public:
04 bool operator(const QStringList &row1,
05 const QStringList &row2) const;
06 enum { KeyCount = 3 };
07 int keys[KeyCount];
08 bool ascending[KeyCount];
09 };
Класс SpreadsheetCompare является специальным классом, реализующим оператор . Это позволяет нам применять этот класс в качестве функции. Такие классы называются объектами функций или функторами (functors).
Для лучшего понимания работы функторов мы сначала разберем простой пример:
01 class Square
02 {
03 public:
04 int operator(int x) const { return x * x; }
05 }
Класс Square содержит одну функцию operator(int), которая возвращает квадрат переданного ей значения параметра. Обозначая функцию в виде operator(int), а не в виде, например, compute(int), мы получаем возможность применения объекта типа Square как функции:
Square square;
int у = square(5);