Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Win32 API | GDI. Как определить, что пользователь кликнул в объект (http://forum.oszone.net/showthread.php?t=68927)

XCodeR 25-07-2006 11:41 464632

Win32 API | GDI. Как определить, что пользователь кликнул в объект
 
Ищу документацию.... Гугл дал не много...

+ вопрос:
как можно определить, что на нарисованный объект(прямоугольник, линия и т.д. и т.п.) пользователь кликнул мышкой?
допустим рисовали на TCanvas

среда разработки, как всегда C++ Builder || Delphi.

LeonidPr 25-07-2006 13:36 464668

Допустим, ты рисуешь на канве формы. Хотя, это не имеет значения. Ты знаешь координаты своего объекта. Для прямоугольника достаточно знать координаты верхнего левого угла и правого нижнего. Теперь в обработчике OnMouseDown (или OnMouseUp) проверяй координаты X, Y, которые передаются в обработчик события, на то, находится ли точка с этими координатами внутри объекта или нет. Для прямоугольника это будет примерно так:
if ((X>LeftCorner.X)&&(X<RightCorner.X)&&(Y>LeftCorner.Y)&&(Y<RightCorner.Y))
{
//Сюда попадем, если точка внутри прямоугольника
};
LeftCorner и RightCorner - структуры типа POINT, содержащие координаты точек (Левого и правого углов)
Для круга проверка по формуле (X-Xc)^2+(Y-Yc)^<=R^2. Xc и Yc - координаты центра круга. Правда, для сложных фигур (типа замкнутых фигур, состоящих из кривых Безье) такую проверку будет сделать сложновато.
По GDI советую читать MSDN.

XCodeR 25-07-2006 14:16 464688

LeonidPr
спасибо, но в моем случае "рисованных" объектов будет большое количество. и проверка таким образом может занять драгоценное время.
Цитата:

По GDI советую читать MSDN.
что и делаю...

XPEHOMETP 25-07-2006 21:27 464834

По GDI есть книжечка: Фень Юань, "Программирование графики для Windows". Есть электронная версия русского перевода, не помню уже, где скачал.

XCodeR 26-07-2006 00:29 464886

XPEHOMETP
а выложить куда - нибудь или отправить на почту , можешь?

XPEHOMETP 27-07-2006 23:54 465673

XCodeR
Цитата:

а выложить куда - нибудь или отправить на почту , можешь?
Муторно из дома по модему посылать, файл большой. Поищи в Гугле, по названию, я так нашел, где скачать. Если не получится, когда буду на работе, то выложу или пришлю.

XCodeR 28-07-2006 11:41 465771

XPEHOMETP
ок. посмотрю(поищу)...

hasherfrog 28-07-2006 16:30 465899

Сабж - это на самом деле нетривиальная задача. Я решал её уже несколько раз, каждый раз - заново. Всё очень сильно зависит от реализации.

1. Кто определяет "попал-не попал?" Если каждый объект сам для себя - это одно. Если некто вроде "менеджера объектов" - это другое.
2. Алгоритмы вычисления "попади в прямоугольник" сильно отличаются от алгоритмов "кликни в полилинию". ОЧЕНЬ сильно.

XCodeR 28-07-2006 23:51 466047

hasherfrog
Может быть, если я опишу задачу, станет понтянее, что я хочу.

Рисуется несколько объектов(по форме напоминающих квадрат), координаты которых берутся из БД. Между объектами может быть проведена линия.
Так вот у каждого нарисованного объекта и возможной между ними линии есть определенные свойства, которые пользователь может редактировать.
=> что отредактировать свойства объекта пользователь кликает на объект.
Итого задача - определить на какой объект(линию) кликнул пользователь.

На данный момент решено(еще до создания темы) при помощи проверки попадает ли координаты "клика" в "прямоугольник координат" объекта.(для линии пока не решал, но проблем вроде как возникнуть не должно, формулы линии(=прямой) благо вывели задолго до нас)

Но так как объектов может быть очень много боюсь, что это скажется на работоспособности.

Цитата:

Алгоритмы вычисления "попади в прямоугольник" сильно отличаются от алгоритмов "кликни в полилинию". ОЧЕНЬ сильно.
впринципе можно решить при помощи формул ограничивающих многоугольник прямых.... если "полилиния" - многоугольник.
с кривыми Безье, как уже отмечалось в этой теме - все намного сложнее.

hasherfrog 29-07-2006 01:04 466061

Почему я упомянул про 1. Давным-давно (лет двенадцать назад) я решал такую задачу. Есть карта Москвы, улицы - полилинии, дома даны в виде полигонов (не путать с полилинией), у каждого свой Id, координаты в базе. Надо определить, куда попал пользователь мышой, выдать подпись "Улица/дом". Очевидно, что объектов очень много, поэтому было использована технология (громко сказан :]) нескольких "окон".

