Конференция "Основная" » Реализация интерфейса-мастера.
 
  • Kolan © (29.02.08 17:02) [0]
    Здравствуйте,
     Разрабатываю программу для тач скрина. Интерфейс (все представляют терминал оплаты) состоит из нескольких экранов, которые работают как мастер.

    Вопрос как это реализовать?

    Как показывать окна я придумал, имхо, надо использовать некие мета данные, где описаны какие окна должны открываться.

    А вот как быть с остальными (кроме показа окон) действиями?

    Допустим есть 4 шага. На шаге 2 пользователь вводит данные, а на шаге 4 их надо обработать как-то.

    У меня есть идея, но она мне ненравится из за условного выражения.
    Чтобы перейти на сл экран пользователь жмет «далее». Соотв при нажатии далее возникает событие «Далее(Sender)», где сендер — это окно где нажали далее. Какое следующее окно паказать написанно в мета данных, а что сделать определяется по Sender.

    То есть что-то вроде:
    if Sender.StepNumber = 2 then
     <сохранить даные>
    if Sender.StepNumber = 4 then
     ShowMessge(<сохраненные данные>)



    Мне ненравится такой подход из за if'а…

    А что вы посоветуете?
  • Игорь Шевченко © (01.03.08 00:05) [1]

    > А что вы посоветуете?


    Конечный автомат.

    type
     TAutomataState = (asStartState, asState1, asasState2, asCompleteState);

    И анализировать этот State при действиях
  • Kolan © (01.03.08 10:37) [2]
    > И анализировать этот 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…
    Но вот как быть с выполнением действий — хз.

    Плюс ко всму окон много и кейс будет здоровый…

    Мож есть еще идеии?
  • b z (01.03.08 12:42) [3]

    > Мож есть еще идеии?

    Может взять компонент аля wizard?
  • Kolan © (01.03.08 14:07) [4]
    > Может взять компонент аля wizard?

    А как он работает?

    Визард (собссно есть свой) — это страницы (на подобии PageControl) которые лежат на форме, то есть. Мне бы хотелось не создавать ненужные окна.
  • Kolan © (03.03.08 10:09) [5]
    Мож есть у кого еще идеи?
  • clickmaker © (03.03.08 13:15) [6]

    > Мне ненравится такой подход из за if'а

    не вижу логики.
    Чем if-то плох?
  • Kolan © (03.03.08 13:35) [7]
    Плохо тем, что неудобно добавлять или удалять экраны. Кроме того экранов много и иф будет большой — неудобно. А еще есть как-бы разные ветки, несвязаные друг с другом, и все это будет в одном месте…
  • Семеныч (03.03.08 14:03) [8]
    > Kolan ©   (03.03.08 13:35) [7]

    Вместо if можно вызывать некий метод (или процедуру), но не напрямую, а по ссылке, которая хранится в некоей переменной и устанавливается конечным автоматом в зависимости от его текущего состояния.
  • Kolan © (03.03.08 14:19) [9]
    > которая хранится в некоей переменной

    Лучьше уж стратегию использовать, только как. Хотелось бы более конкретный пример.
  • clickmaker © (03.03.08 14:23) [10]

    > Плохо тем, что неудобно добавлять или удалять экраны.

    и часто они будут добавляться/удаляться?
    все равно же одним добавлением не ограничится? Нужно же еще какой-то код писать, так ведь?
  • KSergey © (03.03.08 14:27) [11]
    > Kolan ©   (01.03.08 10:37) [2]
    > Теперь если надо вставить asState1 между asStartState и
    > asasState2, то надо менять ссылки — неудобно.

    Вот именно поэтому Игорь и говорит про конечный автомат.
    Весь этот "большой case", которого вы так опасаетесь в итоге просто вынесется в однельный управляющий unit, который будет это самый case содержать и создавать требуемые формы при надобности в зависимости от кнопок, нажатых пользователем (анализировать результат ShowModal).
    Такой подход позволит:
    а) элементарно вставлять новые шаги в середину визарда;
    б) легко реализовать кнопку "пошли все на!" на k., шаге;
    в) в дополнение к пункту а - построить в одном месте логику "Шаг X из Y" (при условии поддержки в формах)
    г) главная засада взардов - иногда возникающая необходимость пропускать некоторые шаги в зависимости от пользовательского ввода. Здесь этот обычно довольно некрасивый и развесистый код реализуется хотя бы в одном точно месте.

    ну и главное: если визард тупо-глупо линейный, т.е. только с кнопочками "Back" / "Next" / "Cancel" - то можно и вовсе прописать классы форм в перечислителе - тогда и вовсе никаких Case не понадобится.
  • Kolan © (03.03.08 14:37) [12]
    > и часто они будут добавляться/удаляться?
    > все равно же одним добавлением не ограничится? Нужно же
    > еще какой-то код писать, так ведь?

    Опыт показал что может 1-2 добавится/исчезнуть.

    Угу, ессно код писать надо, если бы ненадо было, то я, как говорил, использовал бы мета данные и редактировал бы только их.
    В том и дело, что код писать надо.


    > элементарно вставлять новые шаги в середину визарда;

    Сомневаюсь.


    > если визард тупо-глупо линейный

    Визард восе не тупой.

    Для варианта с кэйсом я уже придумал все:

    Сделаю общего предка для всех форм визарда. Предок будет содержать классовую функцию, которая вернет код формы(этот код и есть как-бы стейт).
    В инициализациях потомки будут регистрировать свои классы.

    Тот класс, у кого и будет всеь этот кейс будет по полученному коду и операции делать что-то, а потом брать инфу из мета данных, как в [2], и показывать следующиее окно.

    Валидация будет внутри форм.

    Оцените, плз…
  • Игорь Шевченко © (03.03.08 15:07) [13]

    > Оцените, плз…


    Keep It Simple Stupid
  • oxffff © (03.03.08 15:50) [14]

    > А что вы посоветуете?


    А чем тебе двунаправленный список не угодил?
    Объект в элементе списка поддерживает интерфейс.

    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.
  • Kolan © (03.03.08 18:23) [15]
    > Keep It Simple Stupid

    Вроде просто, а вы предлогаете что? Не [1] я читал, как конкретно предлагается реализовать? Где хранить состояния? Как узнавать что следующим показывать?


    > А чем тебе двунаправленный список не угодил?
    > Объект в элементе списка поддерживает интерфейс.

    Так и хотел сделать примерно, только операций много не только «Назад» «Далее», поэтому интерфейс несколько другой.
    Вопрос что писать в контроллере? При возникновении  Back и Forward?
  • oxffff © (03.03.08 22:18) [16]

    > Вопрос что писать в контроллере? При возникновении  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;
  • Kolan © (03.03.08 22:58) [17]
    > procedureTStepController.back(node:TStepNode);

    Так это для одного «нода» а теперь представь что  их 25 и у всех по некст(бэк не беру тут проще) надо делать разные действия.
    Так вот как ты это напишешь? Вот сама суть того, что я хз как сделать, чтобы попроще было…
  • oxffff © (03.03.08 23:11) [18]

    > Kolan ©   (03.03.08 22:58) [17]


    У конктроллера есть связный список переходов на одном уровне.
    Его уведомляет элемент о Back переходе, вызовом

    procedureTStepController.back(node:TStepNode);

    У контролер зафиксировано предудущее состояние (либо оно вычисляется). Он совершает на него переход.

    Динамическая структура, без статической привязки.

    Что тебе не нравится?
  • Kolan © (03.03.08 23:31) [19]
    Да переход фигня, кароме него работу еще надо сделать.

    На 2 шаге запомнить в переменную на 4 что-то с ней сделать, на 7 запустить поток и туда её засунуть…

    Вот как это делать ты прелагаешь — непонятно.
 
Конференция "Основная" » Реализация интерфейса-мастера.
Есть новые Нет новых   [134484   +45][b:0][p:0.001]