QT 4: программирование GUI на С++
Шрифт:
Порядок действий при программировании функции sort аналогичен порядку действий, применяемому при программировании функции goToCell;
• мы создаем диалоговое окно в стеке и инициализируем его;
• мы вызываем диалоговое окно при помощи функции exec;
• если пользователь нажимает кнопку OK, мы используем введенные пользователем в диалоговом окне значения соответствующим образом.
Вызов setColumnRange
В объекте compare хранятся первичный, вторичный и третичный ключи, а также порядок сортировки по ним. (Определение класса SpreadsheetCompare мы рассмотрим в следующей главе.) Этот объект используется функцией Spreadsheet::sort для сортировки строк. В массиве keys содержатся номера столбцов ключей. Например, если выбрана область с C2 по E5, то столбец С будет иметь индекс 0. В массиве ascending в переменных типа bool хранятся значения направления сортировки для каждого ключа. Функция QComboBox::currentIndex возвращает индекс текущего элемента (начиная с 0). Для вторичного и третичного ключей мы вычитаем единицу из текущего элемента, чтобы учесть значения «None» (отсутствует).
Функция sort сделает свою работу, но она не совсем надежна. Она предполагает определенный способ реализации диалогового окна, а именно использование выпадающих списков и элементов со значением «None». Это означает, что при изменении дизайна диалогового окна Sort нам, возможно, потребуется изменить также программный код. Такой подход можно использовать для диалогового окна, применяемого только в одном месте; однако это может вызвать серьезные проблемы сопровождения, если это диалоговое окно станет использоваться в различных местах.
Более надежным будет такой подход, когда класс SortDialog делается более «разумным» и может создавать свой собственный объект SpreadsheetCompare, доступный вызывающему его компоненту. Это значительно упрощает функцию MainWindow::sort:
Такой подход приводит к созданию слабо связанных компонентов, и выбор его почти всегда будет правилен для диалоговых окон, которые вызываются из нескольких мест.
Более «радикальный» подход мог бы заключаться в передаче указателя на объект Spreadsheet при инициализации объекта SortDialog и разрешении диалоговому окну работать непосредственно с объектом Spreadsheet. Это значительно снизит универсальность диалогового окна SortDialog, поскольку оно будет работать только с виджетами определенного типа, но это позволит еще больше упростить программу из-за возможности исключения функции SortDialog::setColumnRange. В этом случае функция MainWindow::sort примет следующий
Этот подход является зеркальным отражением первого: вместо знания вызывающим компонентом характерных особенностей диалогового окна теперь само диалоговое окно должно иметь представление об особенностях структур данных, передаваемых вызывающим компонентом. Этот подход полезно применять, когда диалоговому окну требуется отслеживать изменения. В то время как при первом подходе ненадежен код вызвавшего компонента, третий подход перестает работать при изменении структуры данных.
Некоторые разработчики выбирают один из подходов и всегда следуют ему. При этом разработка диалоговых окон становится более привычным и простым делом, однако достоинства других подходов не будут использованы. В идеале решение по выбору конкретного подхода должно учитывать в каждом случае особенности конкретного диалогового окна.
Мы завершим данный раздел созданием диалогового окна About (справка о программе). Мы могли бы создать для представления данных о программе специальное диалоговое окно наподобие созданных нами ранее Find или Go-to-Cell, но поскольку диалоговые окна About сильно стилизованы, в средствах разработки Qt предусмотрено простое решение:
Рис. 3.15. Справка о приложении Электронная таблица.
Диалоговое окно About получается путем вызова удобной статической функции QMessageBox::about. Эта функция очень напоминает функцию QMessageBox::warning, однако здесь вместо стандартных «предупреждающих» пиктограмм используется пиктограмма родительского окна.
Таким образом, мы уже сумели воспользоваться несколькими удобными статическими функциями, определенными в классах QMessageBox и QFileDialog. Эти функции создают диалоговое окно, инициализируют его и вызывают для него функцию exec. Кроме того, вполне возможно, хотя и менее удобно, создать виджет QMessageBox или QFileDialog так же, как это делается для любого другого виджета, и явно вызвать для него функцию exec или даже show.
Сохранение настроек приложения
В конструкторе MainWindow мы уже вызывали функцию readSettings для загрузки сохраненных приложением настроек. Аналогично в функции closeEvent мы вызывали writeSettings для сохранения настроек. Эти функции являются последними функциями—членами MainWindow, которые необходимо реализовать.