Ещё до вывода, до отрисовки, вообще "до", в самом формировании базы, все дома (точнее, прямоугольники, куда входили полигоны домов) отфильтровывались по оси Y. У каждого дома, дополнительно, в соответствии с его ID, хранился прямоугольник boundaries, ы который "вписывался дом". При выводе на экран бинарным деревом отфильтровывались Id тех ненужных домов, которые оказывались вне экранного окна по Y (min/max окна). Потом отфильтровывались (емнип, тупым перебором) по данным прямоугольников boundaries дома оставшиеся - теперь выкидывались те, кто оказался вне экрана по оси X. Из оставшихся формировался список Idэшек, который хранился до тех пор, пока пользователь не сменит масштабирование/не проскроллит экран. По этому списку дома отрисовывались, если надо было перерисовать экран.

Когда пользователь кликал мышой, координата пересчитывалась в реальные. Этот XY использовался для отфильтровки из "хранимого" Id-списка всех тех "близлежащих" домов, прямоугольные boundaries которых содержали в себе тыкнутую точку. Потом начиналось самое дурацкое - определение "попал-не-попал" для полигона и точки. Сейчас я (вот прямо сейчас :] ага. Нет уж, когда время будет и когда доки дпишу китайцам) ищу/пишу нормальный алгоритм того же самого, потому что старые (подсчёт и анализ количества точек пересечений всех сторон полигона с горизонтальной осью x=x_точки_тыка слева от y_точки_тыка) меня перестал устраивать. Правда, сегодняшняя задача у меня много проще, нет такого количества данных, примитивный coreldraw :]

Когда-то (это уже лет пять назад) я писал в AutoCAD, с использованием ихнего :] API, там было всё круто насчёт определения очки пересечения отрезков - это было вшито в библиотеки и работало как электровеник. Но во реализация и алгоритм их мне не известен, поэтому у меня свой :]

***

Что касается вопроса 2. Для линий всё немного проще. Вы (ну в смысле я) делаете небольшой виртуальный крестик из двух отрезков, превращая точку в плюсик. И у двух отрезков данного плюсика ищете точки пересечения с отрезками из заданной полилинии (с минимальной двухуровневой оптимизацией. основанной на тех же "окнах": окно всей полилинии vs boundaries крестика и окна отрезков крестика vs каждый отрезок полилинии при поиске точки тересечения). Если пересечение есть, считаете, что пользватель "попал". Можно брать не крестик, а квадратик (если мышиный курсор у Вас не квадратик, а стрелочка, лучше брать всё-таки "плюсик-крестик").

***


Вот по поводу именно GDI - я не знаю. У меня всегда расчёт шёл в double-числах, может, для integer'ов можно как-то всё ещё прооптимизировать...

бинарным деревом :D чё сказал?

XCodeR 29-07-2006 12:32 466111

hasherfrog
случаем карта была не GWXMap?

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

Цитата:

У меня всегда расчёт шёл в double-числах, может, для integer'ов можно как-то всё ещё прооптимизировать...
сдается мне, что нет.

hasherfrog 29-07-2006 14:48 466143

Не знаю про GWXMap :-/
Я тогда вот тут http://www.allmaps.ru/about/ работал.
А та прога ещё под ДОС заточена была :-)

pva 30-07-2006 22:23 466449

Если памяти не жалко, можно составить карту, в которой каждый пиксель - ID объекта. Проверка занимает 1 операцию. Если на экране одновременно не более 255 объектов, а экран 1280x1024, то карта примерно 1.5 МБ займёт. Для отрисовка можно использовать функции GDI.


Время: 20:12.

Время: 20:12.
© OSzone.net 2001-