Re[2]: Мысль о GUI
От: Lonely Dog Россия  
Дата: 20.06.06 13:24
Оценка:
Здравствуйте, Vector, Вы писали:

V>Если интересно, могу более подробно все расписать...

V>Или же соорудить простенький проектик с использованием всего этого...
Пока не очень понял принцип работы, но выглядит хорошо. Примерно тоже самое я и хотел сделать.
Если есть возможность расписать более подробно, то сделай это плиз.
Заранее спасибо.
Re[3]: Мысль о GUI
От: Vector Россия  
Дата: 21.06.06 06:56
Оценка:
Здравствуйте, Lonely Dog, Вы писали:

LD>Здравствуйте, Vector, Вы писали:


V>>Если интересно, могу более подробно все расписать...

V>>Или же соорудить простенький проектик с использованием всего этого...
LD>Пока не очень понял принцип работы, но выглядит хорошо. Примерно тоже самое я и хотел сделать.
LD>Если есть возможность расписать более подробно, то сделай это плиз.
LD>Заранее спасибо.

Вобщем идея в том, чтобы использовать вместо простых типов классы, отнаследованные от CProperty, у которого есть событие OnChange.
У конкретных пропертей (CStringProperty, CIntProperty, CSystemTimeProperty...) Есть Get-теры и Set-теры, а так же преобразование к ссылке на тип, который оно заменяет, вобщем, ведут они себя как те типы, которые они "оборачивают", только кидаются OnChange-ем при изменении.

Дальше — есть базовый классик CPropertyBind — обеспечивает связь CProperty с элементом управления. CPropertyBind будет уведомляться от окна о событиях WM_COMMAND и WM_NOTIFY от контрола (будет вызываться его абстрактный метод OnCommand), так же он подписывается на OnChange у Property и обновляет состояние элемента управления.

Ну, и есть класс CBindingImpl, у которого есть std::multimap<UINT, CPropertyBind*> m_mapBindProp и MSG_MAP, который ловит WM_COMMAND и WM_NOTIFY и уведомляет о них Bind-ы(В multimap-е ключом является ID-шник элемента управления).
Теперь тупо реаизовываются всякие разные Property, мне хватило Int, String, SystemTime, и для каждого из них различные Bind-ы, к примеру для IntProperty есть:
CBind — помещает число в контрол (SetDlgItemInt, GetDlgItemInt)
CBindRadio — содержит значение, который нужно запихнуть в IntProperty, если RadioButton сделают "выбранным"
CBindCheck — содержит флаг, который нужно запихнуть(убрать) в IntProperty, если CheckBox чекнут(анчекнут)
CBindEnabled — содержит значение(или флаг), котрое должно содержать свойство, чтобы контрол за-Enable-лся.

Этого уже достаточно, чтобы рулить GUI, в котором много переключателей и от каждого из них зависит доступность разных контролов(именно для этого, в первую очередь, я это все и затеял)

Да, еще всякие макросы для BIND-а, это понятно, для удобства описания.

здесь лежит тестовый проектик. Идея реализована совсем недавно, поэтому, думаю, что еще буду додумывать, буду рад услышать предложения, мысли и все такое
Re: Мысль о GUI
От: Аноним  
Дата: 22.06.06 20:48
Оценка:
Здравствуйте, Lonely Dog, Вы писали:

LD>Привет!


LD>Родилась мысль о том, как можно упростить реализацию GUI, конкретнее, хочется заставить систему саму отсжеливать состояния контролов. (enabled/disabled, visible, и пр)

LD>Поясню на примере: пусть у нас есть диалог смены пароля. В этом диалоге есть поле ввода нового пароля и поле его подтверждения.
LD>Кроме того, на диалоге есть кнопки OK и Cancel. Если поле вводе нового пароля пустое, кнопка OK должна быть в состоянии disabled. Если строка введенная в поле ввода нового пароля не равна строке в поле подтверждения, то OK также должна быть в состоянии disabed. Кроме того, пусть на диалоге будет текстовое поле с подсказкой. Если поле нового пароля пустое, подсказка будет отображать строку "пароль не может быть пустым". Если новый пароль и его подтверждение не совпадают, подсказка будет отображать строку "пароли не совпадают." Хочется описывать большую часть этого поведения декларативно, на уровне некой карты поведения диалога. (как карта сообщений в WTL или MFC.) Не очень понятно, как это сделать. Пока я думаю в сторону конечных автоматов, но возможно вы сможете подсказать что-нибудь еще?

LD>Заранее спасибо.


