Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.10.17;
Скачать: CL | DM;

Вниз

Создания кликуемых регионов.   Найти похожие ветки 

 
:: Joiro [unregistered] ::   (2002-06-12 13:23) [0]

Привет знатокам.

Медленно делаю свой маленький графический редактор и вот появилась нужда в одной возможности, которую никак не могу найти.

Хотелось бы сделать что-то похожее на свободно дефинируемые прозрачные регионы (они все четирёхугольные), которые расположены на форме и их можно кликнуть и вызвать действие. Можно думать о них как о регионах на картинках в HTML.

Пример - на форме картинка на которой видны кнопки или что-то ещё. Надо дать возможность кликнуть "над" этой картинкой как обычную кнопку (или вернее не совсем обычную а регирующую на все три кнопки мышы).

На данный момент использую простые Shape - Rectangle c прозрачными линиями и фоном, но это кажется не совсем эффективным способом.

Есть идеи?

Заранее спасибо.


 
MBo ©   (2002-06-12 19:29) [1]

WinSDK Help
CreateRectRgn, PtInRect(для обработки мыши) и т.п. смотрел?


 
ZiX ©   (2002-06-12 20:30) [2]

а если не прямоуголтный то CreatePolygonRgn или что то типа..
а ваще там все есть -WinSDK Help


 
.: Joiro :. ©   (2002-06-12 22:07) [3]

Окей... посмотрел в хелпе про CreateRectRgn и создал регион, но вот с PtInRect трудности... может можно попросить небольщой примерчик?

И я так понимаю это оптимальный вариант, но есть другие?


 
MBo ©   (2002-06-13 07:01) [4]

Я несколько неточно сказал - при использовании регионов надо будет PtInRegion, а PtInRect можно использовать и без регионов,
достаточно знать ограничивающий прямоугольник.


пример для регионов
list:tlist;

procedure TForm1.Button1Click(Sender: TObject);
var
hr:hrgn;
i:integer;
x1,y1,x2,y2:integer;
begin
randomize;
for i:=0 to 4 do begin
x1:=random(300)+20;
x2:=x1+random(250)+20;
y1:=random(300)+20;
y2:=y1+random(250)+20;
hr:=createrectrgn(x1,y1,x2,y2);
canvas.brush.color:=random($FFFFFF);
fillrgn(canvas.handle,hr,canvas.brush.handle);
list.add(pointer(hr));
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
list:=tlist.create;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
hr:hrgn;
r:trect;
i:integer;
begin
for i:=0 to list.count-1 do begin
hr:=hrgn(list[i]);
if PtInRegion(hr,x,y) then
Memo1.Lines.Add(inttostr(x)+":"+inttostr(y)+" лежит в регионе N "+inttostr(i));
end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
hr:hrgn;
i:integer;
begin
for i:=0 to list.count-1 do begin
hr:=hrgn(list[i]);
DeleteObject(hr);
end;
list.free;
end;


 
.: Joiro :. ©   (2002-06-13 10:47) [5]

О! Спасибо, с примером сразу легче. Немножко изменил чтобы точно видно что и где создаётся:

procedure TForm1.Button1Click(Sender: TObject);
var
hr:hrgn;
i,x1,y1,x2,y2 : Word;
begin
Randomize;
for i:=0 to 7 do begin
x1 := I*32+4;
x2 := I*32+28;
y1 := 4;
y2 := 28;
hr:=createrectrgn(x1,y1,x2,y2);
canvas.brush.color:= RGB(I*32,I*16,0);
fillrgn(canvas.handle,hr,canvas.brush.handle);
list.add(pointer(hr));
end;
end;


Но теперь появляется ещё один вопрос – как нормально реализовать идентификацию и создание нужных регионов? Я тут думал о считывании координат и кода действия из текст файла или что-то похожее и потом у каждого региона свой код и когда на него кликуют тот проверяется и есть действие. Но опять кажется, что этоможет быть не совсем оптимально, да и самому не до конца ясно, как это сделать.

Моя проблема в том, что я перешёл сразу на Delphi ни разу не работав с Паскалом и получилось так, что научился использовать верхний уровень не зная что под ним. Теперь я медленно учусь правильно программировать, так что если не трудно буду очень благодарен за примеры.


 
.: Joiro :. ©   (2002-06-13 11:32) [6]

