Как построить сохранение состояния компонентного приложения?
Представим задачу в вакууме. Имеется приложение, которое содержит следующие графические компоненты:
1) область с меню
2) список с чекбоксами
Макет представляется таким:
корневой элемент - область с меню
- внутри области (выбрав определённую вкладку) ещё одна область с под-меню
-- внутри области (выбрав определённую вкладку) 2 списка с чекбоксами, расположенные рядом
Требуется при старте приложения подать такой файл конфигурации, который сымитирует нажатие на нужную вкладку корневого меню, затем у вложенного, затем расставить чекбоксы в заданном виде. Эти действия не нужно отображать, пользователю должен сразу представиться нужный вид.
Тут непонятно, как при этом сохранить компонентную независимость. Т.е. вариант передавать часть конфигурации от верхних элементов к нижним не покатит, потому что между ними может быть вставлен промежуточный контейнер - например, один из списков будет помещён в рамку или куда-нибудь ещё.
sim3x: ну да, суть вопроса перефразировал верно)
Если что-то осталось непонятным, прошу переспросить. Проблема в том, что при написании софта нужно сохранять независимость компонентов друг от друга, чтобы их можно было использовать повторно и менять компоновку.
Виталий:
Что в итоге накладывает два ограничения
- компонент должен знать в ком он находится и уметь пересылать сообщение - "покажите меня"
- конфиг должен быть "плоским"
sim3x: я так понимаю, речь о формате "ключ - значение". Как при этом избежать конфликтов между однотипными компонентами, требующими запись по одинаковым ключам?
sim3x: окей, но я ведь не зря привёл пример с двумя компонентами Меню и Список. В этом случае у нас получается последовательная запись
Меню: {ключ: значение}
Меню: {ключ: значение}
Список: {ключ: значение}
Список: {ключ: значение}
где следующий компонент того же типа перезаписывает настройки предыдущего.
Обычно компоненты вместе со своими свойствами и состояниями выгружаются в xml форму. Потом загружаются обратно. Иерархия компонентов хорошо ложиться в xml в виде вложенных структур или в виде ссылки на id родителя. Состояние чекбокса, например - лишь значение поля value - 1 или 0.
Так ведь задача - не выгрузка всех компонентов и их состояний, а лишь тех значений, которые выставляются опционально. Пример использования: ярлык на запуск программы с определённой конфигурацией, два ярлыка - два стартовых состояния.
Виталий: ИМХО, следует просто хранить начальное состояние, а также текущее. Если есть различие - показывать его. В любом случае, это тема gui state serialization. И я решал-бы ее именно так. Но, возможно я ошибаюсь.
Константин Степанов: кажется, мы говорим на разные темы. Само собой разумеется, что для того, чтобы сохранять и восстанавливать состояние GUI, нужно перед сохранением делать сериализацию ключевых значений состояния в файл/объект, который перед восстановлением будем парсить для перезаписи значений по умолчанию. Вопрос состоит в том, как организовать структуру такого файла, чтобы она была гибкой к изменениям GUI.
Пример: сделать хранилище "текстовый ключ - бинарное значение". Но в этом случае возникают две проблемы: возможный конфликт между различными компонентами и гарантированный конфликт при повторах компонентов одного типа.
Другой пример: сделать хранилище в виде древовидного документа. Но тогда возникает проблема собирать/передавать значения через промежуточные GUI-компоненты, которые не должны в этом участвовать.
Вероятно, решение состоит не в изменении структуры файла, а в проектировании GUI для взаимодействия компонентов между собой по определённой схеме.
Виталий: Я лично использую Qt и выгрузка сцены со всеми свойствами в xml работает из коробки. QAbstractFormBuilder умеет загружать и сохранять сцены в xml.
Вообще, GUI - это очень сложно, долго и муторно. Так что, рекомендую просто найти фреймворк который умеет делать все, что вам нужно, нежели писать свое.
Константин Степанов: я ведь объяснил, что мне не нужно выгружать сцены со всеми свойствами, мне нужен компактный файлик с описанием лишь некоторых значений.
Вариант 2 - QMainWindow может выгружать свое состояние в qbytearray и загружать из него. Всегда держите под рукой изначальное состояние в виде массива байт, а изменения храните в виде разницы нового и изначального массива. Вроде не сильно много будет.