LD>PS: Есть мысль развить эту идею до уровня библиотеки. Сам я пишу на WTL, т.ч. первая версия будет для нее. В дальнейшем, можно будет сделать и для остальных библиотек (и языков).


Возможно с точки зрения организации классов можно использовать паттерн Меdiator, описанный в книге Эриха Гаммы с сотоварищами, про паттерны проектирования.
Re[4]: Мысль о GUI
От: remark Россия http://www.1024cores.net/
Дата: 25.06.06 22:14
Оценка:
Здравствуйте, Vector, Вы писали:

V>здесь лежит тестовый проектик. Идея реализована совсем недавно, поэтому, думаю, что еще буду додумывать, буду рад услышать предложения, мысли и все такое



Вот моя мысль.
Мне не нравится это:

class CIntProperty : public CProperty
{
//...
private:
    int        m_nValue;
};


Почему класс, который является чем-то вспомогательным для диалога, ответственнен за хранение данных?

Я бы сделал возможность принимать различные данные из вне, причём что бы это можно было расширить для своих классов с помощью шаблонов/динамического полиморфизма. Самый простой вариант для простого int:

class CIntProperty : public CProperty
{
public:
CIntProperty(int& value)
: m_nValue(value)
{}
//...
private:
    int&        m_nValue;
};



Что бы я мог расширить так:

class MyIntProperty : public CIntProperty
{
public:
CIntProperty(IntStorageThatAlreadyUsedInWholeProject& value)
: m_nValue(value)
{}
//...
private:
    IntStorageThatAlreadyUsedInWholeProject&        m_nValue;
};



IntStorageThatAlreadyUsedInWholeProject должен реализовывать интерфейс типа:

struct IStorage
{
getValue();
setValue();
subscribeToChange();
};


Тогда я смогу заюзать MyIntProperty, причём он не будет навязывать мне некасающихся его проектных решений.
Возможна функциональность вплоть до того, что IntStorageThatAlreadyUsedInWholeProject будет меняться другим потоком и через механизм подписки на события изменения автоматически обновляться в интерфейсе. С обычным int ты такого не сделаешь.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Мысль о GUI
От: remark Россия http://www.1024cores.net/
Дата: 25.06.06 22:18
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Vector, Вы писали:


V>>здесь лежит тестовый проектик. Идея реализована совсем недавно, поэтому, думаю, что еще буду додумывать, буду рад услышать предложения, мысли и все такое


Вот ещё одна мысль.
Нужны функции-преобразователи из внутреннего представления во внешнее и обратно.
Например, внутри программы временные интервалы хранятся в миллисекундых, а в диалоге они должны выводится в секундах.

В принципе даже тип внутреннего представления и внешнего могут не совпадать. Например, внутри программы хранится int/enum/ещё_что_то, а в диалог должна выводится строка.

R>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Мысль о GUI
От: Vector Россия  
Дата: 24.07.06 06:16
Оценка:
Здравствуйте, remark, Вы писали:

R>Вот моя мысль.

R>Мне не нравится это:

R>Почему класс, который является чем-то вспомогательным для диалога, ответственнен за хранение данных?


R>Я бы сделал возможность принимать различные данные из вне, причём что бы это можно было расширить для своих классов с помощью шаблонов/динамического полиморфизма. Самый простой вариант для простого int:


Класс CIntProperty не является вспомогательным для диалога. Он является оберткой над простым типом, и занимается уведомлением об изменении значения. Я эти самые SomeProperty выношу в класс документа, а не диалога/окна. Можно конечно не делать оберток над типами, но тогда нужно вручную вызывать что-то типа RefreshView, а я человек ленивый и писать это постоянно не хочу
Re[6]: Мысль о GUI
От: Vector Россия  
Дата: 24.07.06 06:28
Оценка:
Здравствуйте, remark, Вы писали:

R>Вот ещё одна мысль.

R>Нужны функции-преобразователи из внутреннего представления во внешнее и обратно.
R>Например, внутри программы временные интервалы хранятся в миллисекундых, а в диалоге они должны выводится в секундах.

R>В принципе даже тип внутреннего представления и внешнего могут не совпадать. Например, внутри программы хранится int/enum/ещё_что_то, а в диалог должна выводится строка.


Это можно решить написанием своего Bind класса, и биндить свойство через него. Конечно, не удобно, что все в ручную, но, думаю, что универсализма в данном случае будет проблематично добиться, и нужен ли он тут. Строку вместо enum нужно отображать обычно в ComboBox, для этого у меня есть CBindCombo. В комбик заливаются нужные строчки и проставляется у каждой строчки соответствующая Data (SetItemData), и все получается так как хотелось. Разве что каждый комбик заполняется отдельно, независимо от Property. Вобщем, не очень удобно, согласен, но жить с этим можно.
Re: Мысль о GUI
От: Аноним  
Дата: 24.07.06 08:07
Оценка:
Здравствуйте, Lonely Dog, Вы писали:

