Графика и события

Модератор: Absurd

Ответить
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

Всю жизнь рисовал прямоугольники методом paint на панели.

Для того, чтобы добраться потом до них - нужно было на панель навешивать MouseListener и в зависимости от того, на какую область была нажата мышка - делать обьект "актиным".

Для того, чтобы перетащить прямоугольник - нужно было изменить его местоположение и сделать repaint панели.

Думаю все с таким знакомы.


Последние две недели обрабатываю другой подход:

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

class DraggableComponent extends JComponent implements MouseListener, MouseMotionListener

JPanel.add(new DraggableComponent());
если поставить свой Layout, который не будет пытаться автоматически расставлять обьекты - всё прекрасно получается.

Каждый обьект таскает сам себя, на обьекте можно нарисовать рожицу, али ещё чего, в методе paintComponent и всё отлично выглядит.

Прекрасная масштабируемость (добавляешь новый элемент и он сам знает, что с собой делать), не нужно добавлять горы мусора в метод paint той самой панели.


Проблемы возникают же во время взаимосвязи таких обьектов.
Например, если два прямоугольника нужно соединить линией ... Эту линию нужно тоже сделать JComponent и добавить на панель.
В общем-то не сложно.

Но изменения положения прямоугольника должны влиять на положение линии - уже сложнее, но всё ещё реально.

А как насчёт выбрать пару прямоугольников и перетащить их вместе?
Если прямоугольник отвечает только за себя - то нужно опять же обращаться к панели, чтобы узнать, выбраны ли другие обьекты.

И вот уже есть ограничение:
Если сначала DraggableComponent можно было добавить на любую стандартную панель - то теперь это должна быть уже специфическая панель (чего бы не хотелось).

Нет, ну конечно же можно всё это реализовать (и большинство я уже сделал), но вот в чём вопрос:

А нужно ли это?


Действительно ли я получаю достаточно преимуществ при этом?
И какие ещё есть потенциальные недостатки такого подхода?

Преимущества я вижу:

1. В новом подходе работа идёт с "векторной" графикой и, мне кажется, это удобнее при необходимости связи "Графика & события".

2. Кроме того, идёт работа по слоям (ZOrder у любого контейнера) и получается намного проще реализовывать перекрытия обьектов.

3. Чтобы скрыть обьект - достаточно удалить его с панели (или же setVisible(false), только это не всегда отключает обработчик событий), а при необходимости добавить .


Но есть и вышеперечисленные недостатки, которых, по моему, меньше.

Хотелось бы услышать мнение уважаемого сообщества!
Может кто-то уже мучался и знает разные "За" и "Против" ?!

А может уже где-то есть и готовые библиотеки для подобных изощрений?
Искал, не нашел ничего подходящего, неужели никто таким не пользвуется? Если таки нет - значит, наверное, есть на то причины!..
Аватара пользователя
AiK
Сообщения: 2287
Зарегистрирован: 13 фев 2004, 18:14
Откуда: СПб
Контактная информация:

Чего-то я тебя не понимаю. Я вот ООП почти не знаю, но чуствую, что ты где-то накосячил. Собственно знать о других объектах может только метод класса, т.к. статический метод. А зачем ты делал перерисовку (или листенер)на уровне класса спрашивается?
И панель тебе не нужна. Нужно только отлавливать нажатие кнопки shift. Типа если объект выделили, но с нажатием shift'а, то при уходе мыши за границы объекта мы не считаем, что выделение снято. В итоге все объекты будут ездить параллельно друг другу.
Теперь если ты хочешь прилепить отрезок к прямоугольнику, чтобы при изменении положения прямоугольника отрезок тоже менял положение того конца, который склеен с прямоугольником.
Делаешь два субкласса от DraggableComponent. Один будет для ведомых объектов, другой для ведущих. Ведомые знают только про себя, а ведущие - про всех ведомых. У ведомых два метода connectToDC и disconnectfromDC. Если тащат за ведомый компонент, то он либо прицепляется к ведущему либо отцепляется от него, в зависимости от своего положения. Если тащат за ведущий, то он оповещает всех его ведомых о новых координатах их connectionPoint. Если немного подумать, то отдельный субкласс для ведомых можно и не делать, типа если контейнер connectedDCs пуст, то ведомый, если не пуст - то ведущий.
В общем, извини за сумбур - всё на уровне идеи и тщательно не продумывалось.
Даже самый дурацкий замысел можно воплотить мастерски
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

