Когда QStatusBar располагает виджеты индикаторов, он постарается обеспечить «идеальный» размер виджетов, заданный функцией QWidget::sizeHint(), и затем растянет виджеты, которые допускают растяжение, заполняя дополнительное пространство. Идеальный размер виджета зависит от его содержания и будет сам изменяться по мере изменения содержания. Чтобы предотвратить постоянное изменение размера индикатора ячейки, мы устанавливаем его минимальный размер на значение, достаточное для размещения в нем самого большого возможного текстового значения («W999»), и добавляем еще немного пространства. Мы также устанавливаем его параметр выравнивания на значение AlignHCenter для выравнивания по центру текста в области индикатора.
Перед завершением функции мы соединяем два сигнала Spreadsheet с двумя слотами главного окна MainWindow: updateStatusBar() и spreadsheetModified().
01 void MainWindow::updateStatusBar()
02 {
03 locationLabel->setText(spreadsheet->currentLocation());
04 formulaLabel->setText(spreadsheet->currentFormula());
05 }
Слот updateStatusBar() обновляет индикаторы расположения ячейки и формулы ячейки. Он вызывается при любом перемещении пользователем курсора ячейки на новую ячейку. В конце функции createStatusBar() этот слот используется как обычная функция для инициализации индикаторов. Это необходимо, поскольку Spreadsheet при запуске не генерирует сигнал currentCellChanged().
06 void MainWindow::spreadsheetModified()
07 {
08 setWindowModified(true);
09 updateStatusBar();
10 }
Слот spreadsheetModified()
обновляет все три индикатора для отражения ими текущего состояния приложения и устанавливает переменную modified на значение true. (Мы использовали переменную modified при реализации меню File для контроля несохраненных изменений.) Слот spreadsheetModified() устанавливает свойство windowModified в значение true, обновляя строку заголовка. Эта функция обновляет также индикаторы расположения и формулы ячейки, чтобы они отражали текущее состояние.
Реализация меню File
01 void MainWindow::newFile()
02 {
03 if (okToContinue ())
04 {
05 spreadsheet->clear();
06 setCurrentFile("");
07 }
08 }
Слот newFile() вызывается при выборе пользователем пункта меню File | New или при нажатии кнопки New на панели инструментов. Закрытая функция okToContinue() задает пользователю вопрос относительно необходимости сохранения изменений («Do you want to save your changes?» Сохранить изменения?), если изменения до этого не были сохранены. Она возвращает значение true, если пользователь отвечает Yes или No (сохраняя документ при ответе Yes), и она возвращает значение false, если пользователь отвечает Cancel. Функция Spreadsheet::clear() очищает все ячейки и формулы электронной таблицы. Закрытая функция setCurrentFile() кроме установки закрытой переменной curFile и обновления списка недавно используемых файлов изменяет заголовок окна, отражая тот факт, что редактируемый документ не имеет заголовка.
01 bool MainWindow::okToContinue()
02 {
03 if (isWindowModified()) {
04 int r = QMessageBox::warning(this,
05 tr("Spreadsheet"), tr("The document has been modified.\n"
06 "Do you want to save your changes?"),
07 QMessageBox::Yes | QMessageBox::Default,
08 QMessageBox::No,
09 QMessageBox::Cancel | QMessageBox::Escape);
10 if (r == QMessageBox::Yes) {
11 return save();
12 } else if (r == QMessageBox::Cancel) {
13 return false;
14 }
15 }
16 return true;
17 }
B okToContinue() мы проверяем свойство windowModified. Если оно имеет значение true, мы выводим на экран сообщение, показанное на рис. 3.9. Окно сообщения содержит кнопки Yes, No и Cancel. Модификатор QMessageBox::Default делает Yes кнопкой, которая выбирается по умолчанию. Модификатор QMessageBox::Escape задает клавишу Esc в качестве синонима кнопки Cancel.
Рис. 3.9. «Сохранить изменения?»
Вызов функции warning() на первый взгляд может показаться слишком сложным, но он имеет очень простой формат:
QMessageBox::warning(родительский объект, заголовок, сообщение, кнопка0, кнопка1, );
QMessageBox содержит функции information(), question() и critical(), каждая из которых имеет собственную пиктограмму.
Рис. 3.10. Пиктограммы окна сообщения.
01 void MainWindow::open()
02 {
03 if (okToContinue()) {
04 QString fileName = QFileDialog::getOpenFileName(".", fileFilters, this);
05 if (!fileName.isEmpty())
06 loadFile(fileName);
07 }
08 }
Слот open() соответствует пункту меню File | Open. Как и слот newFile(), он сначала вызывает okToContinue() для обработки несохраненных изменений. Затем он вызывает удобную статическую функцию QFileDialog::getOpenFileName() для получения от пользователя нового имени файла. Эта функция выводит на экран диалоговое окно для выбора пользователем файла и возвращает имя файла или пустую строку при нажатии пользователем клавиши Cancel.
В первом аргументе функции QFileDialog::getOpenFileName() задается родительский виджет. Взаимодействие родительских и дочерних объектов для диалоговых окон и для других виджетов будет различно. Диалоговое окно всегда является самостоятельным окном, однако если у него имеется родитель, то оно размещается