LD>Привет!


LD>Родилась мысль о том, как можно упростить реализацию GUI, конкретнее, хочется заставить систему саму отсжеливать состояния контролов. (enabled/disabled, visible, и пр)


http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/intWF_FndRlsEng.asp
Re[3]: Мысль о GUI
От: Gadsky Россия  
Дата: 24.07.06 08:16
Оценка:
Здравствуйте, Кодт, Вы писали:

К>В одной GUI-библиотеке (Zinc) у контролов было свойство Disabled, по умолчанию false. Там удобнее было задавать условия от противного.


Кстати вот да, простое и отличное решение не позволяющее запинать реализацию корректного свойства на потом.
Re: Мысль о GUI
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.07.06 23:26
Оценка: +1
Здравствуйте, Lonely Dog, Вы писали:

LD>Привет!


LD>Родилась мысль о том, как можно упростить реализацию GUI, конкретнее, хочется заставить систему саму отсжеливать состояния контролов. (enabled/disabled, visible, и пр)

LD>Поясню на примере: пусть у нас есть диалог смены пароля. В этом диалоге есть поле ввода нового пароля и поле его подтверждения.
LD>Кроме того, на диалоге есть кнопки OK и Cancel. Если поле вводе нового пароля пустое, кнопка OK должна быть в состоянии disabled. Если строка введенная в поле ввода нового пароля не равна строке в поле подтверждения, то OK также должна быть в состоянии disabed. Кроме того, пусть на диалоге будет текстовое поле с подсказкой. Если поле нового пароля пустое, подсказка будет отображать строку "пароль не может быть пустым". Если новый пароль и его подтверждение не совпадают, подсказка будет отображать строку "пароли не совпадают." Хочется описывать большую часть этого поведения декларативно, на уровне некой карты поведения диалога. (как карта сообщений в WTL или MFC.) Не очень понятно, как это сделать. Пока я думаю в сторону конечных автоматов, но возможно вы сможете подсказать что-нибудь еще?
А я думаю, что КА для мало-мальски сложного диалога быстро приведут в тупик. Причины уже приведены. Из одного требования коммутативности реакций на действия пользователя сразу получается, что состояние зависимых контролов описывается не последовательностью изменений в управляющих контролах, а просто некоторой функцией от самого этого состояния.

Так что более надежным подходом скорее будет являться функциональный. Т.е. вместо карты переходов разрешаем ассоциировать свойства Enabled и Visible с некоторыми предикатами, которые однозначно вычисляются на основе свойств контролов диалога (и, может быть, чего-то еще — к примеру, настроек приложения или текущего состояния document в модели MVC).

У этого подхода тоже есть одна грабля: выражения должны гарантировать отсутствие циклов. Иначе набор этих предикатов может стать вырожденной системой уравнений, у которой либо больше одного решения, либо нет ни одного.

Можно вообще запретить использовать в предикатах свойства Enabled и Visible, а применять предикаты — только к этим двум свойствам.
Можно сделать детектирование циклов а-ля Excel.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Мысль о GUI
От: Георгиевич Россия  
Дата: 24.08.07 13:10
Оценка:
Есть еще одна проблема автоматов, и она обязательно проявится — комбинаторный взрыв.
Re: Мысль о GUI
От: minorlogic Украина  
Дата: 24.08.07 19:04
Оценка:
При использовании MVC или какого либо похожего варианта (например можно лениво совместить все в одном модуле) нам не требуется ВООБЩЕ как то особо прописывать отношения между контролами.

Мы пишем набор предикатов ручками , например update кнопки OK вызывает прописанный условие isVisible() в ктором мы кодим конкретную инфу.

Теперь когда юзер набирает пароль, мы получаем ON_CHANGE на поле ввода , и логично было бы там вызвать некий updateOKButton , но это грубейшая ОШИБКА. Единственное что он должен делать это запланировать Update всей формы.

А вот Update всей формы пробегает по контролам и все они меняют состояние на соответствующие. А создавать отдельный язык для предикатов контролов , кажется слишком неблагодарное занятие, слишком много вариантов.

P.S. задача этого посат не описать идеальную архитектуру а показать стандартные ошибки начинающих GUI строителей. Опять я не знаю насколько знаком автор поста с MVC , если знаком то прошу прощения за мой пример , может он послужит другим.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.