-
Здравствуйте, Разрабатываю программу для тач скрина. Интерфейс (все представляют терминал оплаты) состоит из нескольких экранов, которые работают как мастер. Вопрос как это реализовать? Как показывать окна я придумал, имхо, надо использовать некие мета данные, где описаны какие окна должны открываться. А вот как быть с остальными (кроме показа окон) действиями? Допустим есть 4 шага. На шаге 2 пользователь вводит данные, а на шаге 4 их надо обработать как-то. У меня есть идея, но она мне ненравится из за условного выражения. Чтобы перейти на сл экран пользователь жмет «далее». Соотв при нажатии далее возникает событие «Далее(Sender)», где сендер это окно где нажали далее. Какое следующее окно паказать написанно в мета данных, а что сделать определяется по Sender. То есть что-то вроде: if Sender.StepNumber = 2 then
<сохранить даные>
if Sender.StepNumber = 4 then
ShowMessge(<сохраненные данные>) Мне ненравится такой подход из за if'а
А что вы посоветуете?
-
> А что вы посоветуете?
Конечный автомат.
type TAutomataState = (asStartState, asState1, asasState2, asCompleteState);
И анализировать этот State при действиях
-
> И анализировать этот State при действиях
И сделать большой кейс? Ну я тоже самое и предложил, только в моем случае эти стейты хроняться в самих окнах как бы, и передаются по событию
В стейтах плохо то, что трудно модифицировать такой автомат, я так пробовал. Например бы такой:
case Stae of:
asStartState:
begin
DoSmth;
State := asState2;
end;
asasState2:
begin
State := CompleteState;
end;
asCompleteState:
begin
end; Теперь если надо вставить asState1 между asStartState и asasState2, то надо менять ссылки неудобно. Кроме того, нафига состояния если состояние однозначно связано с показываемым экраном, так почему бы не использовать сам экран(то есть форму у меня) в качестве состояния. Если бы надо было бы только показывать экраны, то я бы сделал, наверно, такой файлик: У окон есть номера.[0.0]
Next=0.1
[0.1]
Next=0.2
Back=0.1 То есть некие мета данные
Загружал бы его и при возникновении события «Back» в окне «0.1» я бы знал, что надо перейти в окно 0.1
Но вот как быть с выполнением действий хз. Плюс ко всму окон много и кейс будет здоровый
Мож есть еще идеии?
-
> Мож есть еще идеии?
Может взять компонент аля wizard?
-
> Может взять компонент аля wizard?
А как он работает?
Визард (собссно есть свой) это страницы (на подобии PageControl) которые лежат на форме, то есть. Мне бы хотелось не создавать ненужные окна.
-
Мож есть у кого еще идеи?
-
> Мне ненравится такой подход из за if'а
не вижу логики. Чем if-то плох?
-
Плохо тем, что неудобно добавлять или удалять экраны. Кроме того экранов много и иф будет большой неудобно. А еще есть как-бы разные ветки, несвязаные друг с другом, и все это будет в одном месте
-
> Kolan © (03.03.08 13:35) [7]
Вместо if можно вызывать некий метод (или процедуру), но не напрямую, а по ссылке, которая хранится в некоей переменной и устанавливается конечным автоматом в зависимости от его текущего состояния.
-
> которая хранится в некоей переменной
Лучьше уж стратегию использовать, только как. Хотелось бы более конкретный пример.
-
> Плохо тем, что неудобно добавлять или удалять экраны.
и часто они будут добавляться/удаляться? все равно же одним добавлением не ограничится? Нужно же еще какой-то код писать, так ведь?
-
> Kolan © (01.03.08 10:37) [2] > Теперь если надо вставить asState1 между asStartState и > asasState2, то надо менять ссылки — неудобно.
Вот именно поэтому Игорь и говорит про конечный автомат. Весь этот "большой case", которого вы так опасаетесь в итоге просто вынесется в однельный управляющий unit, который будет это самый case содержать и создавать требуемые формы при надобности в зависимости от кнопок, нажатых пользователем (анализировать результат ShowModal). Такой подход позволит: а) элементарно вставлять новые шаги в середину визарда; б) легко реализовать кнопку "пошли все на!" на k., шаге; в) в дополнение к пункту а - построить в одном месте логику "Шаг X из Y" (при условии поддержки в формах) г) главная засада взардов - иногда возникающая необходимость пропускать некоторые шаги в зависимости от пользовательского ввода. Здесь этот обычно довольно некрасивый и развесистый код реализуется хотя бы в одном точно месте.
ну и главное: если визард тупо-глупо линейный, т.е. только с кнопочками "Back" / "Next" / "Cancel" - то можно и вовсе прописать классы форм в перечислителе - тогда и вовсе никаких Case не понадобится.
-
> и часто они будут добавляться/удаляться? > все равно же одним добавлением не ограничится? Нужно же > еще какой-то код писать, так ведь?
Опыт показал что может 1-2 добавится/исчезнуть.
Угу, ессно код писать надо, если бы ненадо было, то я, как говорил, использовал бы мета данные и редактировал бы только их. В том и дело, что код писать надо.
> элементарно вставлять новые шаги в середину визарда;
Сомневаюсь.
> если визард тупо-глупо линейный
Визард восе не тупой.
Для варианта с кэйсом я уже придумал все:
Сделаю общего предка для всех форм визарда. Предок будет содержать классовую функцию, которая вернет код формы(этот код и есть как-бы стейт). В инициализациях потомки будут регистрировать свои классы.
Тот класс, у кого и будет всеь этот кейс будет по полученному коду и операции делать что-то, а потом брать инфу из мета данных, как в [2], и показывать следующиее окно.
Валидация будет внутри форм.
Оцените, плз
-
> Оцените, плз…
Keep It Simple Stupid
-
> А что вы посоветуете?
А чем тебе двунаправленный список не угодил? Объект в элементе списка поддерживает интерфейс.
TStepNode=class function IsDataValid:boolean;Virtual;abstract; вызывается controlleroм для { }
function Back:integer;Virtual;abstract; делегирует вызов контролер .передавая себя в параметре. function Forward:integer;Virtual;abstract; делегирует вызов контролеру. передавая себя в параметре.
function SkipSteps(stepCount:integer):Boolean делегирует вызов контролеру который проверяет уж каждого пропущенного IsDataValid. И в случае успеха устанавливает текущий шаг.
Рассуждая так далее можно сделать вложенные шаги и т.д.
Игорь Шевченко © (03.03.08 15:07) [13]
Keep It smart and simple.
-
> Keep It Simple Stupid
Вроде просто, а вы предлогаете что? Не [1] я читал, как конкретно предлагается реализовать? Где хранить состояния? Как узнавать что следующим показывать?
> А чем тебе двунаправленный список не угодил? > Объект в элементе списка поддерживает интерфейс.
Так и хотел сделать примерно, только операций много не только «Назад» «Далее», поэтому интерфейс несколько другой. Вопрос что писать в контроллере? При возникновении Back и Forward?
-
> Вопрос что писать в контроллере? При возникновении Back > и Forward?
function TStepNode.Back:boolean; begin result:=controller.back(self); end;
procedureTStepController.back(node:TStepNode); begin if AllowBack and node.AllowBack then // paranoiac AllowBack :) begin Node.Detach; // on Node setStepNode(previous); // <- где previous может быть не предыдущий, а тот например который Skipped, либо другое поведение на твое усмотре previous.Attach; end; end;
end;
-
> procedureTStepController.back(node:TStepNode);
Так это для одного «нода» а теперь представь что их 25 и у всех по некст(бэк не беру тут проще) надо делать разные действия. Так вот как ты это напишешь? Вот сама суть того, что я хз как сделать, чтобы попроще было
-
> Kolan © (03.03.08 22:58) [17]
У конктроллера есть связный список переходов на одном уровне. Его уведомляет элемент о Back переходе, вызовом
procedureTStepController.back(node:TStepNode);
У контролер зафиксировано предудущее состояние (либо оно вычисляется). Он совершает на него переход.
Динамическая структура, без статической привязки.
Что тебе не нравится?
-
Да переход фигня, кароме него работу еще надо сделать.
На 2 шаге запомнить в переменную на 4 что-то с ней сделать, на 7 запустить поток и туда её засунуть
Вот как это делать ты прелагаешь непонятно.
|