Обработка событий мыши в моделях AnyLogic

AnyLogic – среда имитационного моделирования, а не разработки ПО, и поэтому он включает в основном элементы логики моделей, оставляя разработчикам лишь базовые объекты пользовательского интерфейса

Однако визуализация и интерактивность моделей в AnyLogic – это их несомненные конкурентные преимущества. Поэтому иногда требуется не просто продемонстрировать пользователю «мультик» с изменяемым масштабом модельного времени, но и позволить ему активно влиять на происходящее в модели. Базовые элементы управления AnyLogic позволяют это сделать, но иногда требуется реализовать какой-нибудь нетривиальный способ управления моделью.

Пример такого взаимодействия с моделью – перетаскивание элементов мышью. Перетаскивание будет полезно, если:

  • Моделируется логистическая сеть, и нужно дать возможность добавлять новые и перемещать существующие распределительные центры на карте
  • Необходимо разрешить изменение плана моделируемого магазина или АЗС
  • Нужно дать пользователю возможность вручную распределять задания на перемещение паллет на складе между погрузчиками

Стандартные элементы AnyLogic не дают возможности реализовать перетаскивание. Но AnyLogic хорош тем, что позволяет расширять функциональность моделей практически бесконечно за счет программирования на языке Java.

Давайте рассмотрим, как это делается, на примере реализации перетаскивания. В нашем примере мы будем перетаскивать прямоугольник. Создадим модель и добавим прямоугольник на холст объекта Main.

С помощью стандартной функциональности AnyLogic можно обработать только событие щелчка мышью по нашему прямоугольнику. Для перетаскивания этого явно мало, так как нам нужно отследить три события:

  1. Нажатие кнопки мыши
  2. Движение мыши с нажатой кнопкой
  3. Отпускание кнопки мыши

Логика процесса перетаскивания такова:

  • При нажатии кнопки мыши на прямоугольнике поднимаем флаг isDragged (флаг – переменная типа boolean), означающий «идет перетаскивание»
  • Во время перетаскивания (то есть, если флаг поднят) двигаем прямоугольник, присваивая ему положение координат курсора
  • При отпускании кнопки мыши опускаем флаг

Для удобства создадим в модели три функции – onMouseDown, onMouseDragged и onMouseUp, которые будем вызывать при соответствующих событиях.

Итак, получаем следующую модель:

Обратите внимание, что в модель мы добавили еще две переменные – это смещения точки нажатия кнопки мыши от левого верхнего угла прямоугольника. Эти смещения мы будем использовать при движении прямоугольника, чтобы он не «прыгал» к курсору при начале перетаскивания.

Пока мы не знаем, как будут вызываться наши функции – мы лишь понимаем, что они должны вызываться при событиях, связанных с манипуляциями мыши.

Для того чтобы понять, как подойти к обработке событий, необходимо немного знать язык Java. Все содержимое окна с моделью располагается на Java-компоненте Panel. Программный доступ к этому компоненту можно получить с помощью вызова getPresentation().getPanel() из любого активного объекта AnyLogic.

Компонент Panel, как и любой Java-компонент, может содержать в себе так называемые «слушатели событий». Подробнее об обработке событий в Java можно узнать, например, здесь. Слушатель событий – это реализация некоторого интерфейса, переопределенные методы которого вызываются, когда событие происходит. Один слушатель обычно обрабатывает события нескольких типов, поэтому при создании экземпляра интерфейса слушателя нужно переопределять несколько методов. На практике нечасто нужно обрабатывать все события слушателя. Специально для таких случаев в Java есть так называемые адаптеры – реализации интерфейсов слушателей с заглушками – пустыми обработчиками всех событий. С помощью адаптеров можно реализовывать обработчики только нужных методов.

В нашем примере мы добавляем два слушателя, которые реализуем с помощью адаптеров:

  1. MouseAdapter – обрабатывает события нажатия клавиш мыши
  2. MouseMotionAdapter – обрабатывает передвижения мыши

Добавлять слушателей удобнее всего в «действии при запуске» объекта Main:

Теперь ясно, что созданные нами функции onMouseDown, onMouseDragged и onMouseUp нужно вызывать из обработчиков событий мыши – весь паззл нашей реализации складывается! Наши функции принимают по три параметра – координаты курсора и номер кнопки мыши. В этом примере номер кнопки не используется, но его можно использовать, например, для различия манипуляций правой и левой кнопкой мыши.

Код функций очень прост и соответствует логике перетаскивания:

Теперь, запустив модель убеждаемся, что перетаскивание действительно работает!

Продемонстрированную модель с перетаскиванием прямоугольника вполне можно использовать как отправную точку при реализации аналогичного поведения в реальных моделях. Кроме того, надеюсь, этот пример показал, что обрабатывать любые события пользовательского интерфейса в моделях AnyLogic не сложно. Например, так же просто реализуется и обработка событий клавиатуры.

Comments are closed.