| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > класс для облегчения работы с GUI |
| Автор: Alek86 9.1.2008, 18:36 |
| в общем, вопрос из разряда "хотелось бы отакую штуку, а вдруг уже есть?" иногда, как ни жаль, приходится работать с формами, на которых есть немало кнопок, эдитов и т.п. самое обидное, что часто приходится делать их "визибл/инвизибл" или "энэйблэд/дисэйблэд" в зависимости от того, в какой ситуации какую конпку нажали. очень бы хотелось иметь шаблон (не С++ template) этакого "конечного автомата" с некоторым количеством состояний (немелким, но конечным), в котором можно держать состояния видимости и доступности для контролов и в который можно было бы добавлять различные "события". К примеру, если есть эдит, в который записывается сообщение, и кнопка - "Послать сообщение в чат". Если эдит не заполнен, то и кнопке "Послать" нужно быть недоступной, а когда приходит событие "Эдит стал непустым", она становится доступной. При событии "Эдит опустел" она снова тухнет. Идея хороша была бы не только тем, что тогда вся эта логика собрана в одном месте, но и тем, что сравнительно нетрудно сделать тестер, который предоставит все возможные для данного первоначального состояния и данных реакций на события состояния автомата (и "пути" из событий, по которому эти состояния были достигнуты). Ибо баги с тем, что кнопка, которая должна быть недоступной, вдруг ни с того ни с сего стала доступной, имхо, одни из самых задалбывающих... мне уже приходилось пару раз писать подобные простенькие автоматы, но а вдруг такое уже давным-давно существует? и если существуют, то уж определенно получше, чем я смогу в свободное время наваять.... в общем, это и весь вопрос - знает кто-либо что-либо подобное? |
| Автор: JackYF 9.1.2008, 18:41 |
| Кстати, да - дваждую вопрос. Пока не очень сильно надобилось, но задумывался. |
| Автор: Earnest 9.1.2008, 19:50 |
| ИМХО, такие вещи лучше делать примерно так (без автоматов и явного прописывания состояний): 1) каждый контрол имеет вирт функцию OnUpdate с каким-то подходящим параметром или, что почти тоже самое, родительская форма имеет функцию OnUpdateItem, которая вызывается для каждого элемента в определенные периоды времени. Во втором случае можно завести таблицу (ид-р элемента -> Update-функция) - чтобы со свичами не связываться. В общем, какой-то диспетчер. Для каждого элемента может быть установлено состояние, текст, выделение, etc (в зависимости от элемента) - и все это дело зависит от состояния родительской формы (режим, установленные значения - что угодно). Функцию, которая вызывает эти Update'ы, назовем UpdateItems. 2) Эта функция может вызываться в цикле простоя (автоматически, средой) или прямо (формой, по наступлению каких-то событий). Собственно, все. Весьма гибко и удобно. Не нужно выдумывать никакие "состояния", ибо состояние - это совокупность значений переменных формы. Для обновления каждого поля реализуются свои проверки. Да, есть некоторая избыточность - при изменении некоторой переменной, не влияющей на данной поле, его Update все же будет вызван (т.к. вызывается всегда - после любых изменений), но на практике это совершенно не грузит интерфейс - зато здорово разгружает код. Для случаев более тяжело обновляемых компонент можно реализовать спец. проверки. |
| Автор: JackYF 9.1.2008, 20:15 |
| Earnest, я почему-то подобные решения и представлял как собственный велосипед. Например, чтобы контролу заиметь функцию OnUpdate, от него надо отнаследоваться. Разным контролам в onUpdate надо подсовывать разные типы данных - строку, число, булевское значение... |
| Автор: Earnest 9.1.2008, 20:42 | ||
Если велосипед написать один раз, и написать хорошо, то это уже будет мопед или даже мотоцикл Насчет "отнаследоваться" - да, верно, проще пользоваться стандартными контролами в общем случае. Поэтому я и написала про несколько Апдейтов на родительской форме + диспетчеризация вызовов. А передавать разные переменные вовсе не обязательно - спрашиваем у формы то, что нас в каждом конкретном случае интересует. Например: кнопка - "Послать сообщение в чат", которая зависит от набитого в поле текста. Пишем OnUpdateSendMsg: форма, дай текстик от поля трам-пам-пам. Пустой? - засериваюсь! Ну и т.д. Логически, вообще никакие параметры не нужны (кроме формы, конечно - эти функции могут быть и не частью формы, можно такую обновлялку как отдельный класс писать). Технически - может потребоваться какой-то вспомогательный параметр типа контекста... Добавлено через 3 минуты и 2 секунды Кстати, развитые фрейворки наверняка такой или похожий подход предоставляют. MFC, например. А общего класса-объекта, конечно, нет, т.к. сильно от среды зависит. |
| Автор: Alek86 10.1.2008, 10:53 | ||||
почему это он зависит от среды? к тому же при таком подходе (что предложил(а) Earnest), работа с состояниями контролов будет разнесена. А это, имхо, не есть хорошо. Повторюсь, что автомат не только позволит собрать всю эту логику в одном месте, но и автоматически протестить ее. К тому-же, благодаря шаблонам в автомат можно подсунуть не булевые переменные, а уже сами классы контролов, чтобы автомат мог сам менять их состояния. (если кто-то не понял, и очень захочет убедиться, то могу кинуть код, но он не очень мелкий).
реализовать-то можно, просто думалось, что уже есть такое.... Добавлено через 5 минут и 37 секунд не заметил, посмотрим-с.... |
| Автор: archimed7592 10.1.2008, 11:08 |
От GUI-библиотеки, если быть точнее Ну, по хорошему, велосипед - это массив экшэнов(Action) с некоторой, минимальной, логикой |
| Автор: Lazin 10.1.2008, 12:34 | ||
| Как то городил подобное на VCL, у меня был TActionList и набор TAction. Каждое действие назначалось как минимум одному контролу, а чаще нескольким. Затем у меня возникла необходимость некоторые из них прятать время от времени, для этого я использовал свойство Tag. Для разных категорий действий (TAction) я установил разные значения Tag и потом в коде определял по ним какие TAction когда должны-быть активны, видимы и т.д. код уродлив но крайне эффективен
|
| Автор: mes 15.1.2008, 14:32 |
| в обшем виде я делаю так так: В одном месте строю модель UI (без widget'ов). При изменение своего состояния он вызывает событие на обновление вида. Событие распределяется по всем widget`ам которые имееют отношение к этой модели например модель контрола для отправки сообшения в чат CChatTextSender имеет события "Активен" "Неактивен" "СтрокаОчишена" "ПоявилсяТекст" "ТекстНаОтправку" "ТекстОтправлен" Например представление состоит из строки, кнопки и возможно еше чего нибудь. Тогда у всех них вызывается метод UpdateUI_OnChatTextSenderEvent (...); Итого получается что логика собрана в одном месте, а представление логики в другой. P.S Вид диспетчеризации сообшения приведен условно.. Вариантов несколько - но эта другая тема |
| Автор: Alek86 15.1.2008, 14:54 |
| повторюсь, у меня главная идея была в том, чтобы абстрагироваться от контролов и собрать все это в одном классе |
| Автор: mes 15.1.2008, 17:14 | ||||||
Ну и я про то же... Вначале забываешь про контролы и составляешь функциональный объект. Каждый такой объект может генерировать UpdateUI с параметрами события. например так:
Потом составляешь форму. Бросаешь туда контролы. Каждый контрол подписываешь на события от одного или более функциональнго объекта. А в в обработку внутренних событий контрола (например нажатие кнопки) бросаешь метод от ф. обьекта. И того в контралах только вызов функции и изменение вида при каких то определенных событиях (независимо от состояния других) . то есть контролы выглядит примерно так:
При том получение контрола возмоэно двумя путями. Наследоваться от кнопки и дополнить ее функционалом Или включать в себя кнопку как объект (указатель на него) и подписываться на события. Второй способ мне кжется предпочтительней. А да ... мелкие функциональные объекты (могут быть) объеденены в одном большом который обеспечивает связи между ними и выдает по требованию ссылку на их интерфейс |