Страница 1 из 2

Указатели, динамическое создание переменных и т.п.

Добавлено: 16 Декабрь 2007, 23:37
AnDS
Собственно описываю задачу, которую не могу решить:
Имеем очередь, содержащую наименования (скажем, метки) полей и их длину.
Пусть это будут строки (STRING) (хотя можно и другие типы данных использовать - не важно)

Необходимо динамически создать в окне ENTRY-поля для каждой записи в очереди.
Вроде бы все просто:
В цикле делаем create(control_id,create:entry,parent_id)
потом UNHIDE(control_id). Задаем все неоходимые свойства (координаты и т.п)

А вот как быть со свойством USE?
PROP:USE требует для ENTRY-полей задания USE-переменной

Первая мысль -- создадим динамически новые переменные!
Вторая мысль - как?
Первым делом придумалось вот что:
создать массив из указателей на строки
(ну ограничить себя, например 512-ю переменными)
А вот как правильно создать массив указателей на строки и потом подсунуть еще каждому ENTRY его USE-переменую?

Поискал у себя в закромах, раскопал старый пример Олега Руденко - как создавать через RTL Клариона новые переменные, обрадовался.
Приведу его полностью, что бы объяснить:

Код: Выделить всё

MAP
  MODULE('Clarion RTL')
    RTL::NewMem(UNSIGNED _Size),ULONG,NAME('Cla$NewMemZ')
    RTL::NewStr(UNSIGNED _Size),ULONG,NAME('Cla$NewMemB')
    RTL::FreeMem(ULONG _Addr),NAME('_free')
    RTL::Mem2UfoAddr(ULONG _VarAddr,BYTE _VarType,ULONG _DecFloat=0, |
    UNSIGNED _VarSize,BYTE=0),ULONG,RAW,NAME('Cla$Mem2Ufo')
    RTL::FreeUfo(ULONG _UFOAddr),RAW,NAME('Cla$FreeUfo')
    RTL::Bind(ULONG _UFOAddr,STRING _Name),NAME('Cla$BindV')
    RTL::UnBind(STRING _Name),NAME('Cla$UnbindV')
    RTL::GetBindVar(STRING _cVarName),*?,RAW,NAME('Cla$EvaluateVariable')
  END
END

Var1  ANY
sVar1 STRING(40)
Var2  ANY
sVar2 STRING(40)

VarNamesQue QUEUE,PRE(VAR)
Name     STRING(40) ! Имя переменной
Type     LONG ! Тип
Size     LONG ! Размер
DecFloat BYTE ! Для DECIMAL/PDECIMAL
Addr     LONG ! Здесь будет адрес блока памяти
UFOAddr  LONG ! Здесь будет адрес UFO-оболочки для переменной
           END
!
! Последние два поля при создании очереди инициализируются нулями.
!