И ещё вопрос – вот, пробую засветить один регион когда мышь над ним, но почему-то все они меняют краску. В чём дело?

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
var
hr:hrgn;
i:integer;
begin
Canvas.Pen.Mode := pmMerge;
for i:=0 to list.count-1 do begin
hr:=hrgn(list[i]);
if PtInRegion(hr,x,y) then
canvas.brush.color:= RGB(I*4,I*3,0);
fillrgn(canvas.handle,hr,canvas.brush.handle);
end;
end;


 
MBo ©   (2002-06-13 12:27) [7]

if PtInRegion(hr,x,y) then BEGIN
canvas.brush.color:= RGB(I*4,I*3,0);
fillrgn(canvas.handle,hr,canvas.brush.handle);
END

А насчет идентификации - можно сделать объектную обертку над регионами, чтобы не возиться с API каждый раз, да и к внутренним
параметрам регионов через GetRegionData обращаться неудобно.
Или хоть для начала можно, скажем, сделать записи типа
TRgnRec=record
hr:hRgn;
x1:integer;
...
Brush:TBrush или Color
Name:String
и т.п.
end;


 
:: Joiro [ur] ::   (2002-06-13 14:20) [8]

Ухх... надо же Begin и End забыть... совсем уже глюки начались (сессия...). :)

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

Спасибо за помощь.


 
.: Joiro :. ©   (2002-06-13 18:11) [9]

Окей... подумал и решил делать вариант с записями. Хорощо что в примере была переменная String – сразу подумал что так можно прекрасно реализовать помощь на-лету, где если мышь над кликуемым обектом где-то показывается информация.

Больщое спасибо за помощь - сам я бы тут днями сидел и мучался (что, возможно, было бы правильнее для изучения языка, но всё же...).

Но теперь есть ещё вопрос:

Реально регионы будут над картинкой и когда мышь над ними надо высветить регион и когда она удаляется вернуть обратно. Всё что я смог смастерить это или перерисовывать всю фоновую картинку (но тогда мерцание и просто неправильно так делать) или пробовать копировать кусок картинки «под» регионом. Но и с этим были трудности – ясно что не использовать медленные функции копирования из Canvas а c быстрыми мэтодами из WinAPI я так и не смог разобратся.

Чтобы легче понять что и как я засунул код и картинку для фона в Zip файл, который можно найти здесь: www.ltn.lv/~joiro/REGIONS.zip

Может кто-нибудь из знатоков мог бы взглянуть и дать совет как сделать нормальные кнопки?

Если так легче можно и по почте.


 
int64 ©   (2002-06-13 20:56) [10]

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


> медленные функции копирования из Canvas


Функции копирования из Canvas достаточно быстрые, тем более для твоей задачи.


>быстрыми мэтодами из WinAPI


Быстрее где-то на 1-2%.

ЗЫ. То что ты решил использовать для своей задачи канву, а не сотни анимированных контролов - правильно. А вот зачем юзать регионы, когда они всегда прямоугольные - непонятно.


 
.: Joiro :. ©   (2002-06-13 23:15) [11]

Ты должен ввести "глобальную" переменную, которая...
Ага... так... хмм... а как выгдядит обработчик реагирующый на изменения глобальной переменной? У елементов есть onChange, а переменные? (Помните - я псевдо-чайник).

Функции копирования из Canvas достаточно быстрые, тем более для твоей задачи.
Ну, я ещё не делал тесты (для других частей программы делал измеряя процессорные тики - надо будет и здесь это сделать), но повсюду вроде слышно что WinAPI всё же быстрее.

ЗЫ. То что ты решил использовать для своей задачи канву, а не сотни анимированных контролов - правильно. А вот зачем юзать регионы, когда они всегда прямоугольные - непонятно.
Я не знаю посмотрел ли ты пример, но там уже частично видно зачем, если я правильно понимаю вопрос. Я сам больще занимаюсь графикой чем программированием и хочется приятный и достаточно "реагирующий" интерфейсс. Когда мышь заходит на "кнопку" та зажыгается, если кликнуть ещё блестнет. Регионы там всегда стоят и я смогу одним хоткием включить им всем подсветку и посмотреть правильно они расположены или нет. В конце будет пара десятков, возможно даже около сотни кнопок - не хочется мучатся. :)

