01 void MainWindow::openRecentFile()
02 {
03 if (okToContinue()) {
04 QAction *action = qobject_cast<QAction *>(sender());
05 if (action)
06 loadFile(action->data(). toString());
07 }
08 }
При выборе пользователем какого-нибудь недавно используемого файла вызывается слот openRecentFile(). Функция okToContinue() используется в том случае, когда имеются несохраненные изменения, и если пользователь не отменил сохранение изменений, мы определяем, какой конкретный пункт меню вызвал слот, используя функцию QObject::sender().
Функция qobject_cast<T>() выполняет динамическое приведение типов на основе метаинформации, сгенерированной moc компилятором метаобъектов Qt. Она возвращает указатель на запрошенный подкласс QObject или 0, если нельзя объект привести к данному типу. В отличие от функции dynamic_cast<T>() стандартного С++, функция Qt qobject_cast<T>() работает правильно за пределами динамической библиотеки. В нашем примере мы используем qobject_cast<T>() для приведения указателя QObject в указатель QAction. Если приведение удачно (а оно должно быть удачным), мы вызываем функцию loadFile(), задавая полное имя файла, которое мы извлекаем из элемента данных пункта меню.
Поскольку мы знаем, что слот вызывался объектом QAction, в данном случае программа все же правильно сработала бы при использовании функции static_cast<T>() или при традиционном приведении Стипов. (См. раздел «Преобразование типов» в , где дается обзор различных методов приведения типов в С++.)
Применение диалоговых окон
Рис. 3.12. Диалоговое окно Find приложения Электронная таблица.
Мы начнем с диалогового окна Find. Поскольку мы хотим, чтобы пользователь имел возможность свободно переключаться с главного окна приложения Электронная таблица на диалоговое окно Find и обратно, это диалоговое окно должно быть немодальным. Немодальным называется окно, которое может работать независимо от других окон приложения.
При создании немодальных диалоговых окон они обычно имеют свои сигналы, соединенные со слотами, которые реагируют на действия пользователя:
01 void MainWindow::find()
02 {
03 if (!findDialog) {
04 findDialog = new FindDialog(this);
05 connect(findDialog,
с помощью функции QString::mid() (которая возвращает подстроку с первой позиции до конца этой строки), преобразуем ее в целое число типа int при помощи функции QString::toInt() и вычитаем единицу. Для получения номера столбца мы вычитаем числовой код буквы «А» из числового кода первой буквы строки, преобразованной в прописную. Мы знаем, что строка будет иметь правильный формат, потому что осуществляемый нами контроль диалога с помощью QRegExpValidator делает кнопку OK активной только в том случае, если за буквой располагается не более трех цифр.
Функция goToCell() отличается от приводимого до сих пор программного кода тем, что она создает виджет (GoToCellDialog) в виде переменной стека. Мы столь же легко могли бы воспользоваться операторами new и delete, что увеличило бы программный код только на одну строку:
01 void MainWindow::goToCell()
02 {
03 GoToCellDialog *dialog = new GoToCellDialog(this);
04 if (dialog->exec()) {
05 QString str = dialog->lineEdit->text().toUpper();
06 spreadsheet->setCurrentCell(str.mid(1).toInt() - 1,
07 str[0].unicode() - 'A');
08 }
09 delete dialog;
10 }
Создание модальных диалоговых окон (и контекстных меню при переопределении QWidget::contextMenuEvent() ) является обычной практикой программирования, поскольку такое окно (или меню) будет не нужно после его использования, и оно будет автоматически уничтожено при выходе из области видимости.
Теперь мы перейдем к созданию диалогового окна Sort. Это диалоговое окно является модальным и позволяет пользователю упорядочить текущую выбранную область, задавая в качестве ключей сортировки определенные столбцы. На рис. 3.14 показан пример сортировки, когда в качестве главного ключа сортировки используется столбец В, а в качестве вторичного ключа сортировки используется столбец А (в обоих случаях сортировка выполняется по возрастанию значений).
Рис. 3.14. Сортировка выделенной области электронной таблицы.
01 void MainWindow::sort()
02 {
03 SortDialog dialog(this);
04 QTableWidgetSelectionRange range = spreadsheet->selectedRange();
05 dialog.setColumnRange('A' + range.leftColumn(),
06 'А' + range.rightColumn());
07 if (dialog.exec()) {
08 SpreadsheetCompare compare;
09 compare.keys[0] =
10 dialog.primaryColumnCombo->currentIndex();
11 compare.keys[1] =
12 dialog.secondaryColumnCombo->currentIndex() - 1;
13 compare.keys[2] =
14 dialog.tertiaryColumnCombo->currentIndex() - 1;
15 compare.ascending[0] =
16 (dialog.primaryOrderCombo->currentIndex() == 0);
17 compare.ascending[1] =
18 (dialog.secondaryOrderCombo->currentIndex() == 0);
19 compare.ascending[2] =
20 (dialog.tertiaryOrderCombo->currentIndex() == 0);
21 spreadsheet->sort(compaге);
22 }
23 }
Порядок действий при программировании функции sort() аналогичен порядку действий, применяемому при программировании функции goToCell();