AiK, привет! :-)

Я, конечно же, понимаю, что мои размышления для человека, который никогда не пытался сделать MyComponent extends JComponent могут показаться слегка размытыми ..
Но твой же ответ я бы занёс в книгу перлов ))

Нет, ну если бы у меня самого не было чувства, что я где-то накосячил, я бы не спрашивал тут совета, так что в этом мы с тобой сходимся!
AiK писал(а):знать о других объектах может только метод класса, т.к. статический метод
Читал я эту строку множество раз, много думал ... Так и не понял :lol:
AiK писал(а):И панель тебе не нужна.
Ага, и окошки мне не нужны, и нафига мне вообще эта Java сдалась? )))

Всё то, что ты написал о самой идее - правильно!
Вот только вопрос был немного в другом.

http://home.in.tum.de/~skrypnyo/Java/
Тут лежит мой код. Правда без соединений между эелементами, но сам DraggableLabel работает на ура.
Апплет (applet.html) скомпилирован под Java 1.5

AiK писал(а):А зачем ты делал перерисовку (или листенер)на уровне класса спрашивается?
Это и есть мой главный вопрос!
Стоит ли делать это на уровне класса, или же достаточно сделать это на уровне Панели (без которой, кстати говоря, уж никак не обойтись, поскольку мои обьекты должны ведь где-то находится).

Есть два варианта:

1. Мои элементы - графика!

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

2. Мои элементы - extends JComponent

Каждый элемент ловит события мышки самостоятельно и сам рисует себя.

-----

Во втором случае снимается нагрузка с Панели, но усложняется связь с другими элементами (нужно обращаться к Панели).

В первом случае обращение ко всем элементам идёт из Панели, но вся нагрузка на обработку событий и прорисовку лежит опять же таки на ней.

Какой вариант лучше?
В этом и заключался мой вопрос.
Аватара пользователя
AiK
Сообщения: 2287
Зарегистрирован: 13 фев 2004, 18:14
Откуда: СПб
Контактная информация:

Читал я эту строку множество раз, много думал ... Так и не понял
Там т.е. читать надо вместо т.к. Будет понятнее :)
Смотри. Например, ты хочешь посчитать, сколько объектов класса ты создал. Конечно можно где-то в левом месте держать счётчик, а можно его прямо в классе реализовать. Для этого тебе нужно объявить переменную класса, т.е. static. Насколько я помню, доступ к этой переменной, по крайней мере на запись, ты можешь получить только в статическом же методе, т.е. методе класса.
Таким же макаром, ты можешь разместить в классе статический контейнер, который будет содержать ссылки (я знаю, что жабе ссылок нет, но мне так удобнее именовать :) ) на все объекты класса. Соответственно, когда тебе нужно подвигать объекты, то ты пробегаешь по контейнеру и у каждого [нужного] объекта вызываешь его метод moveTo. Как вариант, ты делаешь этот контейнер не static свойством, и соответственно там хранятся только объекты связанные с данным экземпляром класса.
Какой вариант лучше?
Ты ж сам писал, что хочешь на любой панели рисовать :)
Тут лежит мой код. Правда без соединений между эелементами, но сам DraggableLabel работает на ура.
Апплет (applet.html) скомпилирован под Java 1.5
Апплет не работает. Сам код гляну позже, сейчас времени нет.
Даже самый дурацкий замысел можно воплотить мастерски
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

AiK, дурак, виноват, исправлюсь ;-)

Об использовании статических обьектов/методов для работы со всеми инстанциями класса действительно не подумал.

Спасибо большое!
Аватара пользователя
AiK
Сообщения: 2287
Зарегистрирован: 13 фев 2004, 18:14
Откуда: СПб
Контактная информация:

Если честно, то я немного не это имел ввиду :) Я думал, что ты так и реализовал/хотел реализовать перемещения всех объектов одним статическим методом класса или же в другом классе (панели). Так в принципе тоже можно.
Но, как вариант, это всё можно сделать не на уровне класса, а на уровне экземпляра объекта. Всё, что для этого нужно, это в экземляре класса знать все зависимые объекты. И, соответственно, при изменении своего положения такой объект должен оповестить об этом событии все заинтересованные объекты. Но, панель для осуществления этой связи не нужна. Не, можно конечно её и для этих целей использовать, но это как-то некошерно :)
Даже самый дурацкий замысел можно воплотить мастерски
Ответить