CODE
...
Loop Var# = 1 to Records(VarNameQue)
  Get(VarNameQue,Var#)
  if ~VAR:Name OR ~VAR:Type OR ~VAR:Size Then Cycle.
  if VAR:Type = TYPE:STRING
    VAR:Addr = RTL::NewStr(VAR:Size)
  else
    VAR:Addr = RTL::NewMem(VAR:Size)
  .
  if ~VAR:Addr then Cycle. ! Память не выделена
  VAR:UFOAddr = RTL::Mem2UfoAddr(VAR:Addr,VAR:Type,VAR:DecFloat,VAR:Size)
  if ~VAR:UFOAddr ! UFO-оболочка не создана
    RTL::FreeMem(VAR:Addr)
    Cycle
  .
  RTL::Bind(VAR:UFOAddr,VAR:Name)
  Put(VarNameQue)   ! Обновить запись
.

Get(VarNameQue,1); Var1 &= RTL::GetBindVar(Clip(VAR:Name)&'<0>')
Get(VarNameQue,2); Var2 &= RTL::GetBindVar(Clip(VAR:Name)&'<0>')
! ВНИМАНИЕ!!! Если какая-либо переменная не найдена и ANY &= Null,
! без проверки на Message() получим GPF.
if ~(Var1 &= Null) AND ~(Var2 &= Null)
  Message(Var1 + Var2) ! Var1 + Var2
.

! В конце надо освобождать за собой занятую память:

  Loop Var# = 1 to Records(VarNameQue)
    Get(VarNameQue,Var#)
    if ~VAR:Addr then Cycle.
    RTL::FreeMem(VAR:Addr); Clear(VAR:Addr)
    if ~VAR:UFOAddr then Cycle.
    RTL::FreeUfo(VAR:UFOAddr); Clear(VAR:UFOAddr)
    RTL::UnBind(Clip(VAR:Name))
  .

Опять обрадовался -- пример сулит как раз именно то, что я хочу вроде бы.
Вместо Var1 и Var2 опишу массивчик Var ANY,DIM(512)
А потом буду работать с ним так:

Код: Выделить всё

Var[numb_of_var#] &= RTL::GetBindVar(Clip(VAR:Name)&'<0>')
И потом control_id{PROP:USE}=Var[numb_of_var#]

Фиг. В 32-х разрядной модели в C6RUNX.DLL нет 'Cla$EvaluateVariable'
(C63)
(то есть даже попробовать не удалось)

Ладно, думаю, попробую так:

Код: Выделить всё

Var[numb_of_var#] &= (VAR:Addr)
Так нельзя, оказывается, тоже. :-(

Так как реализовать такую, вроде бы простую, вещь?
(Или может быть я мудрю? Может это на уровне первого класса, а у меня ум за разум зашел?)

Помогите, плз, разобраться.

Добавлено: 16 Декабрь 2007, 23:43
AnDS
Хм. Сижу, читаю ClarionLife.
На глаза попадается статься того же магистра Олега Руденко:
http://www.clarionlife.net/content/view/144/29/

Так что же получается, можно вообще не указывать для ENTRY-поля USE-переменную?

UPD. что-то PROP:VALUE возвращает формат поля. Да и PROP:USE что-то не то... Вернее то же самое...
И событие accepted не проходит. Странно.
:-(

Добавлено: 17 Декабрь 2007, 13:17
Yufil
AnDS писал(а):Хм. Сижу, читаю ClarionLife.
На глаза попадается статься того же магистра Олега Руденко:
http://www.clarionlife.net/content/view/144/29/

Так что же получается, можно вообще не указывать для ENTRY-поля USE-переменную?

UPD. что-то PROP:VALUE возвращает формат поля. Да и PROP:USE что-то не то... Вернее то же самое...
И событие accepted не проходит. Странно.
:-(
Ну, я использую примерно так...

VV Group,Pre(),Dim(5000)
VarList &Cstring
End

VarQ Queue,Pre(VarQ)
Val &Cstring
N Long
Id Cstring(20)
End

VarQ:N = 1
VV[1].VarList &= New Cstring(1000)
VarQ:Val &= VV[1].VarList
VarQ:Id='A'
Bind('A',VV[1].VarList)

VarQ:N = 2
VV[2].VarList &= New Cstring(1000)
VarQ:Val &= VV[2].VarList
VarQ:Id='B'
Bind('B',VV[2].VarList)

Ну и так далее
Теперь, если на экране надо разместить 'A', находим её номер и размещаем VV[VarQ:N].VarList.

С уважением,
Юрий Философов

Добавлено: 17 Декабрь 2007, 16:27
AnDS
Хм. Ну да, так проще всего. И не нужно заморачиваться - куда-то меня вчера понесло не в ту степь... :-)

Второй вопрос:

При каком условии, на руками созданном ENTRY, проходят события EVENT:Accepted, EVENT:Selected?

Вот NewSelection проходит, когда IMM свойство есть. Это событие вижу.
А Accepted И Selected не вижу. :-(

Может какое-то свойство не добавил.
Окно описано так:

Код: Выделить всё

WINDOW('text-text-text'),AT(,,318,231),FONT('MS Sans Serif',8,,FONT:regular),ALRT(MouseLeft2),IMM,ICON('icon.ico'),TIMER(0),SYSTEM,GRAY,MASK,AUTO
вот поле (создано руками, но свойства такие):

Код: Выделить всё

ENTRY(@S20),AT(4,31,48,10),USE(loc:fl_Date),IMM,FLAT,RIGHT(2),FONT(,,COLOR:Blue,,CHARSET:ANSI), OVR

Re: Указатели, динамическое создание переменных и т.п.

Добавлено: 18 Декабрь 2007, 2:40
Олег
AnDS писал(а):Фиг. В 32-х разрядной модели в C6RUNX.DLL нет 'Cla$EvaluateVariable' (C63)
Да, в C63 изменили немного Evaluate-блок и перевели его на "классовую" модель - теперь с ним приходится работать немного по другому. И если раньше для получения имени BIND-переменной достаточно было вызвать одну функцию RTL, то теперь для этого надо использовать небольшой код с вызовом некоторых методов классов Evaluate-блока.
AnDS писал(а):Ладно, думаю, попробую так:

Код: Выделить всё

Var[numb_of_var#] &= (VAR:Addr)
Так нельзя, оказывается, тоже. :(
Ишь ты, чего захотел! :) Создать UFO-переменную только по одному адресу! Низззя!
Для этого надо еще, как минимум, указать тип переменной. А для строк и DECIMAL еще немного. Если очень хочется, то можно так:

Код: Выделить всё

MAP
  RTL::Mem2Ufo(LONG _VarAddr,BYTE _VarType,LONG _DecFloat=0,UNSIGNED _VarSize,BYTE=0),*?,NAME('Cla$Mem2Ufo'),DLL(dll_mode)
END

  Var[numb_of_var#] &= RTL::Mem2Ufo(VAR:Addr,VAR:Type,VAR:DecFloat,VAR:Size)
Как видишь, можно прекрасно обойтись и другим вариантом, без использования Evaluate-блока. Только не забудь потом уничтожить соданные UFO-обьекты с помощью Var[...] &= Null.
AnDS писал(а):Так что же получается, можно вообще не указывать для ENTRY-поля USE-переменную?
Да, для ENTRY-поля совсем необязательно назначать USE-переменные. В этом случае, как уже писал, всю работу по созданию временных переменных на время жизни таких контролов берет на себя RTL. Работать с такими контролами можно абсолютно так-же, как и с обычными, у которых есть USE-переменная. А получить от таких полей их значения проще простого: ?Entry1{PROP:ScreenText} или CONTENS(?Entry1) или {PROP:Value} или {PROP:Use}.
AnDS писал(а):UPD. что-то PROP:VALUE возвращает формат поля. Да и PROP:USE что-то не то... Вернее то же самое...:(
Хмм.. Все нормально работает - оба свойства возвращают содержимое контролов. Работают для обеих видов - как с USE-переменной, так и без нее.
AnDS писал(а):При каком условии, на руками созданном ENTRY, проходят события EVENT:Accepted, EVENT:Selected?
Вот NewSelection проходит, когда IMM свойство есть. Это событие вижу. А Accepted И Selected не вижу.
Все контролы созданные с помощью CREATE работают абсолютно так-же, как и обычные контролы, "нарисованные" в дизайнере! И потом, что значит "Accepted И Selected не вижу"? Где не видишь?
В обычном коде все прекрасно обрабатывается:

Код: Выделить всё

window  WINDOW('Тест'),AT(,,300,150),CENTER,IMM,SYSTEM,GRAY,DOUBLE,AUTO,MDI
  END

?Entry1  EQUATE(100)
?Entry2  EQUATE(101)
?Ok  EQUATE(102)
?Cancel  EQUATE(103)

  OPEN(Window)

  CREATE(?Entry1,CREATE:entry)
  SETPOSITION(?Entry1,x1,y1,w1,h1)
  ?Entry1{PROP:Text} = '@n15`2'
  UNHIDE(?Entry1)

  CREATE(?Entry2,CREATE:entry)
  SETPOSITION(?Entry2,x2,y2,w2,h2)
  ?Entry2{PROP:Text} = '@s255'
  UNHIDE(?Entry2)

  CREATE(?Ok,CREATE:button)
  SETPOSITION(?Ok,x3,y3,w3,h3)
  ?Ok{PROP:Text} = 'Сохранить'
  UNHIDE(?Ok)

  CREATE(?Cancel,CREATE:button)
  SETPOSITION(?Cancel,x4,y4,w4,h4)
  ?Cancel{PROP:Text} = 'Отменить'
  ?Cancel{PROP:Std} = STD:Close
  UNHIDE(?Cancel)

  ACCEPT
    CASE FIELD()
    OF ?Entry1
         CASE EVENT()
         OF EVENT:Selected
              Message('EVENT:Selected','?Entry1')
         OF EVENT:Accepted
              Message('EVENT:Accepted','?Entry1')
         END
    OF ?Entry2
         CASE EVENT()
         OF EVENT:Selected
              Message('EVENT:Selected','?Entry2')
         OF EVENT:Accepted
              Message('EVENT:Accepted','?Entry2')
         END
    OF ?Ok
         IF EVENT() = EVENT:Accepted
             Message(Contens(?Entry1) &'|'& Contens(?Entry2))
             Break
         END
    END
  END
Все прекрасно работает на C63.9054!

Re: Указатели, динамическое создание переменных и т.п.

Добавлено: 18 Декабрь 2007, 9:21
AnDS
Олег писал(а):Да, в C63 изменили немного Evaluate-блок и перевели его на "классовую" модель - теперь с ним приходится работать немного по другому. И если раньше для получения имени BIND-переменной достаточно было вызвать одну функцию RTL, то теперь для этого надо использовать небольшой код с вызовом некоторых методов классов Evaluate-блока.
А как теперь надо вызывать эти методы? Пример какой-нибудь можешь привести?
Олег писал(а):
AnDS писал(а):При каком условии, на руками созданном ENTRY, проходят события EVENT:Accepted, EVENT:Selected?
Вот NewSelection проходит, когда IMM свойство есть. Это событие вижу. А Accepted И Selected не вижу.
Все контролы созданные с помощью CREATE работают абсолютно так-же, как и обычные контролы, "нарисованные" в дизайнере! И потом, что значит "Accepted И Selected не вижу"? Где не видишь?
Мой код выглядит приблизительно так:

Код: Выделить всё

window  WINDOW('Тест'),AT(,,300,150),CENTER,IMM,SYSTEM,GRAY,DOUBLE,AUTO,MDI
  END

  OPEN(Window)

  тут CREATEы всякие и установки PROPов

  loop
    ACCEPT
      loc:field= FIELD()
      loc:event= EVENT()
      BREAK
    END

   CASE loc:event
   OF EVENT:Selected
              Message('EVENT:Selected',loc:field)
   OF EVENT:Accepted
              Message('EVENT:Accepted',loc:field)
   OF EVENT:NewSelection
              Message('EVENT:NewSelection',loc:field)
   END
  end
Для ENTRY-полей работает почему-то только событие NewSelection.

Подозреваю, что при создании/установке свойств для ENTRY что-то намудрил.

Добавлено: 18 Декабрь 2007, 9:36
AnDS
вот как я создаю ENTRY:
a#=create(WQ:id,create:entry,WQ:parent)

вот какие пропы устанавливаю у ENTRY:

prop:TEXT
prop:AT
prop:FLAT
prop:FONT
prop:IMM
prop:OVR
prop:RIGHT
prop:USE
prop:USE,2

вот именно в таком порядке устанавливаются.
никакого криминала нет, вроде бы?

Добавлено: 18 Декабрь 2007, 15:02
Олег
Что касается определения адреса BIND-переменной, то код достаточно обьемный за счет необходимости обьявления интерфейсов некоторых классов Evaluate-блока RTL Клариона. Здесь его не очень удобно писать - если есть желание, то я могу выложить его в письме в рассылке ClaList?

Что до создания контролов и отработки сообщений по ним - было-бы неплохо получить код создания хотя-бы одного твоего контрола - тогда можно будет проверить это реально. Возможно у тебя проблемы с идентификацией контрола и feq-номера.
Кстати, я использую другую форму создания контролов, с явным заданием feq-номера - это, имхо, предоставляет бОльший контроль разработчику. И еще - ты используешь явную привязку к родителю всегда? Даже в случае создания отдельного контрола вне групп?

Добавлено: 18 Декабрь 2007, 16:22
AnDS
Олег писал(а):если есть желание, то я могу выложить его в письме в рассылке ClaList?
Есть желание. А можно продублировать еще и в личную почту?
Олег писал(а): Что до создания контролов и отработки сообщений по ним - было-бы неплохо получить код создания хотя-бы одного твоего контрола -
Ммм... я попробую выдрать... соберу и в эту ветку отдельным сообщением.
Олег писал(а): тогда можно будет проверить это реально. Возможно у тебя проблемы с идентификацией контрола и feq-номера.
Гм. Ну да. Возможно.
только я внутри accept-цикла запоминаю номер конрола и сразу вываливаюсь из него (из accept-а).

О! Кстати, а может новый accept (на следующем витке loop) чистит события?
Олег писал(а): Кстати, я использую другую форму создания контролов, с явным заданием feq-номера - это, имхо, предоставляет бОльший контроль разработчику.
Так и я вроде явно задаю. Или... ты что считаешь явным заданием?
переменная a# -- только для контроля - "а создался ли элемент"?
Олег писал(а): И еще - ты используешь явную привязку к родителю всегда? Даже в случае создания отдельного контрола вне групп?
Ну, если родитель = 0, то ничего ведь страшного нет?

Добавлено: 18 Декабрь 2007, 16:59
Олег
AnDS писал(а):Есть желание. А можно продублировать еще и в личную почту?
Без проблем.
AnDS писал(а):Ммм... я попробую выдрать... соберу и в эту ветку отдельным сообщением.
Ты не понял - не нужен полный код процедуры. Только пару строк кода создания контрола.
AnDS писал(а):Так и я вроде явно задаю. Или... ты что считаешь явным заданием? переменная a# -- только для контроля - "а создался ли элемент"?
Сорри, я посмотрел на форму вызова (с получением a#) и не обратил внимания на явно заданный первый параметр. Надеюсь, в этом параметре перед вызовом Create уже содержится уникальный номер контрола?
И еще, только сейчас обратил внимание - зачем ты задаешь контролу новый feq-номер свойством {PROP:Use,2}?!

Добавлено: 19 Декабрь 2007, 9:28
AnDS
Олег писал(а):
AnDS писал(а):Ммм... я попробую выдрать... соберу и в эту ветку отдельным сообщением.
Ты не понял - не нужен полный код процедуры. Только пару строк кода создания контрола.
Так я вроде пример привел выше?
Там как раз пара строк.

У меня одна очередь в которой перечислены свойства контролов.
В виде:
FEQ
Тип контрола
Наименование свойства
Значение свойства

И в зависимости от содержимого полей я либо создаю, либо устанавливаю свойства.

Код: Выделить всё

       case upper(clip(keyw2))
       of 'WINDOW'

         open(QWindow)

         destroy(1,5000)
         loop pcounter#=1 to records(WinQ)
           get(WinQ,pcounter#)

           if clip(WQ:Name)='' !новый контрол
             do CreateCTL
           else
             do SetCTLProp
           end
         end
  ..............

Код: Выделить всё

CreateCTL routine
    case clip(WQ:CTRL)
    of 'WINDOW'
    of 'BUTTON'
      a#=create(WQ:id,create:button,WQ:parent)
    of 'PANEL'
      a#=create(WQ:id,create:panel,WQ:parent)
    of 'IMAGE'
      a#=create(WQ:id,create:image,WQ:parent)
    of 'PROMPT'
      a#=create(WQ:id,create:prompt,WQ:parent)
    of 'GROUP'
      a#=create(WQ:id,create:group,WQ:parent)
    of 'SHEET'
      a#=create(WQ:id,create:sheet,WQ:parent)
    of 'TAB'
      a#=create(WQ:id,create:tab,WQ:parent)
    of 'STRING'
      a#=create(WQ:id,create:sstring,WQ:parent)
    of 'ENTRY'
      a#=create(WQ:id,create:entry,WQ:parent)
    of 'CHECK'
      a#=create(WQ:id,create:check,WQ:parent)
    of 'OPTION'
      a#=create(WQ:id,create:option,WQ:parent)
    of 'RADIO'
      a#=create(WQ:id,create:radio,WQ:parent)
    end
    if clip(WQ:CTRL)<>'STRING'
      WQ:id{Prop:Text}=clip(WQ:prop)
    end
    unhide(WQ:id)

Код: Выделить всё

SetCTLProp routine
 data
prop STRING(255)
 code

    case upper(left(WQ:Name))
    of 'ACTIVE'
      if clip(WQ:Prop)='' then WQ:Prop='1'.
      WQ:id{PROP:ACTIVE}=clip(WQ:Prop)
    of 'ACCEPTALL'
      if clip(WQ:Prop)='' then WQ:Prop='1'.
      WQ:id{PROP:ACCEPTALL}=clip(WQ:Prop)
    of 'TOUCHED'
      if clip(WQ:Prop)='' then WQ:Prop='1'.
      WQ:id{PROP:TOUCHED}=clip(WQ:Prop)
    of 'TEXT'
      WQ:id{PROP:TEXT}=clip(WQ:Prop)
    of 'FORMAT'
      WQ:id{PROP:FORMAT}=clip(WQ:Prop)
    of 'USE'
      UQ:id=WQ:id
      UQ:Use=clip(WQ:Prop)
      UQ:CTRL=clip(WQ:CTRL)
      add(UseQ,+UQ:Use)
      case upper(clip(WQ:CTRL))
      of 'ENTRY' OROF 'STRING' OROF 'CHECK'
        VAR:id=WQ:id
        get(VarNamesQue,+VAR:id)
        if ~errorcode() then
          WQ:id{PROP:USE}=VarData[VAR:num].VarStr
          WQ:id{PROP:USE,2}=WQ:id
        end
      end

    of 'VALUE'
      case upper(clip(WQ:CTRL))
      of 'RADIO'
        WQ:id{PROP:VALUE}=clip(WQ:Prop)
      OF 'CHECK'
        free(ParamsQ)
        a#=Parse(ParamsQ,clip(WQ:Prop))
        loop pq#=1 to 2
          if ~errorcode() and clip(ParamsQ.VName)<>'' then
            WQ:id{PROP:VALUE,pq#}=clip(ParamsQ.VName)
          end
        end
      end
    of 'AT'
      free(ParamsQ)
      a#=Parse(ParamsQ,clip(WQ:Prop))
      loop pq#=1 to 4
        get(ParamsQ,pq#)
        if ~errorcode() and clip(ParamsQ.VName)<>'' then
          WQ:id{PROP:at,pq#}=clip(ParamsQ.VName)
        end
      end

Олег писал(а): Сорри, я посмотрел на форму вызова (с получением a#) и не обратил внимания на явно заданный первый параметр. Надеюсь, в этом параметре перед вызовом Create уже содержится уникальный номер контрола?
Ну да, уникальный. Должен быть.
Олег писал(а): И еще, только сейчас обратил внимание - зачем ты задаешь контролу новый feq-номер свойством {PROP:Use,2}?!
Это следы экспериментов. Когда нижеуказанная конструкция не отрабатывала EVENT:accepted
можно убрать -- ничего не изменяется

Код: Выделить всё


где-то далеко и высоко начинается глобальный цикл...
.......
потом case по выполняемым командам... :
.......
     of 'ACCEPT'
         accept
           loc:keycode=keycode()
           loc:keycode_name=GetNameKeycode(loc:keycode)
           loc:event_num=event()
           loc:field_num=field()
           loc:event_name=GetNameEquate(loc:event_num,'EVENT')
           sort(UseQ,+UQ:id)
           UQ:id=loc:field_num
           get(UseQ,+UQ:id)
           if ~errorcode() then
             loc:field_name=UQ:Use
           else
             loc:field_name=''
           end
           sort(UseQ,+UQ:Use)
           if loc:field_num then ! это тоже след экспериментов -- этот if не нужен
             update(loc:field_num)
           end
           break
         end
..... и так далее ....

где-то там, внизу, case и loop заканчиваются

Ну, вот вроде все привел.

Добавлено: 19 Декабрь 2007, 17:19
Олег
Вот простейший тест, который, насколько я понял, реализует твой подход. Все нормально работает - и события отлавливаются и поля.
Я бы тебе рекомендовал постепенно усложнять его до функционала твоей задачи - сразу увидишь, когда перестанет работать.
По крайней мере, на нем легко можно дополнить блок создания контролов теми свойствами, которые необходимы и сразу станет понятно - причина в них или надо "копать" в другом месте.
Проверять, естественно, лучше всего на чистом "ручном" коде без использования APP и шаблонов.

Код: Выделить всё

window WINDOW('Test'),AT(,,260,100),FONT('Arial',8,,,CHARSET:CYRILLIC),CENTER,IMM,SYSTEM,GRAY,DOUBLE, |
         AUTO
     END

ctrlque  queue,pre(ctrl)
id         long
type       long
text       string(20)
x          long
y          long
w          long
h          long
         .

  Code

  ctrl:id   = 100
  ctrl:type = create:entry
  ctrl:text = '@n15`2'
  ctrl:x    = 10; ctrl:y = 10; ctrl:w = 50; ctrl:h = 10
  add(ctrlque)

  ctrl:id   = 101
  ctrl:type = create:entry
  ctrl:text = '@n_4'
  ctrl:x    = 70; ctrl:y = 10; ctrl:w = 30; ctrl:h = 10
  add(ctrlque)

  ctrl:id   = 102
  ctrl:type = create:button
  ctrl:text = 'button1'
  ctrl:x    = 10; ctrl:y = 50; ctrl:w = 60; ctrl:h = 14
  add(ctrlque)

  ctrl:id   = 103
  ctrl:type = create:button
  ctrl:text = 'button2'
  ctrl:x    = 100; ctrl:y = 50; ctrl:w = 60; ctrl:h = 14
  add(ctrlque)

  open(window)
  sort(ctrlque,+ctrl:id)
  loop ndx# = 1 to records(ctrlque)
    get(ctrlque,ndx#)
    create(ctrl:id,ctrl:type)
    ctrl:id{prop:text} = ctrl:text
    setposition(ctrl:id,ctrl:x,ctrl:y,ctrl:w,ctrl:h)
    unhide(ctrl:id)
  .

  loop
    event# = 0; field# = 0
    accept
      event# = event()
      field# = field()
      break
    .
    if (event# = event:closewindow) or (event# = event:closedown) then break.
    if event# and field#
       ctrl:id = field#; get(ctrlque,+ctrl:id)
       case event#
       of event:selected
       of event:accepted
          if field# = 103 then break.
  . .  .

Добавлено: 20 Декабрь 2007, 8:56
AnDS
Олег писал(а):Вот простейший тест, который, насколько я понял, реализует твой подход. Все нормально работает - и события отлавливаются и поля.
Так вот как раз и не работает.

Пробую ввести что-нибудь в одно из полей и нажать TAB.
Должен при этом ACCEPTED проходить?

Сделал отдельный проект. Без APP.

Добавлено: 20 Декабрь 2007, 23:49
Олег
При выходе из поля независимо от того, было выполнено изменение в нем или нет, всегда первым посылается событие EVENT:Selecting. И лишь после этого посылается событие EVENT:Accepted (если были изменения в поле) и событие EVENT:Seleted. Так вот, после посылки события EVENT:Selecting мы "вываливаемся" из ACCEPT-цикла и последующие события EVENT:Accepted и EVENT:Selected уже не посылаются этим ACCEPT-ом. Ну а следующий ACCEPT на втором шаге цикла само-собой ничего не знает о том, что произошло в предыдущем ACCEPT-е!
Поэтому при таком алгоритме ты никогда не получишь от полей ввода событий EVENT:Accepted и EVENT:Selected. Так что, или всегда крутись в одном ACCEPT-цикле или каким-либо образом работай только с событием EVENT:Selecting, что, имхо, не сможет дать полную информацию о происходящем в окне!

Добавлено: 21 Декабрь 2007, 11:43
AnDS
Гм. Да, это неприятный момент.

А может как-нибудь можно получить доступ к... эээ... событиям ACCEPT? что-то типа стека/очереди... какие-нибудь недокументированные функции?