И ещё тогда вопрос - как правильно копировать из канвы в регион? Что-то у меня не получается.


 
int64 ©   (2002-06-14 03:30) [12]

1. Глобальную я взял в кавычки. Разумеется, это свойство какого-л. объекта или функция, меняющая эту переменную. Главное не то, как ты её будешь хранить, а то, что будет происходить, когда в программе дойдёт очередь её менять.

2. Когда я писал, что методы WinAPI для копирования канвы быстрее на 1-2%, то взял цифры наглаз. Настолько большие, насколько хватило духу. На самом деле всё ещё быстрее. Тормоза можно будет зафиксировать, если для битмапа ты юзаешь свою палитру, HALFTONE"s и с-во Transparent. (см. TBitmap.Draw). А так же постоянно меняешь шрифты, стили и.т.д.
А юзанье TCanvas.CopyRect вообще идентично StretchBlt.

3. Самое главное.
Для твоей задачи регионы нахрен не нужны. Достаточно иметь список прямоугольников. PtInRect куда быстрее, чем PtInRegion. И копировать из канвы в регион вообще не придётся. Ректы нужно будет хранить для прорисовки (имхо, и это лишнее).
Более того, поскольку все ректы у тебя одинаковые по длине и по ширене, и образуют таблицу, то проверять наличие указателя в том или ином ректе перебором в цикле просто глупо. Достаточно получать номер строки:
row:= MouseX div WidthOfRect;
Колонка - анологично.


 
.: Joiro :. ©   (2002-06-14 10:05) [13]

1. Глобальную я взял в кавычки. Разумеется, это...
А, ну тогда ясно...

2. Когда я писал, что методы WinAPI для...
Ну, ничего так особенно там менятся не будет - так что да, тормозов скорее всего не будет.

Более того, поскольку все ректы у тебя одинаковые по длине и по ширене, и образуют таблицу, то проверять наличие указателя в том или ином ректе перебором в цикле просто глупо. Достаточно получать номер строки:
row:= MouseX div WidthOfRect;
Колонка - анологично.

Я и чайник, но не такой чайник - когда есть нужда я точно так и делаю (в старой программе). Но это ведь только пример и если так подумать не совсем похожый на реально применяемый. Реально кнопки разные, распределены по-разному на форме и разного размера.

Если интересно, то дай мейл, я подошлю картинки и кое-что ещё.


 
SI-riuss ©   (2002-06-16 12:30) [14]

Я вообще не понимаю проблемы. Ну установи ты на форму какой нибудь нулевой компонент, например Image без картинки (вообще ее не загружай), и кликай на нее сколько влезет.


 
.: Joiro :. ©   (2002-06-16 13:43) [15]

Можно конечно и так (я использую не Image а Shape) но как-то хочется чистоты. Для стандартного конечного пользователя это конечно не видно да и всё равно, но так как тут конечный пользователь и я сам...

Но похоже что действительно придётся ставить эти самые ненавистные компоненты, прикрепить CM_MOUSEENTER/CM_MOUSELEAVE и всё.


 
SI-riuss ©   (2002-06-16 18:09) [16]

Хорошо. Хочешь "чистоты", тогда в событии OnClick на форме или что у тебя там наверху, пропиши условие if для координат курсора.


 
.: Joiro :. ©   (2002-06-16 18:39) [17]

Посмотри на мой второй трид - http://delphi.mastak.ru/cgi-bin/forum.pl?look=1&id=1024133464&n=7

Я решил использовать Shape c модификациями. Работает неплохо, хотя и в конце будет полно этих штучек на форме, но возможность очень лёгкой (но красивой, ИМХО) перерисовки оправдывает.



Страницы: 1 вся ветка

Текущий архив: 2002.10.17;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.017 c
1-56049
Юрий Федоров
2002-10-08 11:29
2002.10.17
Application.OnException


14-56300
Cr@sh
2002-09-22 15:04
2002.10.17
У кого какая версия Делфи? Лицензия или нет?


7-56374
Viktor Kushnir
2002-08-09 19:47
2002.10.17
Как узнать частоту обновления экрана


1-56063
Лана Розанова
2002-10-08 12:40
2002.10.17
Exel


14-56319
Esu
2002-09-24 21:37
2002.10.17
Хиппи ты или нет ?