![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Добавление published свойства
RASkov © (2006-09-10 05:27:00)Подскажите пожалуйста как при написании компанента добавить ему паблишед свойство чтобы в инспекторе объектов, значение свойства выбиралось из выподающего списка. В список должны добавляться компаненты имеющиеся на форме и имеющие Canvas. В написании компанент опыта мало т.е. нет.
TMyCompanent = class(TCompanent)
private
FCanvas: TCanvas;
....
published
property Canvas: TCanvas ....?????...
....
end;
Можно кусок примера как это делается. Т.е. если "кинуть" мой компанент на читую("голую") форму то в Инсп.Объектов у моего компанента в списке свойства Canvas должна быть Form1. Бросили на форму Image1 - и его в список. Ну и так всех у кого есть канва.
DimaBr (2006-09-25 16:53:00) [81]
TMyComponent = class(TComponent)
private
fCanvasControls: TCustomControls;
procedure SetCanvasControls(const Value: TCustomControl);
published
property CanvasControls: TCustomControl read fCanvasControls write SetCanvasControls;
end;
procedure TMyComponent.SetCanvasControls(const Value: TCustomControl);
begin // процедура срабатывает при изменении свойства CanvasControls
fCanvasControls := Value;
end;
RASkov (2006-09-25 16:28:00) [82]
> DimaBr (25.09.06 15:51) [38]
Наверное не совсем то...
Вообщем у меня задача изначально была такой... сделать нечто наподобие графического меню, ну типа как в играх, в моем компаненте в одном поле было место под битмап, этот битмап представлял собой кратинки разных состояний элементов меню (нажатое, под мышкой, отключено...) также у него (компанента) есть свойства (поля) кол-во строк меню... высота строки ... ширина... так -же для вывода хотел использовать любой контрол с доступной канвой.... на этой канве имеется рисунок и мой компанент должен был рисовать поверх этого рисунка свои элементы... они (элементы) могут выводится верикально или горизонтально с масштобированием... и также должен был быть доступен выбор одного и того же контрола для вывода несколькими моими компанентами (ну это если захочется сделать несколько разных менюшек на одном "экране" (контроле с канвасом)).... можно конечно создавать кучу Images и выводить их с определенными координатами... но хотелось рисовать все на одной канве методами BitBlt, StreachDraw... для вывода элементов хотел использовать массив TRect и также перехватывать сообщения мыши того контрола который был выбран в моем(их) компаненте(ах)... Вот такая вот загагулина... Поэтому и хотел все это оформить в виде компанента для себя... Похоже затею мою под стол пока... Хотя тут мне советовали пару раз сделать процедуру вывода на любой канвас... например вот:
Забудьте пока о компоненте. Возьмите любой графический контрол, хотя бы TImage и бросьте его на форму (только его одного). Потом напишите метод формы, который будет четко прорисовывать одну и ту же картинку (любую) и на канве формы, и на канве этого контрола.
Чесно не совсем понял этого....
procedure DrawCnvs(Cnv: TCanvas);
begin
Cnv.Rectangle(10,10,100,100);
end;
procedure Form1Paint();
begin
DrawCnvs(Form1.Canvas);
DrawCnvs(Image1.Canvas);
end;
Вроде так что ли?
> GrayFace © (23.09.06 20:48) [36]
> RASkov (22.09.06 16:23) [35]
> Где, как отловить/перекрыть момент заполнения списка поля
> CanvasControls
> write SetCanvasControls
Можно объяснить это - я так понимаю здесь можно ограничить выбор кнтролов а не отфильтровать... т.е. в списке будут все а выбрать будет возможно не все...
Спасибо всем.
DimaBr (2006-09-25 15:51:00) [83]Подумайте над [32] - это гораздо проще...
RASkov (2006-09-24 21:56:00) [84]> [36] GrayFace © (23.09.06 20:48)
Доходчиво... Спасибо.
GrayFace (2006-09-23 20:48:00) [85]Юрий Зотов © (18.09.06 2:04) [25]
Хорошо, если компонент оконный, то можно перехватить его оконную функцию, а в ней обрабатывать сообщения отрисовки.
А еще WM_(NC)PAINT может не всегда вызываться. Например, так происходит с кнопкой и TComboBoxEx.
Ketmar © (18.09.06 16:31) [27]
за такое больно бьют по рукам. а компонент, который имеет наглость затирать OnXXX -- отправляется в помойку без дальгейших бесед.
Зачем же так сразу? А если компонент менюшки отрисовывает? Конечно, их возможно отрисовать без событий OnMeasureItem и OnDrawItem, но ценой разбухания кода и потери гибкости.
RASkov (18.09.06 23:09) [31]
Или плюнуть на такую затею с гибкостью и делать все в одном компаненте?
Сделай процедуру, рисующую на произвольном канвасе в произвольном прямоугольнике и будет гибкость.
RASkov (22.09.06 16:23) [35]
Где, как отловить/перекрыть момент заполнения списка поля CanvasControls
write SetCanvasControls
RASkov (22.09.06 16:23) [35]
И вот есть GetPropInfo(TControl, 'Canvas', tcClass); ... он находит только в published?
Да.
RASkov (22.09.06 16:23) [35]
Смысл, реально ли так сделать... перекрыть заполнение поля и проверяя (если есть там какой нить метод проверки всех property) все property самому выбирать кого добавлять в список?
"Проверять все property" - нельзя. Можно проверять все property, находящиеся в published. А так, редактор свойства может делать все что угодно. Например, при выборе контрола без канваса удалять все значки с рабочего стола, чтоб не повадно было подсовывать компоненту что попало.
RASkov (2006-09-22 16:23:00) [86]Чето ничего не выходит, вот на последок можно поинтересоваться, при таком вот объявлении свойства:
TMyComponent = class(TComponent)
private
fCanvasControls: TCustomControls;
published
property CanvasControls: TCustomControl read fCanvasControls write fCanvasControls;
end;
Где, как отловить/перекрыть момент заполнения списка поля CanvasControls
И вот есть GetPropInfo(TControl, 'Canvas', tcClass); ... он находит только в published? Толком рассмотреть TypInfo неуспел пока....
Смысл, реально ли так сделать... перекрыть заполнение поля и проверяя (если есть там какой нить метод проверки всех property) все property самому выбирать кого добавлять в список? Спасибо.
RASkov (2006-09-19 15:40:00) [87]Спасибо. Будем искать выход из сложившейся ситуации....
Наиль (2006-09-19 09:55:00) [88]
> Можно поподробнее... Если пользователь специально выбирает
> контрол на котором будет рисовать мой компанент... чего
> он там может не ожидать?
Все очень просто.
Вся сущность PaintBax'a в событии OnPaint. Без этого свойства компонент ни чего не делает. Итак, Вася Пупкин ещё не задумываясь о твоей компоненте, бросает на форму PaintBox и определяет его события в результате в Object Inspector'e OnPaint=PaintBox1Paint
Тут он замечает в палитре твою компаненту, бросает на форму и выберает PaintBox в качестве СanvasControl. А теперь 2 варианта:
1. Он сделал это сознательно. Тут он замечает, что свойство OnPaint пустое.
Естественно, он обратно присвает свой метод PaintBox1Paint, тем самым вышыбая твой. Запускает программу, твой компанент не работает. Вася Пупкин расстроен.
2. Он эксперементировал. Не заметив, что PaintBox1Paint исчез из Object Inspector'а он запускает программу. Его метод не срабатывает (если ты его не исполнил в своей компоненте). Вася Пупкин растроен.
Вероятность первой проблемы настолько не нулевая, что ответ очевиден. Так как хочешь сделать ты (присвоение значение паблишед-свойству) - делать нельзя.
> Это как? Т.е. так?
Именно так. С дополнительной проверкой того, что методы не nil и OldPaint<>MyPaint.
> я не могу понять почему: 1) Глупо 2) Не возможно 3) Не нужно...
4) Сложно. Не многим мастерам такое под силу. Но пойдя по такому пути, то соберёшь столько грабель и узнаешь столько секретов, что хватит ло бы на десяток других подобных задач. А это уже не мало. Ставя перед собой труднодостижимые задачи ты обесечиваешь свой быстрый рост, как программиста.
К слову сказать. Попадал ко мне как-то компанент выполняющий аналогичные функции. Его задача была, сделать так что в приложении под W98 все стандартные компоненты (и их потомки) выглядили так, как в XP.
Как он работал точно не знаю, но скорее всего определялся тип контрола, и подменялся виртуальный метод Paint (это можно сделать функцией SetVirtualMethodAddress из модуля RxHook библиотеки RxLib).
Так что задача решаема, а если изменишь формулировку своей задачи на правильную, то тем более.
DimaBr (2006-09-19 08:33:00) [89]Простейшее решение состоит в том чтобы не рисовать на чужём контроле, а создавать поверх него свой, толь присваивая Parent, толи SendToFront
> И это... мой компанент не визуальный, а то чета все забываю сказать.
Ещё в [16] сказал - (TMyComponent = class(TComponent))
RASkov (2006-09-18 23:09:00) [90]> [28] Наиль © (18.09.06 16:37)
> Конечно, можно попытаться запомнить событие назначеное пользователем
> и вызывать его из своего метода
Это как? Т.е. так?
procedure SetCanvasControls (Value: TGraphicControl);
begin
FCanvasControl:=Value;
OldPaint:=Value.OnPaint; //Здесь напрямую неполучится, надо повыеживаться
Value.OnPaint:=MyPaint; //Тоже самое
end;
procedure MyPaint(Sender: TObject);
begin
if FCanvasControl = nil then Exit;
OldPaint;
<Здесь "работает" мой компанент>
end;
....
> Во-первых пользователь ожидает не этого, вернее он этого
> не ожидает. А во-вторых, может возникнуть конфликт метода
> пользователя и твоего метода.
Можно поподробнее... Если пользователь специальновыбирает контрол на котором будет рисовать мой компанент... чего он там может не ожидать?
Или плюнуть на такую затею с гибкостью и делать все в одном компаненте? Я тока учусь и поэтому интересно Ваше мнение. Я конечно понимаю, что тут меня уже отговаривают от моей мысли такого компанента, но я не могу понять почему: 1) Глупо 2) Не возможно 3) Не нужно...
и конечно я понимаю что и Вы можете мою затею не совсем правильно или совсем неправильно понять. Но все равно, обоснованные ответы (особенно Кетмара :), если их понять то вооще можно загордиться...хотя обоснований в них мало - одни указания... но мне они нравятся)наводят на правильные мысли... или неправильные...:)
И это... мой компанент не визуальный, а то чета все забываю сказать.
Спасибо всем.
RASkov (2006-09-18 17:51:00) [91]> [28] Наиль © (18.09.06 16:37)
> [27] Ketmar © (18.09.06 16:31)
> [29] DimaBr (18.09.06 16:42)
Усе понял... Хотя...
> Но в таком случае есть две проблемы. Во-первых пользователь
> ожидает не этого, вернее он этого не ожидает. А во-вторых,
> может возникнуть конфликт метода пользователя и твоего
> метода.
Собственно задумка и была использовать мой комп. с другими т.е. пользователь, при выборе контрола в моем компаненте, должен осозновать, что рисовать на его канве теперь задача моего компанента... вот....
Мож... тогда в мой комп. еще и ПаинтБокс засунуть и решить все одним разом... просто хотелось чтоб... ну и на канве формы можно было это рисовать, без "посредников"...
Спасибо.
DimaBr (2006-09-18 16:42:00) [92]
> FCanvasCtrl.OnPaint:=Методмоегокомпанента;
Ничо не выйдет, OnPaint есть только у TPaintBox
procedure TPaintBox.Paint;
begin
Canvas.Font := Font;
Canvas.Brush.Color := Color;
if Assigned(FOnPaint) then FOnPaint(Self);
end;
Можно попробывать переопределить окннную процедуру контрола и НЕ посылать сообщение о собственной прорисовки. Тогда компонент рисоваться не будет, только на кой ляд это нужно.
Объясните зачем Вам это вообще понадобилось, чувствуется Вы не в той луже топчитесь.
Наиль (2006-09-18 16:37:00) [93]Нельзя так делать.
FCanvasControl указывает на компонент лежащий на форме и доступный пользователю. Если пользователь определил событие контрола, а потом упомянул контрол в CanvasControl, то ссылка на метод пользователя будет сброшена и заменена на вашу.
Конечно, можно попытаться запомнить событие назначеное пользователем и вызывать его из своего метода. Метод пользователя будет вызван, что и требуется. Но в таком случае есть две проблемы. Во-первых пользователь ожидает не этого, вернее он этого не ожидает. А во-вторых, может возникнуть конфликт метода пользователя и твоего метода.
Со второй проблемой предётся бороться в любом случае, т.к. твое рисование не должно отрицать рисование пользователем.
Что касается первой проблемы, то Юрий Зотов уже не раз говорил о том, что при работе с компонентом пользователь опирается на стандартное (стандартизированое) поведения компонент, и не должен вникать в проблемы разработщика компонент.
Ketmar (2006-09-18 16:31:00) [94]> [26] RASkov (18.09.06 16:22)
за такое больно бьют по рукам. а компонент, который имеет наглость затирать OnXXX -- отправляется в помойку без дальгейших бесед.
RASkov (2006-09-18 16:22:00) [95]
> Юрий Зотов © (18.09.06 02:04) [25]
Спасибо Вам, Юрий, а.... нельзя ли так.... у меня компанент нивидимый ну.. т.е. без окна.. ну как TTable или TDataSource и ижи с ними (забыл как их там правильно) но в свойстве CanvasCtrl если выбран контрол, то может в моем компаненте при выборе контрола переопределять некоторые его события например OnPaint он наверняка у него будет когда канва доступна. У моего компанента ведь непосредственная ссылка(указатель) есть на контрол. Вот такие вот предположения... (Только что до этого додумался) Вечером домой приду попробую....
типа так
FCanvasCtrl.OnPaint:=Методмоегокомпанента;
ну может еще привидение типа надо будет...
Спасибо.
Юрий Зотов (2006-09-18 02:04:00) [96]> CopyRect, BitBlt, Draw...
Это понятно. Непонятно другое - КУДА Вы будете вставлять Ваш код отрисовки?
Ведь как только целевой компонент захочет перерисоваться (а это будет обязательно), он тут же затрет Вашу картинку. Поэтому ее нужно перерисовывать одновременно с каждой перерисовкой целевого компонента (точнее, сразу после нее). Значит, его перерисовку надо перехватывать - а как это сделать?
Хорошо, если компонент оконный, то можно перехватить его оконную функцию, а в ней обрабатывать сообщения отрисовки. А если он неоконный, тогда как быть?
Так что не с того Вы начали. Не редактор свойства нужно писать, это как раз не проблема, а код рисования - вот что главное. Иначе получается, что мы решили построить автомобиль и начали с изготовления подфарников. А как делать ходовую часть, двигатель и трансмиссию - не представляем. Вот и судите сами - при таком подходе получится у нас автомобиль, или нет?
Забудьте пока о компоненте. Возьмите любой графический контрол, хотя бы TImage и бросьте его на форму (только его одного). Потом напишите метод формы, который будет четко прорисовывать одну и ту же картинку (любую) и на канве формы, и на канве этого контрола. Как только это получится, задачу можно считать решенной и тогда можно возвращаться к написанию компонента. Причем самый сложный и самый важный кусок будет уже готов, останется только перенести его код в компонент. Вот после этого уже можно и редактор делать.
RASkov (2006-09-17 22:33:00) [97]Смешно как то получается, Я задал вопрос, а тут сам на кучу вопросов отвечаю....:)).... наводящих.
RASkov (2006-09-17 22:30:00) [98]> [22] Юрий Зотов © (17.09.06 21:55)
> > по специально придуманному алгоритму
>
> Вот с этого и стоит начать - КАК Вы собираетесь рисовать?
CopyRect, BitBlt, Draw...
> Потому что рисовать можно на любом TWinControl'е (у него
> есть DC) или TGraphicControl'e (у него есть Canvas)
Ну вот и хотел как проще, отфильтровать тех, у кого канва не скрыта...
> А вот КАК Вы перехватите перерисовку внешнего компонента,
> чтобы Ваша картинка не затиралась?
Ну... вот... я там второй вопрос задал... Буду придумывать :)
Юрий Зотов (2006-09-17 21:55:00) [99]> по специально придуманному алгоритму
Вот с этого и стоит начать - КАК Вы собираетесь рисовать?
Потому что рисовать можно на любом TWinControl'е (у него есть DC) или TGraphicControl'e (у него есть Canvas) - так что проблема фильтрации, можно сказать, просто отсутствует. А вот КАК Вы перехватите перерисовку внешнего компонента, чтобы Ваша картинка не затиралась?
RASkov (2006-09-17 21:29:00) [100]> [20] Юрий Зотов © (17.09.06 17:28)
Спасибо Вам за ответ. Постараюсь описать задачу... пытаюсь сделать компанент у которого в полях имеется БитМап... так вот этот БитМап необходимо прорисовать на канве того кто быдет выбран в поле CanvasControls.
Т.е. вот на форме выбран мой компанент и вот некоторые свойства его в инспекторе объектов
CanvasCtrl | <Все имеющие канву> //Здесь выпадающий список
Picture | (TBitMap) //Тип TBitMap
Top | 10 //Координаты откуда нужно рисовать
Left | 50 //на чужой канве
А вообще Top и Left хочу заменить на TRect (область) но пока незнаю как.
И вот нужно, если установлено Picture и CanvasCtrl, то по специально придуманному алгоритму нарисовать на канве выбранного контрола части указанного Битмапа. Вот загнул. И вот вопрос второй в каком методе лучше это прорисовать, так что бы и во время дизайна было видно что там рисуется? Спасибо.