OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 19 Март, 2024 07:20

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 13 ] 
Автор Сообщение
СообщениеДобавлено: Среда, 21 Июнь, 2017 22:55 
Аватара пользователя

Зарегистрирован: Среда, 22 Апрель, 2015 23:51
Сообщения: 248
Откуда: г. Рига, Латвийская ССР
Широко известна схема цикла «линейный поиск», которая имеет следующий вид:
Код:
Взять_первую_ситуацию;
WHILE ~ситуации_закончились & ~искомое_найдено DO Взять_следующую_ситуацию END;
IF ~ситуации_закончились THEN (* Искомое найдено *) END

При работе над проектом Oberon Vision (аналог Turbo Vision — библиотеки для создания псевдографического интерфейса пользователя) оказалось, что элементы меню, окна и прочее удобно организовывать в двунаправленные кольца (то есть двунаправленные списки, в которых первый и последний элементы также взаимно связаны).
Код:
TYPE Control* = POINTER TO ControlDesc;
  ControlDesc* = RECORD
    parent*: Control; (* Указатель на непосредственный родительский элемент *)
    children*: Control; (* Указатель на первый дочерний элемент *)
    prev*, next*: Control; (* Указатели на братские элементы для организации двунаправленного кольца *)
    caption*: ARRAY 256 OF CHAR
  END;

Одна из подзадач заключается в нахождении среди братских элементов (sibling elements), включая и сам элемент, элемента с определённым свойством. Например, необходимо найти элемент меню, у которого внутри строкового поля caption была бы определённая буква, перед которой стоит символ "&" (элемент "Save &As..." должен отреагировать на букву "A"). Это нужно для того, чтобы при нажатии на ту или иную клавишу, срабатывал соответствующий элемент меню.

У меня получился такой код:
Код:
PROCEDURE MenuKeyDown*(c: Control; key: G.Key);
VAR p: Control; (* Поиск осуществляется среди братских элементов 'c', включая его самого. *)
  br: Control; (* Элемент-барьер *)
  found: BOOLEAN;
BEGIN
  ...
  p := c.prev;
  br := p;
  REPEAT
    p := p.next;
    found := MenuHotkey(p(Menu), CHR(key.sym))
  UNTIL found OR (p = br);
  IF found THEN
    p.do.click(p)
  END;
  ...
END MenuKeyDown;

Как видите, данный код не соответствует вышеупомянутой схеме линейного поиска. Как решить данную задачу более правильно?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 21 Июнь, 2017 23:55 

Зарегистрирован: Пятница, 20 Июль, 2007 17:26
Сообщения: 710
Откуда: Псков
Не имея ввиду "более правильное", предложение такое - проверить начальный элемент на наличие свойства, а, уж в случае его отсутствия, переходить на обход братьев по схеме линейного поиска.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 22 Июнь, 2017 05:36 
Аватара пользователя

