07 selectColumn(currentColumn());
08 }
Функции selectCurrentRow() и selectCurrentColumn() соответствуют пунктам меню Edit | Select | Row и Edit | Select | Column (Правка | Выделить | Строка и Правка | Выделить | Столбец). Здесь используется реализация функций selectRow() и selectColumn() класса QTableWidget. Нам не требуется реализовывать функциональность пункта меню Edit | Select | All (Правка | Выделить | Все), поскольку она обеспечивается в QTableWidget унаследованной функцией QAbstractItemView::selectAll().
01 void Spreadsheet::findNext(const QString &str, Qt::CaseSensitivity cs)
02 {
03 int row = currentRow();
04 int column = currentColumn() + 1;
05 while (row < RowCount) {
06 while (column < ColumnCount) {
07 if (text(row, column).contains(str, cs)) {
08 clearSelection();
09 setCurrentCell(row, column);
10 activateWindow();
11 return;
12 }
13 ++column;
14 }
15 column = 0;
16 ++row;
17 }
18 QApplication::beep();
19 }
Слот findNext() в цикле просматривает ячейки, начиная с ячейки, расположенной правее курсора, и двигается вправо до достижения последнего столбца; затем процесс идет с первого столбца строки, расположенной ниже, и так продолжается, пока не будет найден требуемый текст или пока не будет достигнута самая последняя ячейка. Например, если текущей является ячейка C24, поиск будет продолжаться по ячейкам D24, E24, … Z24, затем no A25, B25, C25, … Z25 и так далее, пока не будет достигнута ячейка Z999. Если соответствующее значение найдено, мы сбрасываем текущее выделение и перемещаем курсор на ячейку, в которой оно находится, и делаем активным окно, содержащее эту электронную таблицу Spreadsheet. При неудачном завершении поиска мы заставляем приложение выдать соответствующий звуковой сигнал.
01 void Spreadsheet::findPrevious(const QString &str, Qt::CaseSensitivity cs)
02 {
03 int row = currentRow();
04 int column = currentColumn() - 1;
05 while (row>= 0) {
06 while (column >= 0) {
07 if (text(row, column).contains(str, cs)) {
08 clearSelection();
09 setCurrentCell(row, column);
10 activateWindow();
11 return;
12 }
13 --column;
14 }
15 column = ColumnCount - 1;
16 --row;
17 }
18 QApplication::beep();
19 }
Слот findPrevious() похож на findNext(), но здесь цикл выполняется в обратном направлении и заканчивается в ячейке A1.
Реализация других меню
Теперь мы реализуем слоты для пунктов меню Tools и Options.
Рис. 4.7. Меню Tools и Options приложения Электронная таблица.
01 void Spreadsheet::recalculate()
02 {
03 for (int row = 0; row < RowCount; ++row) {
04 for (int column = 0; column < ColumnCount; ++column) {
05 if (cell(row, column))
06 cell(row, column)->setDirty();
07 }
08 }
09 viewport()->update();
10 }
Слот recalculate() соответствует пункту меню Tools | Recalculate (Инструменты | Пересчитать). Он также вызывается в Spreadsheet автоматически по мере необходимости.
Мы выполняем цикл по всем ячейкам и вызываем функцию setDirty(), которая помечает каждую из них для перерасчета значения. В следующий раз, когда QTableWidget для получения отображаемого в электронной таблице значения вызовет text() для некоторой ячейки Cell, значение этой ячейки будет пересчитано.
Затем мы вызываем для области отображения функцию update() для перерисовки всей электронной таблицы. При этом используемый в QTableWidget программный код по перерисовке вызывает функцию text() для каждой видимой ячейки для получения отображаемого значения. Поскольку функция setDirty() вызывалась нами для каждой ячейки, в вызовах text() будет использовано новое рассчитанное значение. В этом случае может потребоваться расчет невидимых ячеек, который будет проводиться до тех пор, пока не будут рассчитаны все ячейки, влияющие на правильное отображение текста в перерассчитанной области отображения. Этот расчет выполняется в классе Cell.
01 void Spreadsheet::setAutoRecalculate(bool recalc)
02 {
03 autoRecalc = recalc;
04 if (autoRecalc)