Зарегистрирован: Четверг, 08 Октябрь, 2009 15:00
Сообщения: 3774
Вот так должно сработать и это ближе к схеме
Код:
 
  p := c;
  WHILE  (p # NIL) & ~ MenuHotkey(p(Menu), CHR(key.sym)) DO
    IF p.next # с THEN p := p.next ELSE p := NIL END
  END;
  IF p # NIL THEN p.do.click(p) END;
  ...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 22 Июнь, 2017 13:03 
Аватара пользователя

Зарегистрирован: Среда, 22 Апрель, 2015 23:51
Сообщения: 248
Откуда: г. Рига, Латвийская ССР
Иван Денисов писал(а):
Вот так должно сработать и это ближе к схеме

Отлично! То, что надо.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 22 Июнь, 2017 16:59 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Чего-то не вижу? Почему не просто

WHILE (p.next # c) ...
p := p.next
END;
IF p.next # c ...

?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 22 Июнь, 2017 17:09 
Аватара пользователя

Зарегистрирован: Четверг, 08 Октябрь, 2009 15:00
Сообщения: 3774
Info21 писал(а):
Чего-то не вижу? Почему не просто

WHILE (p.next # c) ...
p := p.next
END;
IF p.next # c ...

?

Так не получится "защучить" последний элемент при условии выполнения проверки на нем.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 22 Июнь, 2017 17:44 

Зарегистрирован: Пятница, 20 Июль, 2007 17:26
Сообщения: 710
Откуда: Псков
Добавлю, что в случае цепочки из одного "закольцованного" элемента, тело цикла WHILE (p.next # c) вообще не выполнится.
Кстати тут "двунаправленность" и даже "закольцованность" принципиально ничего кардинально усложняющего по сравнению с линейным списком (строкой, файлом и т.д) не привносит. Просто везде надо определить соответствующий рассматриваемому случаю EOF.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 22 Июнь, 2017 20:40 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Как вариант:

Код:
p := first.next;
WHILE (p # first) & ~условие_поиска DO
  p := p.next
END;
IF условие_поиска THEN

END


Относительно схемы ЛП меняется условие в IF.
Цикл такой же, инвариант такой же.
Другая инициализация цикла (принимаем за начальный не первый, а второй элемент, а первый - за конец. Мы вольны в кольцевом списке, всё элементы эквивалентны. Главное, что не имеем права начать с того же, которым заканчиваем.)

Но в классическом ЛП end => UNDEFINED(условие_поиска), поэтому проверка по ~end.
А тут E p end & условие_поиска (существует на множестве всех выполнений программы).
И A p DEFINED(условие_поиска).
Отсюда другой IF в конце.

Ы?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 07 Июль, 2017 18:56 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Отвечаю здесь на viewtopic.php?p=101253#p101253

Цитата:
Вот здесь viewtopic.php?p=101164#p101164 приведено решение с грубой ошибкой. Поиск начинается со второго элемента, но если элемент один?


Так всё нормально будет, если он там один! Цикл не выполнится ни разу - и будет сразу проверка завершающего элемента (первого).
Другой вопрос, что это расчитано на непустой список. Так что придётся держать в нём "пустышку".

Цитата:
Само собой, я тогда тоже задумался над примером. И синтезировал (быстро, но не мгновенно!) рабочий вариант.
Он короче варианта Ивана Денисова.


Не томите ) Давайте вариант сюда.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 08 Июль, 2017 08:22 

Зарегистрирован: Пятница, 24 Апрель, 2009 16:28
Сообщения: 563
Откуда: Москва
На этой площадке не веду такую деятельность.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 08 Июль, 2017 13:25 
Аватара пользователя

Зарегистрирован: Четверг, 08 Октябрь, 2009 15:00
Сообщения: 3774
Peter Almazov писал(а):
На этой площадке не веду такую деятельность.

А я придумал вариант еще короче вашего! ;)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 11 Июль, 2017 07:42 

Зарегистрирован: Суббота, 16 Февраль, 2008 07:58
Сообщения: 358
Откуда: Россия, Стерлитамак
Иван Денисов писал(а):
Peter Almazov писал(а):
На этой площадке не веду такую деятельность.

А я придумал вариант еще короче вашего! ;)

Чё, теперь в моде у кого короче ) ?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 13 Июль, 2017 14:14 
Аватара пользователя

Зарегистрирован: Среда, 22 Апрель, 2015 23:51
Сообщения: 248
Откуда: г. Рига, Латвийская ССР
Вот как вариант т. Денисова выглядит в рабочем коде:
Код:
  ...
ELSIF (x # 0) & (c.children # NIL) THEN
  p := c.children; br := p;
  WHILE (p # NIL) &
    ~((p.x <= x) & (x < p.x + p.w) &
      (p.y <= y) & (y < p.y + p.h)) DO
    IF p.next = br THEN p := NIL ELSE p := p.next END
  END;
  IF (p # NIL) & (p.do.mouseDown # NIL) THEN
    p.do.mouseDown(p, x - p.x, y - p.y, button)
  END
END


Вполне годится. Остальные варианты прочёл только сейчас.
Если использовать вариант без IF'а внутри WHILE'а, то, пожалуй, имеет смысл выделить условие проверки координат в отдельную процедуру. Ещё важно отметить, что перебирать элементы кольца в данной задаче необходимо начиная с первого, то есть с c.children. В этом случае, когда пользователь нажимает мышкой на место на экране, где находятся сразу несколько окнон, то событие будет направлено окну, находящемуся впереди.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 13 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB