Форум: "Компоненты";
Текущий архив: 2007.09.09;
Скачать: [xml.tar.bz2];
ВнизДобавление published свойства Найти похожие ветки
← →
RASkov (2006-09-10 05:27) [0]Подскажите пожалуйста как при написании компанента добавить ему паблишед свойство чтобы в инспекторе объектов, значение свойства выбиралось из выподающего списка. В список должны добавляться компаненты имеющиеся на форме и имеющие Canvas. В написании компанент опыта мало т.е. нет.
TMyCompanent = class(TCompanent)
private
FCanvas: TCanvas;
....
published
property Canvas: TCanvas ....?????...
....
end;
Можно кусок примера как это делается. Т.е. если "кинуть" мой компанент на читую("голую") форму то в Инсп.Объектов у моего компанента в списке свойства Canvas должна быть Form1. Бросили на форму Image1 - и его в список. Ну и так всех у кого есть канва.
← →
Джо © (2006-09-10 21:32) [1]Нужно зарегистрировать свой редактор свойств, вызвав RegisterPropertyEditor. Редактор (наследник TPropertyEditor) должен иметь атрибут paValueList). Примеры написания редакторов смотри в файле DesignEditors.pas.
← →
DimaBr (2006-09-11 09:31) [2]
> Джо © (10.09.06 21:32) [1]
Не совсем так, думаю достаточно сделать следующее
TMyComponent = class(TComponent)
private
fCanvasControls: TCustomControls;
public
procedure Notification(AComponent: TComponent; Operation: TOperation);override;
published
property CanvasControls: TCustomControl read fCanvasControls write fCanvasControls;
end;
procedure TMyComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin
If (Operator = opRemove) and (AComponent = CanvasControls) then CanvasControls := nil;
end;
← →
Джо © (2006-09-11 13:32) [3]> [2] DimaBr (11.09.06 09:31)
> Не совсем так, думаю достаточно сделать следующее
И каким образом этот код поможет сделать так "чтобы в инспекторе объектов, значение свойства выбиралось из выподающего списка"?
← →
DimaBr (2006-09-11 13:43) [4]Редактор свойства типа TComponentProperty уже умеет искать компоненты по формам и предлагать выпадающий список.
← →
Джо © (2006-09-11 13:50) [5]> [4] DimaBr (11.09.06 13:43)
> Редактор свойства типа TComponentProperty уже умеет искать
> компоненты по формам и предлагать выпадающий список.
Да, точно, забыл. Только я все-же за свой редактор, ибо, для корректной работы, нужно будет в список помещать не всех наследников TCustomControl, а только тех, у кого Canvas в public. Да еще TGraphicControl. Автору же не все наследники TComponent нужны.
← →
DimaBr (2006-09-11 14:28) [6]
> Джо © (11.09.06 13:50) [5]
> Автору же не все наследники TComponent нужны.
Добраться до канвы можно с помощью Hask касса. А все наследники и не покажутся, только выше TCustomControls
← →
Джо © (2006-09-11 15:19) [7]> [6] DimaBr (11.09.06 14:28)
>
> > Джо © (11.09.06 13:50) [5]
> > Автору же не все наследники TComponent нужны.
>
> Добраться до канвы можно с помощью Hask касса.
Неизвестно, нужно ли это автору. Канва-то, небось, не зря спрятана. Впрочем, тут слово за ним.
> только выше TCustomControls
А Canvas еще есть и у TGraphicControl.
← →
DimaBr (2006-09-11 15:59) [8]
> А Canvas еще есть и у TGraphicControl.
Такая постановка задачи сводится к нулю. Я напишу свой потомок от TControl со своей реализацией Canvas. Его компонент мой контрол не найдёт.
← →
Джо © (2006-09-11 16:02) [9]> [8] DimaBr (11.09.06 15:59)
>
> > А Canvas еще есть и у TGraphicControl.
>
> Такая постановка задачи сводится к нулю.
Тогда непонятно, почему такое предпочтение именно к TCustomControls :)
← →
DimaBr (2006-09-11 16:16) [10]От TCustomControls непосредственно пораждено 25 объектов ( в основном TCustom...)
От TGraphicControl - 18 ( в основном уже конечные компоненты), к тому же виндовс о них ничо не знает.
← →
Джо © (2006-09-11 16:26) [11]> От TGraphicControl - 18 ( в основном уже конечные компоненты)
> , к тому же виндовс о них ничо не знает.
Причем тут Windows и его знание о чем-то?
Хм, 18 против 25 никак нельзя назвать "решительным перевесом", не так ли? ;)
← →
Наиль © (2006-09-11 16:34) [12]
> От TGraphicControl - 18 ( в основном уже конечные компоненты),
> к тому же виндовс о них ничо не знает.
Очень не редко предлагается делать украшательства для программ на основе TImage. И если кто-то прислушивается к таким советам, то перевес может быть обратным.
← →
DimaBr (2006-09-11 16:39) [13]
> Хм, 18 против 25 никак нельзя назвать "решительным перевесом",
> не так ли? ;)
25 Custom-ов вырастут в большое количество компонентов.
← →
RASkov (2006-09-12 12:51) [14]Спасибо всем.
В принципе, меня устроило и этоpublished
property CanvasControls: TGraphicControl read fCanvasControls write fCanvasControls;
Единственный косяк для моих целей, это то, что туда конечно же не попадает форма....
DimaBr (11.09.06 14:28) [6]
> Джо © (11.09.06 13:50) [5]
> Автору же не все наследники TComponent нужны.
Добраться до канвы можно с помощью Hask касса. А все наследники и не покажутся, только выше TCustomControls
А можно пример "добраться до канвы можно с помощью Hask касса"...
← →
Наиль © (2006-09-12 15:24) [15]Из старых форумов
type
THackCheckListBox = class(TCheckListBox);
//.................
var
ACheckListBox : TCheckListBox;
begin
//.....................
THackCheckListBox(ACheckListBox).MultiSelect := ?
//.....................
end;
← →
RASkov (2006-09-12 22:56) [16]> [8] DimaBr (11.09.06 15:59)
> > А Canvas еще есть и у TGraphicControl.
> Такая постановка задачи сводится к нулю. Я напишу свой потомок
> от TControl со своей реализацией Canvas. Его компонент мой
> контрол не найдёт.
Т.е. ты скроешь у своего контрола канву? Мне как раз и нужно в список добавлять такие контролы, у которых она не скрыта, так как мой(я) компанент(а), (как правильно - то?), будет рисовать на ней. Для таких целей можно и жестко сделать типаTMyComponent = class(TComponent)
private
fCanvasControls: TImage;
public
procedure Notification(AComponent: TComponent; Operation: TOperation);override;
published
property CanvasControls: TImage read fCanvasControls write fCanvasControls;
end;
Ну это неправильно. А вообще хотелось бы, что бы туда (в списокproperty CanvasControls
) попала и форма и тот же PaintBox, Image... Т.е. те которые собственно и предназначены для рисования ну и форма в первую очередь.
В данный момент выше написанное проверить не могу (нет Delphi под рукой), но вот заинтересовали пара ответов это [15] и еще больше [2]
Не могли бы Вы нимного прокомментировать их?
В часности [15], т.к. по [2] почти, или наверное, полность описано про мое свойство... останется только добраться до Делфей и проверить а вот [15]...
Спасибо.
← →
DimaBr (2006-09-13 11:19) [17]
> RASkov (12.09.06 22:56) [16]
Я имел в виду следующее: можно написать редактор свойства ( как предлагал Джо ©), который просматривает все компоненты в поиске порождённых от TGraphicControl и TCustomControl, однако мой компонент, поражденный от TContol со своей канвой он не найдёт.
← →
RASkov (2006-09-17 00:11) [18]А без редактора свойства ни как? силами компанента...
Ну вот както TDataSource и свойство DataSet или TUpDown и свойство Associate справляются без редакторов....?
← →
RASkov (2006-09-17 02:04) [19]Ладно, если никак не получится фильтровать в списке без редактора свойства, то вот таким вот способом добился ограничение выбора из списка в инспекторе свойства CanvasControls
TMyComponent = class(TComponent)
private
fCanvasControls: TGraphicControl;
procedure SetCanvasControls(Value: TGraphicControl);
published
property CanvasControls: TGraphicControl read fCanvasControls write SetCanvasControls;
end;
procedure TMyComponent.SetCanvasControls(Value: TGraphicControl);
begin
if Value is TPaintBox then FCanvasControls := Value;
//или
//if Value Imeet Canvas then FCanvasControls := Value;
else raise.Create("Нельзя это");
end;
Подскажите как вот организовать проверкуif Value Imeet Canvas then
, т.е. как опредилить - имеет ли Value доступную канву?
Ну рано мне пока с редакторами делать....
Подсмотрел как делается у TUpDown свойство Associate и... нихрена толком не понял кроме того, что привел выше. Спасибо.
← →
Юрий Зотов © (2006-09-17 17:28) [20]> RASkov (17.09.06 02:04) [19]
> как вот организовать проверку
Универсального способа не существует (по крайней мере, легального).
Заведомо известно, что канву имеют TGraphicControl (и все его потомки) и TCustomControl (и все его потомки) - поэтому проверку можно построить на простой принадлежности к этим классам (оператор is). Но такая проверка не будет полностью достоверной, потому что никто не мешает написать свой объект с любым предком и ввести в него канву (привязавшись к любому окну и получив его DC).
Если свойство (или поле) типа TCanvas объявлено в секции published и объект компилировался с опцией M+ (или наследовался от TPersistent), то можно построить фильтрацию на механизмах RTTI - получить список свойств (или полей), пройти по нему и определить наличие свойств (или полей) типа TCanvas. Но и такое решение тоже не будет полным, потому что свойство (или поле) типа TCanvas выносить в published просто незачем, так что вряд ли кто станет это делать; с другой стороны, это свойство (или поле) реально нужно в секции public (или protected) - а для них RTTI не работает.
Можно строить фильтрацию и на любой комбинации двух изложенных подходов - но и в этом случае полностью достоверной она все равно не будет.
Поэтому универсального способа не существует (по крайней мере, легального). Вообще же, возникает ощущение, что Вы ищете решение задачи не там, где его можно найти. В чем она первоначально заключается?
← →
RASkov (2006-09-17 21:29) [21]> [20] Юрий Зотов © (17.09.06 17:28)
Спасибо Вам за ответ. Постараюсь описать задачу... пытаюсь сделать компанент у которого в полях имеется БитМап... так вот этот БитМап необходимо прорисовать на канве того кто быдет выбран в поле CanvasControls.
Т.е. вот на форме выбран мой компанент и вот некоторые свойства его в инспекторе объектовCanvasCtrl | <Все имеющие канву> //Здесь выпадающий список
Picture | (TBitMap) //Тип TBitMap
Top | 10 //Координаты откуда нужно рисовать
Left | 50 //на чужой канве
А вообще Top и Left хочу заменить на TRect (область) но пока незнаю как.
И вот нужно, если установлено Picture и CanvasCtrl, то по специально придуманному алгоритму нарисовать на канве выбранного контрола части указанного Битмапа. Вот загнул. И вот вопрос второй в каком методе лучше это прорисовать, так что бы и во время дизайна было видно что там рисуется? Спасибо.
← →
Юрий Зотов © (2006-09-17 21:55) [22]> по специально придуманному алгоритму
Вот с этого и стоит начать - КАК Вы собираетесь рисовать?
Потому что рисовать можно на любом TWinControl"е (у него есть DC) или TGraphicControl"e (у него есть Canvas) - так что проблема фильтрации, можно сказать, просто отсутствует. А вот КАК Вы перехватите перерисовку внешнего компонента, чтобы Ваша картинка не затиралась?
← →
RASkov (2006-09-17 22:30) [23]> [22] Юрий Зотов © (17.09.06 21:55)
> > по специально придуманному алгоритму
>
> Вот с этого и стоит начать - КАК Вы собираетесь рисовать?
CopyRect, BitBlt, Draw...
> Потому что рисовать можно на любом TWinControl"е (у него
> есть DC) или TGraphicControl"e (у него есть Canvas)
Ну вот и хотел как проще, отфильтровать тех, у кого канва не скрыта...
> А вот КАК Вы перехватите перерисовку внешнего компонента,
> чтобы Ваша картинка не затиралась?
Ну... вот... я там второй вопрос задал... Буду придумывать :)
← →
RASkov (2006-09-17 22:33) [24]Смешно как то получается, Я задал вопрос, а тут сам на кучу вопросов отвечаю....:)).... наводящих.
← →
Юрий Зотов © (2006-09-18 02:04) [25]> CopyRect, BitBlt, Draw...
Это понятно. Непонятно другое - КУДА Вы будете вставлять Ваш код отрисовки?
Ведь как только целевой компонент захочет перерисоваться (а это будет обязательно), он тут же затрет Вашу картинку. Поэтому ее нужно перерисовывать одновременно с каждой перерисовкой целевого компонента (точнее, сразу после нее). Значит, его перерисовку надо перехватывать - а как это сделать?
Хорошо, если компонент оконный, то можно перехватить его оконную функцию, а в ней обрабатывать сообщения отрисовки. А если он неоконный, тогда как быть?
Так что не с того Вы начали. Не редактор свойства нужно писать, это как раз не проблема, а код рисования - вот что главное. Иначе получается, что мы решили построить автомобиль и начали с изготовления подфарников. А как делать ходовую часть, двигатель и трансмиссию - не представляем. Вот и судите сами - при таком подходе получится у нас автомобиль, или нет?
Забудьте пока о компоненте. Возьмите любой графический контрол, хотя бы TImage и бросьте его на форму (только его одного). Потом напишите метод формы, который будет четко прорисовывать одну и ту же картинку (любую) и на канве формы, и на канве этого контрола. Как только это получится, задачу можно считать решенной и тогда можно возвращаться к написанию компонента. Причем самый сложный и самый важный кусок будет уже готов, останется только перенести его код в компонент. Вот после этого уже можно и редактор делать.
← →
RASkov (2006-09-18 16:22) [26]
> Юрий Зотов © (18.09.06 02:04) [25]
Спасибо Вам, Юрий, а.... нельзя ли так.... у меня компанент нивидимый ну.. т.е. без окна.. ну как TTable или TDataSource и ижи с ними (забыл как их там правильно) но в свойстве CanvasCtrl если выбран контрол, то может в моем компаненте при выборе контрола переопределять некоторые его события например OnPaint он наверняка у него будет когда канва доступна. У моего компанента ведь непосредственная ссылка(указатель) есть на контрол. Вот такие вот предположения... (Только что до этого додумался) Вечером домой приду попробую....
типа так
FCanvasCtrl.OnPaint:=Методмоегокомпанента;
ну может еще привидение типа надо будет...
Спасибо.
← →
Ketmar © (2006-09-18 16:31) [27]> [26] RASkov (18.09.06 16:22)
за такое больно бьют по рукам. а компонент, который имеет наглость затирать OnXXX -- отправляется в помойку без дальгейших бесед.
← →
Наиль © (2006-09-18 16:37) [28]Нельзя так делать.
FCanvasControl указывает на компонент лежащий на форме и доступный пользователю. Если пользователь определил событие контрола, а потом упомянул контрол в CanvasControl, то ссылка на метод пользователя будет сброшена и заменена на вашу.
Конечно, можно попытаться запомнить событие назначеное пользователем и вызывать его из своего метода. Метод пользователя будет вызван, что и требуется. Но в таком случае есть две проблемы. Во-первых пользователь ожидает не этого, вернее он этого не ожидает. А во-вторых, может возникнуть конфликт метода пользователя и твоего метода.
Со второй проблемой предётся бороться в любом случае, т.к. твое рисование не должно отрицать рисование пользователем.
Что касается первой проблемы, то Юрий Зотов уже не раз говорил о том, что при работе с компонентом пользователь опирается на стандартное (стандартизированое) поведения компонент, и не должен вникать в проблемы разработщика компонент.
← →
DimaBr (2006-09-18 16:42) [29]
> FCanvasCtrl.OnPaint:=Методмоегокомпанента;
Ничо не выйдет, OnPaint есть только у TPaintBoxprocedure TPaintBox.Paint;
begin
Canvas.Font := Font;
Canvas.Brush.Color := Color;
if Assigned(FOnPaint) then FOnPaint(Self);
end;
Можно попробывать переопределить окннную процедуру контрола и НЕ посылать сообщение о собственной прорисовки. Тогда компонент рисоваться не будет, только на кой ляд это нужно.
Объясните зачем Вам это вообще понадобилось, чувствуется Вы не в той луже топчитесь.
← →
RASkov (2006-09-18 17:51) [30]> [28] Наиль © (18.09.06 16:37)
> [27] Ketmar © (18.09.06 16:31)
> [29] DimaBr (18.09.06 16:42)
Усе понял... Хотя...
> Но в таком случае есть две проблемы. Во-первых пользователь
> ожидает не этого, вернее он этого не ожидает. А во-вторых,
> может возникнуть конфликт метода пользователя и твоего
> метода.
Собственно задумка и была использовать мой комп. с другими т.е. пользователь, при выборе контрола в моем компаненте, должен осозновать, что рисовать на его канве теперь задача моего компанента... вот....
Мож... тогда в мой комп. еще и ПаинтБокс засунуть и решить все одним разом... просто хотелось чтоб... ну и на канве формы можно было это рисовать, без "посредников"...
Спасибо.
← →
RASkov (2006-09-18 23:09) [31]> [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) Не нужно...
и конечно я понимаю что и Вы можете мою затею не совсем правильно или совсем неправильно понять. Но все равно, обоснованные ответы (особенно Кетмара :), если их понять то вооще можно загордиться...хотя обоснований в них мало - одни указания... но мне они нравятся) наводят на правильные мысли... или неправильные...:)
И это... мой компанент не визуальный, а то чета все забываю сказать.
Спасибо всем.
← →
DimaBr (2006-09-19 08:33) [32]Простейшее решение состоит в том чтобы не рисовать на чужём контроле, а создавать поверх него свой, толь присваивая Parent, толи SendToFront
> И это... мой компанент не визуальный, а то чета все забываю сказать.
Ещё в [16] сказал - (TMyComponent = class(TComponent))
← →
Наиль © (2006-09-19 09:55) [33]
> Можно поподробнее... Если пользователь специально выбирает
> контрол на котором будет рисовать мой компанент... чего
> он там может не ожидать?
Все очень просто.
Вся сущность 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).
Так что задача решаема, а если изменишь формулировку своей задачи на правильную, то тем более.
← →
RASkov (2006-09-19 15:40) [34]Спасибо. Будем искать выход из сложившейся ситуации....
← →
RASkov (2006-09-22 16:23) [35]Чето ничего не выходит, вот на последок можно поинтересоваться, при таком вот объявлении свойства:
TMyComponent = class(TComponent)
private
fCanvasControls: TCustomControls;
published
property CanvasControls: TCustomControl read fCanvasControls write fCanvasControls;
end;
Где, как отловить/перекрыть момент заполнения списка поля CanvasControls
И вот есть GetPropInfo(TControl, "Canvas", tcClass); ... он находит только в published? Толком рассмотреть TypInfo неуспел пока....
Смысл, реально ли так сделать... перекрыть заполнение поля и проверяя (если есть там какой нить метод проверки всех property) все property самому выбирать кого добавлять в список? Спасибо.
← →
GrayFace © (2006-09-23 20:48) [36]Юрий Зотов © (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-24 21:56) [37]> [36] GrayFace © (23.09.06 20:48)
Доходчиво... Спасибо.
← →
DimaBr (2006-09-25 15:51) [38]Подумайте над [32] - это гораздо проще...
← →
RASkov (2006-09-25 16:28) [39]
> 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 16:53) [40]
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;
← →
DimaBr (2006-09-25 16:58) [41]Я так и не понял, зачем рисовать изображения на чужих контролах ?
Ваша процедура вывода изображения использует событие формы - решение не подходит, так как не у всех контролов есть OnPaint.
← →
RASkov (2006-09-25 21:02) [42]> [40] DimaBr (25.09.06 16:53)
Это я уже попробовал...:(
Как здесь можно фильтр поставить т.е. "Етого добавить, а Етого нет"?
> Ваша процедура вывода изображения использует событие формы
> - решение не подходит, так как не у всех контролов есть
> OnPaint.
Это тут пару раз мне предложили сделать такую процедуру но я так и не понял что именно нужно и привел этот кусок кода... т.е. так я понял... короче ерунда какая то получается...
> Я так и не понял, зачем рисовать изображения на чужих контролах
> ?
Вроде подробно расписал в [39] вот неполное описание того что хотел сделать. За основу взял TPicClip из RxLib и хотел добавить некоторые свойства и методы:Type
TOrientation = (orVert, orHoriz);
TPicMenu = class(TComponent)
private
FPicture: TPicture;
FCountMenu: Integer;
FBitmap: TBitmap;
FOrientation: TOrientation;
FCanvasControl: TGraphicControl;
.....
published
.......
property MenuHeight: Integer read GetMenuHeight write SetMenuHeight stored False;
property MenuWidth: Integer read GetWidth write SetWidth stored False;
property CountMenu: Integer read FCountMenu write FCountMenu default 1;
property Orientation: TOrientation read FOrientation write SetOrientation default orVert;
property CanvasCtrl: TGraphicControl read FCanvasControl write SetCanvasControl;
end;
Если чесно... то уже желание почти пропало этот компанент делать.
Многое, что понял... многое нет :( И хотелось бы поконкретней услышать про ту процедуру, что имели ввиду Ю.Зотов и GrayFace.
Спасибо всем кто хотел помочь.
← →
RASkov (2006-09-25 21:04) [43]ошибка, так должно:
property MenuWidth: Integer read GetMenuWidth write SetMenuWidth stored False;
← →
DimaBr (2006-09-26 10:27) [44]
> Как здесь можно фильтр поставить т.е. "Етого добавить, а
> Етого нет"?
procedure TMyComponent.SetCanvasControls(const Value: TCustomControl);
begin
if МНЕ ПОДХОДИТ ЭТОТ КОНТРОЛ then fCanvasControls := Value;
end;
Из пункта [39] лично я ничо не понял. Если можно, опишите подробрее (без троеточий) цель Вашего сочинения. Создаётся впечатление что Вас никто не понимает. По крайней мере, цель каждого контрола - корректно отображать свои данные. Вы же предлагаете рисовать поверх него свои, тогда пропадает смысл в использовании этого контрола. Объясните на примерах похожих компонент.
← →
RASkov (2006-09-26 16:40) [45]Прошу прощения, но помоему:
procedure TMyComponent.SetCanvasControls(const Value: TCustomControl);
begin
if МНЕ ПОДХОДИТ ЭТОТ КОНТРОЛ then fCanvasControls := Value;
end;
Таким способом мы ограничиваем выбор свойства т.е. в инспекторе объектов в поле CanvasControls в выподающем списке будут все от TCustomControl но выбрать будет возможно исодя изif МНЕ ПОДХОДИТ ЭТОТ КОНТРОЛ then
- это не совсем то что хотелось.
Хотелось, что бы в инсп. объектов в списке поля CanvasControls были только те контролы которые отвечают условиюif МНЕ ПОДХОДИТ ЭТОТ КОНТРОЛ then
> Из пункта [39] лично я ничо не понял. Если можно, опишите
> подробрее (без троеточий) цель Вашего сочинения. Создаётся
> впечатление что Вас никто не понимает. По крайней мере,
> цель каждого контрола - корректно отображать свои данные.
> Вы же предлагаете рисовать поверх него свои, тогда пропадает
> смысл в использовании этого контрола. Объясните на примерах
> похожих компонент.
Целью моего сочинения было сделать компанент который выводил бы графическое меню на канве выбранного контрола. Т.е. берем ПаинтБокс кидаем на "голую" форму, кидаем туда пару, тройку моих компанентов и в их свойстве указываем один и тот же контрол ПаинтБокс, и вот они (мои компаненты) выводили бы каждый в определенных координатах свои пункты меню. В итоге должно получится такое: контрол (жертва моих компанентов) рисует свою канву и после, поверх уже рисуют мои комп.
Эх... ладно если опять ничего не понятно, то тогда пора закрывать эту тему в связи с тем что нового здесь я уже ничего не узнаю, а как еще понятней объяснить не смогу.
По всей видимости надо свойство сделать жестко, типа TPaintBox и каким то образом заставить инсп. объектов сделать поле с выпадающим списком в котором будут перечислены все ПаинтБоксы на форме. Таким образом ограничить взаимодействие моих компанентов с контролами т.е. привязать их к ПаинтБоксам...
Спасибо всем и отдельное DimaBr за сторание помочь.
← →
RASkov (2006-09-26 16:44) [46]Спасибо всем и отдельное DimaBr за старание помочь.
С русским как и с математикой... трабл:)
← →
DimaBr (2006-09-26 16:55) [47]1. Для ограничения самого списка придётся присать редактор свойства, там уж и будете выбирать какий компоненты подходят, а какие нет. Только в Run-Time этот редактор работать не будет , следовательно ничего не момешает динамически прицепить что угодно.
2. По всей видимости нужно писать как раз таки контрол который отображает, с коллекцией компонентов откуда брать данные, а не наоборот.
← →
GrayFace © (2006-09-26 19:27) [48]RASkov (25.09.06 16:28) [39]
Вроде так что ли?
Ну да. Эта процедура DrawCnvs - в компоненте, а ее вызов при отрисовке какого-то контрола - уже дело пользователя. Как выводить - заботится компонент, куда - пользователь, тут у него и OnPaint, и все что нужно под рукой. Выпадающий список - в топку.
RASkov (25.09.06 16:28) [39]
> RASkov (22.09.06 16:23) [35]
> Где, как отловить/перекрыть момент заполнения списка поля
> CanvasControls
> write SetCanvasControls
Можно объяснить это - я так понимаю здесь можно ограничить выбор кнтролов а не отфильтровать... т.е. в списке будут все а выбрать будет возможно не все...
Да, я тут не понял вопрос.
← →
RASkov (2006-09-26 23:03) [49]> [48] GrayFace © (26.09.06 19:27)
Т.е. получается на OnPaint Controla подсовывать процедуру моего компанентаprocedure TForm1.Form1Paint();
begin
MyCompanent.DrawCnvs(Form1.Canvas);
end;
Если это имелось ввиду... то здесь наверное и смысла нет в компаненте...
Можно просто модуль сделать и таким вот способом рисовать. :)
PS: Я уже плохо сооброжаю чего хочу :)) Сенькс.
← →
DimaBr (2006-09-27 08:33) [50]Ещё раз предлагаю, написать контрол, со свойством - коллекцией управляющих компонентов, который и будет рисовать (предоставлять канву для рисования). Код приблизительно таков
procedure TMyContriol.Paint;
var i: integer;
begin
inherited;
for i := 0 to CompCollection.Count -1 do
CompCollection.Draw(Canvas);
end;
← →
RASkov (2006-09-27 15:04) [51]> [50] DimaBr (27.09.06 08:33)
Спасибо. Мысль понял. Но чето нипойму как это будет выглядеть...
Т.е. как мне в контрол засунуть "много" дуругих. Здесь, наверное, для "нового" контрола нужно будет делать свойство множество для "старых" моих компанентов...
Т.е. примерно так что ли?Type MyOldComp = class (TCompanent)
....
public
Draw(Cnv: TCanvas);
....
end;
TCompCollections = Set of TMyOldComp;
TMyNewComp = class (TGraphicControl);
FPicture: TPicture;
FBitMap: TBitmap;
FCompCollections: TCompCollections;
FCompCollectionCount: Integer;
....
protected
Paint() override;
....
published
property CompCollCount: Integer read FCompCollectionCount;
property CompColletion: TCompCollections read GetCompColl write SetCompColl default [];
property OnPaint; // А это лучше скрыть наверное, но добавить свойство типа "Фон": ТБитМап
......
end;
Вот на "скорую руку накотал". Но, теперь я так понимаю, без редактора свойства никак. Так? Если так, то как он делается, этот редактор..
Можно ли его в одном модуле с компанентом делать, или в одном пакете, или есть какие то правила по их деланию?
Ну вот вроде опять желание появилось "что то хорошее сделать" :)
Если не трудно не могли бы привести простой пример редактора свойства.
Спасибо.
← →
DimaBr (2006-09-27 15:26) [52]немного не так.
TCompCollectionItem = class(TCollectionItem)
private
fComp: TMyOldComp;
public
procedure Notification(AComponent: TComponent; Operation: TOperation);
published
property Comp: TMyOldComp read fComp write fComp;
end;
TMyNewComp = class (TGraphicControl);
fCompCollection: TCollection;
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
published
property CompColletion: TCollections read fCompCollection write fCompCollection;
end;
......
constructor TMyNewComp.Create(AOwner: TComponent);
begin
inherited;
fCompCollection := TOwnedCollectio.Create(Self,TCompCollectionItem);
end;
procedure TMyNewComp.Notification(AComponent: TComponent; Operation: TOperation);
var i: integer;
begin
inherited;
for i := 0 to CompCollection.Count -1
TCompCollectionItem(CompCollection.Items[i]).Notification(AComponent,Operation);
end;
procedure TMyNewComp.Notification(AComponent: TComponent; Operation: TOperation);
begin
if (Operation = opRemove) and (AComponent = Comp) then Comp := nil;
end;
end;
← →
RASkov (2006-09-27 23:48) [53]> [52] DimaBr (27.09.06 15:26)
Спасибо большое.
К сожалению, код приведенный выше содержит ошибки, и я, никогда не писавший компаненты, попытался исправить их... Вроде бы, на мой (делитанский в этом плане) взгляд, исправил ошибки... даже скомпилировал... более того установил этот "чудо-новый мой" компанент
но при выборе его и попытки кинуть на форму.... Усе смерть всей IDE.
Значит не те ошибки исправил :) или более того ничего неисправил, а добавил новых... Что не так? И опять вопрос - нужно ли будет делать редактор для свойства CompColletion? (ну незнаю я как он делается)
Даже не смог заставить это заработать... пойду башкой апстену пится :)
Вот это чудо - смерть Delphi - называется :)unit MyPicMenu;
interface
uses
SysUtils, Classes, Controls;
type
//TMyOldComp = class (TComponent);
TCompCollectionItem = class(TCollectionItem)
private
fComp: TComponent; {TMyOldComp}
public
procedure Notification(AComponent: TComponent; Operation: TOperation);
published
property Comp: TComponent read fComp write fComp;
end;
TMyNewComp = class (TGraphicControl)
fCompCollection: TCollection;
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
published
property CompCollection: TCollection read fCompCollection write fCompCollection;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents("Stnd", [TMyNewComp]);
end;
{ TCompCollectionItem }
procedure TCompCollectionItem.Notification(AComponent: TComponent; Operation: TOperation);
begin
if (Operation = opRemove) and (AComponent = Comp) then Comp := nil;
end;
{ TMyNewComp }
constructor TMyNewComp.Create(AOwner: TComponent);
begin
inherited;
fCompCollection := TCollection.Create(TCompCollectionItem);
end;
destructor TMyNewComp.Destroy;
begin
inherited;
end;
procedure TMyNewComp.Notification(AComponent: TComponent; Operation: TOperation);
var N: Integer;
begin
inherited;
for N := 0 to CompCollection.Count -1 do
TCompCollectionItem(CompCollection.Items[N]).Notification(AComponent,Operation);
end;
procedure TMyNewComp.Paint;
begin
inherited;
end;
end.
Подозреваю, что у TCompCollectionItem нужно Create перекрыть, где создавать поле FComp... Но наверное собака в другом месте закопана.
PS DimaBr Огромное, тебе, спасибо за старание помочь
← →
RASkov (2006-09-28 02:13) [54]Методами тыка апстенку :), сделал вывод, что виснет все из-за метода TMyNewComp.Notification, так же понял, что редактр свойства ненужен :)
Отсюда вопрос: для чего нужен Notification? Т.е. как его исправить? Я понял, что он вызывается при вставке/удаления "объектов классов"
и так же понял что ошибка при обращении к CompCollection в методе Notification. И почему, если сделать вот так,procedure TMyNewComp.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
ShowMessage(AComponent.ClassName);
end;
то при добавлении/удалении либого (или многих, на всех не проверял:) компанента вылазит сообщение с именем его класса.
Что будет если убрать эти методы из моих классов?
← →
Юрий Зотов © (2006-09-28 07:43) [55]> берем ПаинтБокс кидаем на "голую" форму, кидаем туда пару, тройку моих
> компанентов и в их свойстве указываем один и тот же контрол ПаинтБокс,
> и вот они (мои компаненты) выводили бы каждый в определенных
> координатах свои пункты меню.
Практически то же самое делают плавающие тулбары. Чем не устраивают?
← →
DimaBr (2006-09-28 08:44) [56]
> Что будет если убрать эти методы из моих классов?
Если убрать метод нотификации, то при удалении компонента на который будет ссылаться ваш контрол получим битую ссылку.
destructor TMyNewComp.Destroy;
begin
FreeAndNil(fCompCollection);
inherited;
end;
procedure TMyNewComp.Notification(AComponent: TComponent; Operation: TOperation);
var N: Integer;
begin
inherited;
if CompCollection <> nil then
for N := 0 to CompCollection.Count -1 do
TCompCollectionItem(CompCollection.Items[N]).Notification(AComponent,Operation);
end;
← →
DimaBr (2006-09-28 08:53) [57]В принципе, возвращаясь к старому, есть такой компонент, который рисует своё виденье мира на любом WinControl-е, естественно этот контрол уже теряет свою функциональность, это чудо называется TMediaPlayer.
← →
Юрий Зотов © (2006-09-28 10:39) [58]
type
TYzMenuManager = class;
TYzMenuCollection = class;
TYzMenuCollectionItem = class(TCollectionItem)
private
FItemCaption: string;
FItemChecked: boolean;
FItemEnabled: boolean;
FItemMenu: TPopupMenu;
FLeft: integer;
FTop: integer;
procedure SetItemCaption(const Value: string);
procedure SetItemChecked(const Value: boolean);
procedure SetItemEnabled(const Value: boolean);
procedure SetItemMenu(const Value: TPopupMenu);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); dynamic;
procedure AssignTo(Dest: TPersistent); override;
function GetDisplayName: string; override;
function GetManager: TYzMenuManager;
public
constructor Create(Collection: TCollection); override;
procedure ShowMenu;
published
property ItemCaption: string read FItemCaption write SetItemCaption;
property ItemChecked: boolean read FItemChecked write SetItemChecked default False;
property ItemEnabled: boolean read FItemEnabled write SetItemEnabled default True;
property ItemMenu: TPopupMenu read FItemMenu write SetItemMenu;
property Left: integer read FLeft write FLeft default 0;
property Top: integer read FTop write FTop default 0;
end;
TYzMenuCollection = class(TOwnedCollection)
protected
procedure Update(Item: TCollectionItem); override;
procedure Notification(AComponent: TComponent; Operation: TOperation); dynamic;
public
function GetManager: TYzMenuManager;
function GetMenuItem(Index: integer): TYzMenuCollectionItem;
end;
TYzMenuManager = class(TComponent)
private
FControl: TControl;
FMenuCollection: TCollection;
FMainMenu: TPopupMenu;
procedure SetControl(const Value: TControl);
procedure SetMenuCollection(const Value: TCollection);
procedure MainMenuItemClick(Sender: TObject);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure UpdateMainMenu;
property MainMenu: TPopupMenu read FMainMenu;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetMenuCollection: TYzMenuCollection;
published
property Control: TControl read FControl write SetControl;
property MenuCollection: TCollection read FMenuCollection write SetMenuCollection;
end;
{ TYzMenuCollectionItem }
procedure TYzMenuCollectionItem.AssignTo(Dest: TPersistent);
begin
if Dest is TYzMenuCollectionItem then
with TYzMenuCollectionItem(Dest) do
begin
Collection.BeginUpdate;
try
ItemCaption := Self.ItemCaption;
ItemMenu := Self.ItemMenu;
Index := Self.Index;
Left := Self.Left;
Top := Self.Top
finally
Collection.EndUpdate
end
end
else
inherited
end;
constructor TYzMenuCollectionItem.Create(Collection: TCollection);
begin
inherited;
FItemEnabled := True
end;
function TYzMenuCollectionItem.GetDisplayName: string;
begin
Result := FItemCaption
end;
function TYzMenuCollectionItem.GetManager: TYzMenuManager;
begin
Result := TYzMenuCollection(Collection).GetManager
end;
procedure TYzMenuCollectionItem.Notification(AComponent: TComponent; Operation: TOperation);
begin
if (Operation = opRemove) and (AComponent = FItemMenu) then
FItemMenu := nil
end;
procedure TYzMenuCollectionItem.SetItemCaption(const Value: string);
begin
if not AnsiSameStr(Value, FItemCaption) then
begin
FItemCaption := Value;
Changed(False)
end
end;
procedure TYzMenuCollectionItem.SetItemChecked(const Value: boolean);
begin
if FItemChecked <> Value then
begin
FItemChecked := Value;
Changed(False)
end
end;
procedure TYzMenuCollectionItem.SetItemEnabled(const Value: boolean);
begin
if FItemEnabled <> Value then
begin
FItemEnabled := Value;
Changed(False)
end
end;
procedure TYzMenuCollectionItem.SetItemMenu(const Value: TPopupMenu);
begin
if FItemMenu <> Value then
begin
if FItemMenu <> nil then
FItemMenu.RemoveFreeNotification(GetManager);
FItemMenu := Value;
if FItemMenu <> nil then
FItemMenu.FreeNotification(GetManager)
end
end;
procedure TYzMenuCollectionItem.ShowMenu;
var
SavePopupComponent: TComponent;
P: TPoint;
begin
if (GetManager.Control <> nil) and (FItemMenu <> nil) then
begin
SavePopupComponent := FItemMenu.PopupComponent;
FItemMenu.PopupComponent := GetManager.Control;
try
P := GetManager.Control.ClientToScreen(Point(Left, Top));
FItemMenu.Popup(P.X, P.Y)
finally
FItemMenu.PopupComponent := SavePopupComponent
end
end
end;
{ TYzMenuCollection }
function TYzMenuCollection.GetManager: TYzMenuManager;
begin
Result := TYzMenuManager(GetOwner)
end;
function TYzMenuCollection.GetMenuItem(Index: integer): TYzMenuCollectionItem;
begin
Result := TYzMenuCollectionItem(Items[Index])
end;
procedure TYzMenuCollection.Notification(AComponent: TComponent; Operation: TOperation);
var
i: integer;
begin
for i := 0 to Count - 1 do
GetMenuItem(i).Notification(AComponent, Operation)
end;
procedure TYzMenuCollection.Update(Item: TCollectionItem);
begin
inherited;
GetManager.UpdateMainMenu
end;
{ TYzMenuManager }
constructor TYzMenuManager.Create(AOwner: TComponent);
begin
inherited;
FMainMenu := TPopupMenu.Create(Self);
FMenuCollection := TYzMenuCollection.Create(Self, TYzMenuCollectionItem)
end;
type
TFriendControl = class(TControl);
destructor TYzMenuManager.Destroy;
begin
if FControl <> nil then
TFriendControl(FControl).PopupMenu := nil;
FMenuCollection.Free;
inherited
end;
function TYzMenuManager.GetMenuCollection: TYzMenuCollection;
begin
Result := TYzMenuCollection(FMenuCollection)
end;
procedure TYzMenuManager.MainMenuItemClick(Sender: TObject);
begin
GetMenuCollection.GetMenuItem(TMenuItem(Sender).MenuIndex).ShowMenu
end;
procedure TYzMenuManager.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (FMenuCollection <> nil) and not (csDestroying in ComponentState) then
begin
if (Operation = opRemove) and (AComponent = FControl) then
FControl := nil;
GetMenuCollection.Notification(AComponent, Operation)
end
end;
procedure TYzMenuManager.SetControl(const Value: TControl);
begin
if FControl <> Value then
begin
if FControl <> nil then
begin
TFriendControl(FControl).PopupMenu := nil;
FControl.RemoveFreeNotification(Self);
end;
FControl := Value;
if FControl <> nil then
begin
FControl.FreeNotification(Self);
TFriendControl(FControl).PopupMenu := FMainMenu
end
end
end;
procedure TYzMenuManager.SetMenuCollection(const Value: TCollection);
begin
FMenuCollection.Assign(Value)
end;
procedure TYzMenuManager.UpdateMainMenu;
var
i: integer;
begin
FMainMenu.Items.Clear;
for i := 0 to FMenuCollection.Count - 1 do
with GetMenuCollection.GetMenuItem(i) do
FMainMenu.Items.Add(NewItem(ItemCaption, 0, ItemChecked, ItemEnabled, MainMenuItemClick, -1, ""))
end;
end.
← →
Юрий Зотов © (2006-09-28 10:41) [59]Забыл - в AssignTo надо добавить присвоение ItemChecked и ItemEnabled.
← →
DimaBr (2006-09-28 10:58) [60]Нет, я думаю что RASkov хочет отрисовывать меню на контроле, а не POPUP.
> TFriendControl(FControl).PopupMenu := nil;
> TFriendControl(FControl).PopupMenu := FMainMenu
Жестоко, как мне кажется.
← →
RASkov (2006-09-28 13:26) [61]Спасибо Вам огромное.
С предложением DimaBr [50] и примером из [52] совсем отпала необходимость использования стороннего контрола для отрисовки элементов меню. Вы наверное не уловили ход моих мыслей, за что мои извинения. Дело в том что, теперь ни надо свойство из сабжа. Т.е. берем за основу TGaphicControl или TPaintBox (на мой взгляд даже лучше), добавляем некоторые свойства и в их числе будет CollectionMenu : TCollection, элементами которой (коллекции) будут непосредственно "мои первоночальные компаненты" т.е. теперь просто класс используемый новым компанентом.
Т.е. примерно должно получится нечто вроде этого: кидаю на форму новый "мой" компанент - он приобретает Align - alClient по отношению к Parent"у, добавляю в коллекцию CollectionMenu необходимое кол-во элементов (не элементов меню) и соответственно их настраиваю, что бы они рисовали свои пункты (рисунками, картинками или просто разным цветом) меню в определенных координатах и при необходимости (будет опционально, что то типа ShowCaptions) выводили текст и все это на владельце CollectionMenu т.е. на PaintBox если от него плясать (грубо на этом новом компаненте).
Код Ю. Зотова наверное не совсем подходит, но там очень много полезного, огромное спасибо Вам, Юрий.
> [56] DimaBr (28.09.06 08:44)
>
> > Что будет если убрать эти методы из моих классов?
>
> Если убрать метод нотификации, то при удалении компонента
> на который будет ссылаться ваш контрол получим битую ссылку.
Похоже сдесь тоже проблема решена, так как при удалении этого контрола - удалится и вся "коллекция" рисующая на нем :)
Я вот подумал, что тот код, который привел в [53], немного переделать и сделать Мой первоначальный компанент в качестве TCollectionItem
Т.е. нечто так:TMyClick = procedure MyClick(Sender: TObject; var NItem: Integer) of object; //не уверен, что написал верно, приду вечером домой в Delph"ях разберусь.
Ну вот вроде и все... вечером приду домой буду пробовать.
TPicMenuItem = class(TCollectionItem )
....
published
property OnClick: TMyClick;
end;
//это не 1 пункт меню, а одно меню со своими элементами меню.
TCollectionMenu = class(TCollection);
TPicMenu = class(TPaintBox)
FCollectMenu: TCollectionMenu;
.....
end;
вот как будет выглядеть это все:----------------------------------------------------------------
|
| 1111111 11111111 1111111 11111111
|
|
| 222222 33333 33333 33333
| 222222
| 222222
| 222222 44444
|
где в моем компаненте в свойстве CollectMenu будут четыре меню каждый будет рисовать свои пункты первый - 1, второй - 2 и т.д.
Еще раз спасибо Вам огромное.
P/S Если чего нибудь не получится, ничего если я в этой ветке буду спрашивать...
← →
DimaBr (2006-09-28 13:49) [62]
> Похоже сдесь тоже проблема решена, так как при удалении
> этого контрола - удалится и вся "коллекция" рисующая на
> нем :)
Вы не так поняли. Это нужно для удаления компонента на который ссылается ваш PaintBox. Удалили компонент, PaintBox получил сообщение об удалении и передал сообщение каждому элементу коллекции, которые и проверяют не порали удалить битую ссылку.
> P/S Если чего нибудь не получится, ничего если я в этой
> ветке буду спрашивать...
Ничо... :)))
← →
RASkov (2006-09-28 16:15) [63]
> DimaBr (28.09.06 13:49) [62]
> Вы не так поняли. Это нужно для удаления компонента на который
> ссылается ваш PaintBox. Удалили компонент, PaintBox получил
> сообщение об удалении и передал сообщение каждому элементу
> коллекции, которые и проверяют не порали удалить битую ссылку.
>
Чето я туплю :( извеняюсь.... может неправильно написал
> так как при удалении этого контрола - удалится и вся "коллекция"
> рисующая на нем :)
Контрол на котором будут рисовать CollectionItems"ы - это же все один компанент (TNewPaintBox), и цитату выше читать следует так: так как при удалении этого моего компанента - удалится и вся "коллекция"
Если удалить "контейнер" (Контрол на котором находится мой TNewPaintBox:) с моим компанентом то, я так понимаю, он (контейнер, например TPanel или TForm) автоматом грохнет мой компанент, а тот в свою очередь поубивает и итемы из коллекции...
Т.е. другими словами у меня теперь в компаненте нет ссылки на другие контролы... Единственное, теперь нужно как то передавать канву Обладателя КоллектионИтемов (TNewPaintBox - разр. комп.) самим итемам, что бы те, в свою очередь, рисовали на ней. Попробую дома разобраться с этим. Вот вроде так... Сами же предложили отказаться от внешнего холста :)... Или я опять непонял [62] :( Спасибо.
← →
RASkov (2006-09-28 16:24) [64]Смысл этих строк
> P/S Если чего нибудь не получится, ничего если я в этой
> ветке буду спрашивать...
Ничо... :)))
в том, что отказавшись от дополнительно контрола в свойстве компанента, я немного ушел от темы (сабжа) и поидее нужно создовать новую тему, и поэтому так спросил.
Ничо... :))) сенькс ;)
← →
DimaBr (2006-09-28 16:33) [65]Всё опять неверно. У вас два компонента - PaintBox и тот который на нём рисует. В PaintBox-e ссылка в коллекции на внешний компонент и в методе Paint мы предоставляем свою канву дря рисования второму компоненту. Если этот второй компонент удалить, куда будет ссылаться элемент коллекции PaintBoxa ?
← →
RASkov (2006-09-28 17:19) [66]
> У вас два компонента
Воо как... А я планировал сделать все в одном компаненте на основе ПаинтБокса, добавить ему этих итемов, которые на нем (ПаинтБоксе) и будут рисовать. Ну типа как у TTable свойство Fields. Если грохнуть таблицу то и Field"ы все умрут.... Или мы разговариваем на разных языках :( Или я воопще тупю :(У вас два компонента - PaintBox и тот который на нём рисует
- как понять эту строку - в IDE устанавливаются два самостоятельных компанента, или же ПаинтБокс содержит в себе "тот который на нём"
> Если этот второй компонент удалить, куда будет ссылаться
> элемент коллекции PaintBoxa ?
Я же так понимаю элемент коллекции и будет рисовать на паинте... и при его удалении нужно только перерисовать паинт.
Или я никак не вникну в Коллекции и их КоллектионИтемы, к сожалению :(
Ухх.. нелегкая эта работа.....:)
← →
RASkov (2006-09-28 17:24) [67]> Если этот второй компонент удалить, куда будет ссылаться
> элемент коллекции PaintBoxa ?
Т.е. при добавлении элемента, ему подсовывается канвас того ПаинтБокса, которому и добавляем этот элемент. И усе... удалили элемент, перерисовали паинт и ок:) ИМХО.
← →
Юрий Зотов © (2006-09-28 20:17) [68]> DimaBr (28.09.06 10:58) [60]
Ничего жестокого. Юзер хочет привязать к контролу не меню, а коллекцию меню - он ее и привязывает. Что хочет - то и получает.
← →
RASkov (2006-09-28 23:57) [69]> [68] Юрий Зотов © (28.09.06 20:17)
Юрий, извеняюсь, но мне попап вооще не нужен был:)
> Юзер хочет привязать к контролу не меню
Вообще хотел привязать к контролу свой компанент т.е. наоборот, контрол к моему компаненту но пункты меню рисовать самому т.е. выводить их ввиде картинок в определенном TRect"е. И надобность в контроле, насителе канвы, вроде отпала уже. Спасибо [50] DimaBr.
Извеняюсь еще раз, если что не в тему.
← →
DimaBr (2006-09-29 08:44) [70]
> А я планировал сделать все в одном компаненте на основе ПаинтБокса
Тогда просто супер !!! А я всё живу прошлой жизнью, где присутствовало два компонента - рисующий и подопытный.
← →
Наиль © (2006-09-29 09:13) [71]> TCollectionMenu = class(TCollection);
>
> TPicMenu = class(TPaintBox)
> FCollectMenu: TCollectionMenu;
> .....
> end;
Здесь notification не нужен.
> Ну типа как у TTable свойство Fields. Если грохнуть таблицу
> то и Field"ы все умрут....
А здесь нужен. Fields - NonVisual-компоненты. Присутствуют в dfm и pas файлах. Откуда их легко удалить. Со всеми вытекающими последствиями.
В общем нотификация нужна всегда, если компонент на который имеется ссылка может быть удалён без твоего ведома.
← →
Наиль © (2006-09-29 09:37) [72]
> Где, как отловить/перекрыть момент заполнения списка поля
> CanvasControlsType
TMyPropertyEditor=class(TComponentProperty)
private
InspectorProc:TGetStrProc;
procedure MyProc(const S: string);
public
procedure GetValues(Proc: TGetStrProc); override;
End;
{ TMyPropertyEditor }
procedure TMyPropertyEditor.GetValues(Proc: TGetStrProc);
begin
InspectorProc:=Proc;
Designer.GetComponentNames(GetTypeData(GetPropType), MyProc);
end;
procedure TMyPropertyEditor.MyProc(const S: string);
Var
Compon:TComponent;
begin
Compon:=Designer.GetComponent(S);
if Compon=nil then Exit;
if not (Compon is TControl) then Exit;
if (Compon as TControl).Width<200 then InspectorProc(S)
end;
Этот код не точный, возможно не верный. Предназначен лишь для того, чтобы показать, как фильтруются списки в свойствах. В данном случае в список должны попасть лишь те контролы, которые имеют ширину меньше 200.
Естествено, данный редактор свойства нужен зарегестрировать соотвествующим образом.
← →
RASkov (2006-09-29 13:34) [73]Короче, Спасибо Вам всем. На данный момент попробовать чего либо не могу так как нахожусь в другом нас. пункте. завтра к вечеру буду и обязательно попробую разные варианты. Учиться... учиться... и еще раз учиться © Ленин
[70] DimaBr (29.09.06 08:44) - если обидел чем извеняюсь. Трудно на форуме изложить свои мысли, чёбы другие поняли и высказать правильно :)
← →
RASkov (2006-09-30 22:39) [74]Вот вернулся к своему компаненту и задумался - сюда запостить или в новую ветку... решил пока сюда.
Вот что получилось (код компанента ниже), на данный момент пока "скелет" компанета. Код "рабочий", по крайней мере без явных ошибок работает в дизайнтайме т.е. без AV.
Я вот в таком виде его хочу показать Вам, и если Вам не трудно, посмотрите, на правильном я направлении или нет. Меня вот интересуют нотификации (Notification) - у меня они походу для понта здесь. Вот мне хочется узнать нужны ли они в данных моих компанентах? Я в них(Notification) чето никак не въеду:(.
И если нетрудно, ответьте на вопросы:
1) Как из объектов TPicMenuCollectionItem достучаться до TPicMenus? (хотелось бы вызывать перерисовку (Invalidate) при изменении свойств);
2) Каким образом лучше обрабатывать мышь (Enter/Leave/Click элементов меню)? Элементы меню планирую хранить как TRect в поле FItemsMenu в его Object, т.е. сейчас пока присваение так FItemsMenu.Assign(Value); потом хочу переделать с добавлением областей (Rect"ов), ченить типа так (только что здесь придумал, пока писАл)
R:=Rect(<расчитываем область>);
FItemsMenu.AddObject(Value[i], TObject(@R));
(это ни суть, здесь придумаю как их туда засунуть)
Вопрос наверное кем эфективнее обрабатывать - TPicMenuCollectionItem или TPicMenus? Я сам склоняюсь к TPicMenus, т.к. кое-какие махинации с мышью уже реализованы ГрафикКонтролом... И ченить типа
for N:=0 to FItemsMenu-1 do
if PtInRect(TRect(FItemsMenu.Object(N)), Point(X,Y)) then ..
end;
на TPicMenus.MouseMove но... как-то некрасиво... низнаю пока.
Ну вот пока вроде все, следом код (хотел повырезать ненужное но на всяк оставил целиком)
← →
RASkov (2006-09-30 22:39) [75]
unit PicMenu;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Dialogs;
type
TPicMenus = class;
TMenuCollection = class(TCollection);
TOrientationMenu = (omVert, omHoriz);
TPicMenuCollectionItem = class(TCollectionItem)
private
FPicture: TPicture;
FBitMap: TBitMap;
// FCanvas: TCanvas;
FCountMenu: Integer;
FShowCaptions: Boolean;
FItemsMenu: TStrings;
FMenuTop: Integer;
FMenuWidth: Integer;
FMenuLeft: Integer;
FMenuHeight: Integer;
FSpacing: Byte;
FOrientation: TOrientationMenu;
function GetCountMenu: Integer;
procedure SetMenuHeight(const Value: Integer);
procedure SetItemsMenu(const Value: TStrings);
procedure SetMenuLeft(const Value: Integer);
procedure SetMenuTop(const Value: Integer);
procedure SetMenuWidth(const Value: Integer);
procedure SetPicture(const Value: TPicture);
procedure SetShowCaptions(const Value: Boolean);
procedure SetCountMenu(const Value: Integer);
procedure SetSpacing(const Value: Byte);
procedure SetOrientation(const Value: TOrientationMenu);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); dynamic;
function GetPicMenus: TPicMenus;
procedure DrawItems(Cnv: TCanvas);
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
published
property CountMenu: Integer read GetCountMenu write SetCountMenu;
property ItemsMenu: TStrings read FItemsMenu write SetItemsMenu;
property MenuHeight: Integer read FMenuHeight write SetMenuHeight default 14;
property MenuWidth: Integer read FMenuWidth write SetMenuWidth default 50;
property MenuLeft: Integer read FMenuLeft write SetMenuLeft default 10;
property MenuTop: Integer read FMenuTop write SetMenuTop default 10;
property Orientation: TOrientationMenu read FOrientation write SetOrientation default omVert;
property Picture: TPicture read FPicture write SetPicture;
property ShowCaptions: Boolean read FShowCaptions write SetShowCaptions default True;
property Spacing: Byte read FSpacing write SetSpacing default 5;
end;
TPicMenus = class(TGraphicControl)
private
FMenuCollection: TMenuCollection;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property MenuCollection: TMenuCollection read FMenuCollection write FMenuCollection;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents("Stnd", [TPicMenus]);
end;
{ TPicMenuCollectionItem }
constructor TPicMenuCollectionItem.Create(Collection: TCollection);
begin
inherited Create(Collection);
FPicture:=TPicture.Create;
FBitMap:=TBitMap.Create;
FItemsMenu:=TStringList.Create;
FMenuHeight:=14;
FMenuTop:=10;
FMenuLeft:=10;
FMenuWidth:=50;
//FCanvas:=ACanvas;
FShowCaptions:=True;
FSpacing:=5;
end;
destructor TPicMenuCollectionItem.Destroy;
begin
FPicture.Free;
FBitMap.Free;
FItemsMenu.Free;
inherited;
end;
procedure TPicMenuCollectionItem.DrawItems(Cnv: TCanvas);
var N: Integer; R: TRect;
begin
Cnv.Pen.Style:=psSolid;
Cnv.Pen.Width:=1;
for N:=0 to FCountMenu-1 do begin
case Orientation of
omVert: R:=Rect(FMenuLeft, FMenuTop+N*(FMenuHeight+FSpacing), FMenuLeft+FMenuWidth, FMenuTop+FMenuHeight+N*(FMenuHeight+FSpacing));
omHoriz: R:=Rect(FMenuLeft+N*(FMenuWidth+FSpacing), FMenuTop, FMenuLeft+FMenuWidth+N*(FMenuWidth+FSpacing), FMenuTop+FMenuHeight);
end;
Cnv.Rectangle(R);
{ if csDesigning in ComponentState then Cnv.TextRect(R, R.Left, R.Top, ItemsMenu[N]+"dsgmode")
else Cnv.TextRect(R, R.Left, R.Top, ItemsMenu[N]);}
if FShowCaptions then Cnv.TextRect(R, R.Left, R.Top, ItemsMenu[N]);
end;
end;
function TPicMenuCollectionItem.GetCountMenu: Integer;
begin
FCountMenu:=FItemsMenu.Count;
Result:=FCountMenu;
end;
function TPicMenuCollectionItem.GetPicMenus: TPicMenus;
begin
Result:=nil;
end;
procedure TPicMenuCollectionItem.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
end;
procedure TPicMenuCollectionItem.SetCountMenu(const Value: Integer);
begin
FCountMenu := FItemsMenu.Count;
end;
procedure TPicMenuCollectionItem.SetMenuHeight(const Value: Integer);
begin
FMenuHeight := Value;
end;
procedure TPicMenuCollectionItem.SetItemsMenu(const Value: TStrings);
begin
FItemsMenu.Assign(Value);
end;
procedure TPicMenuCollectionItem.SetMenuLeft(const Value: Integer);
begin
FMenuLeft := Value;
end;
procedure TPicMenuCollectionItem.SetMenuTop(const Value: Integer);
begin
FMenuTop := Value;
end;
procedure TPicMenuCollectionItem.SetMenuWidth(const Value: Integer);
begin
FMenuWidth := Value;
end;
procedure TPicMenuCollectionItem.SetPicture(const Value: TPicture);
begin
FPicture := Value;
end;
procedure TPicMenuCollectionItem.SetShowCaptions(const Value: Boolean);
begin
FShowCaptions := Value;
end;
procedure TPicMenuCollectionItem.SetSpacing(const Value: Byte);
begin
FSpacing := Value;
end;
procedure TPicMenuCollectionItem.SetOrientation(const Value: TOrientationMenu);
begin
FOrientation := Value;
end;
{ TPicMenus }
constructor TPicMenus.Create(AOwner: TComponent);
begin
inherited;
FMenuCollection := TMenuCollection.Create(TPicMenuCollectionItem);
Align:=alClient;
end;
destructor TPicMenus.Destroy;
begin
FMenuCollection.Free;
inherited
end;
procedure TPicMenus.Notification(AComponent: TComponent; Operation: TOperation);
var N: Integer;
begin
inherited Notification(AComponent, Operation);
if (FMenuCollection <> nil) and not (csDestroying in ComponentState) then
for N := 0 to FMenuCollection.Count -1 do
TPicMenuCollectionItem(MenuCollection.Items[N]).Notification(AComponent, Operation);
end;
procedure TPicMenus.Paint;
var N: Integer;
begin
Canvas.Font := Font;
Canvas.Brush.Color := Color;
if csDesigning in ComponentState then
with Canvas do begin
Pen.Width:=1;
Pen.Style := psDash;
Brush.Style := bsClear;
Rectangle(0, 0, Width, Height);
end;
for N := 0 to FMenuCollection.Count -1 do
TPicMenuCollectionItem(MenuCollection.Items[N]).DrawItems(Self.Canvas);
end;
end.
Спасибо тому, кто это дело не пропустит... пусть даже будет критик... обаснованный:)
ЗЫ Очень надеюсь на Ваши "пинки".
← →
RASkov (2006-10-01 16:59) [76]> (это ни суть, здесь придумаю как их туда засунуть)
Пока не придумал :)
← →
DimaBr (2006-10-02 09:59) [77]
> Меня вот интересуют нотификации (Notification)
Нотификация нужна для уведомления о добавлении/удалении компонентов формы. Если вы обрабатываете это движение в компоненте - то нужны. Искуственно можно передать нотификацию в коллекцию и вложенные компоненты/персистенты
1. Как достучатся?
function TPicMenuCollectionItem.GetPicMenus: TPicMenus;
begin
Result := TPicMenus(Collection.Owner);
end;
По поводу кода:
1. В принципе нет необходимости рисовать в элементах коллекции (тогда речь шла о двух компонентах), можно рисовать в методе Paint используя свойства коллекции.
2. Во все методы Set.. элементов коллекции добавить GetPicMenus.Invalidate для перерисовки родителя при изменении свойства элемента коллекции
3. Строчка "Align:=alClient" с конструкторе мне не нравится, потому что не хочу чтобы компонент занимал всю область. Повысить видимость Align до Published.
4. В нотификации необходимости нет.
5. TMenuCollection = class(TCollection); лучше заменить на TMenuCollection = class(TOwnedCollection);
← →
RASkov (2006-10-02 14:39) [78]
> DimaBr (02.10.06 09:59) [77]
> function TPicMenuCollectionItem.GetPicMenus: TPicMenus;
> begin
> Result := TPicMenus(Collection.Owner);
> end;
Уже сделал...
1 - 50 на 50 - в данном коде реализована общая прорисовка элементов меню, потом хотел сделать что то типа:procedure TPicMenuCollectionItem.DrawItems;
var N: Integer;
begin
...
for N:=0 to FCountMenu-1 do begin
DrawItem(N, ItemState);
end;
end;
2 - реолизовал
3 - спорный вопрос - ближе к концу решится, есть некоторые факты в пользу alClient - пока оставим так.
4 - спасибо. удалю нафик всю :)
5 - Чем лучше? Т.е. чем мне здесь может это помочь? Хотя уже вроде начал вникать в эти коллекции может сам допру.
И мне бы хотелось узнать - можно какимнить образом из элемента TPicMenuCollectionItem свой индекс в коллекции передать в TPicMenus?
т.е при пересчете Rect"ов передать в TPicMenus номер изменившегося TPicMenuCollectionItem? И как работу с мышью лучше организовать?
Спасибо.
← →
DimaBr (2006-10-02 16:10) [79]
> можно какимнить образом из элемента TPicMenuCollectionItem
> свой индекс в коллекции передать в TPicMenus
Легко
TPicMenus = class(TGraphicControl)
private
procedure ChangeRect(IndexCollection: integer);
end;
procedure TPicMenuCollectionItem.SetMenuHeight(const Value: Integer);
begin
FMenuHeight := Value;
GetPicMenus.ChangeRect(Index);
end;
> И как работу с мышью лучше организовать?
Лучше всего организовать правильно, иначе плохо будет работать :)))
← →
RASkov (2006-10-02 16:33) [80]
> DimaBr (02.10.06 16:10) [79]
Спасибо за индех. То что надо.
> Лучше всего организовать правильно, иначе плохо будет работать
> :)))
Это понятно.... :) я имел ввиду обработать OnMove и PtInRect() или еще как? и на 5 - ?
← →
DimaBr (2006-10-02 17:02) [81]
> я имел ввиду обработать OnMove и PtInRect() или еще как?
Да, естественно, только не OnMove, а procedure MouseMove(Shift: TShiftState; X, Y: Integer);override;
> 5 - Чем лучше?
Тем что в OwnedCollection уже реализован GetOwner и гораздо удобнее динамически менять класс элементов коллекции (хотя в вашем случае в этом не необходимости)
← →
RASkov (2006-10-04 02:52) [82]DimaBr, Вот еще такокой вот вопрос попробую сформулировать...
Как отловить в дизайнтайме выделение/выбор-невыбор itema в редакторе TCollection в инсп. объектов. (ниже конкретней попробую описать) Если это возможно конечно, я думаю возможно, но если это сложно то отставить пока.
Вообщем идея такая когда выделяю на форме свой компанент и жму кнопку[...] в поле MenuCollection - то открывается редактор этого поля - так вот хотелось бы при выборе элемента в коллекции (именно в дизайнтайме) группа итемов меню этого элемента, которые рисуются на канве вертикально или горизонтально, обводились пунктир. прямоугольником ну или еще как выделялись бы. Т.е. когда их (эл. коллекции) штуки 3 и более при выборе различать где он свои итемы рисует... Вот. Если вопрос не понятен, то не судьба мне...:( все равно спасибо.
← →
DimaBr (2006-10-04 09:19) [83]Не знаю точно, но думаю что со стандартным редактором ничего не выйдет.
Я бы ввёл в элемент коллекции свойство DesignerSelected: boolean и написал свой редактор для коллекции, который изменяет это свойство. А отрисовка уже просто. Вы можете написать свой редактор ?
← →
RASkov (2006-10-04 10:32) [84]
> Вы можете написать свой редактор ?
Я пока даже и незнаю что и ответить. Впервой с написанием компанентов и ихими "причендалами". А почему не смогу - смогу, но только потом:). По всей видимости пока отставить в эту сторону. Сейчас нужно немного доделать (на данный момент компанент умеет себя рисовать) функционал компанета а там посмотрим....
Ну я так понял, что не совсем просто это [82].
А вот при удалении элемента коллекции нужно перерисовать компанент - я так думаю нужно перекрыть метод коллекции (TOwnedCollection - он получше:) чутьчуть) Notify - наверное в перекрытом нужно просто вызвать inherited; и GetOwner.Invalidate; Его параметр (Notify(Item: TColl...Item;...) Item я так думаю не надо ни с кем сравнивать?
← →
DimaBr (2006-10-04 11:18) [85]Не знаю, отрабатывает ли Notify в дизайнере, можно и в TPicMenuCollectionItem.Destroy;
procedure TPicMenuCollectionItem.Destroy;
var AOwner: TPicMenus;
begin
AOwner := GetPicMenus;
inherited Destroy;
AOwner.Invalidate
end;
← →
RASkov (2006-10-04 14:02) [86]Блин, почему мне такая мысль не пришла на ум, ведь элементарно ж:)
DimaBr, незнаю уже как и благодарить.... постараюсь "мелочные" вопросы в этой ветке больше не спрашивать. Спасибо.
← →
RASkov (2006-10-08 15:53) [87]Вот такой вот вопрос - добавил свойство:
property FileSoundEnter: TFileName read FFileSoundEnter write SetFileSoundEnter;
ну и такое же для Leave.
как можно задать фильтр в диалоговом окне выбора файлов когда в инспекторе щелкаем [...] кнопку?
Или это опять ужасно сложно?
На данный момент компанент почти готов осталось реализовать клики по итемам, думаю с этим справлюсь. А прикольный получается компанентик:)
А реально ли в компаненте использовать библиотеку, к примеру BASS? (само собой эту версию BASS распростронять с компанентом), или никчему это.
Хотел сделать (т.е. уже сделал) звуки на смену итемов, ну и само собой есть свойство UseSound которое запрещает звуки.
Доделаю полностью выложу - но только в скомпелированном виде (стыдно за код:|) постараюсь с ридмиком, но если кого заинтересует.... хотя врядли, писал его для себя и в целях обучения:) DimaBr если нужно код - без разговора:)
ЗЫ 2 вопросика в посте. Спасибо.
← →
atruhin © (2006-10-08 16:20) [88]Создать свой PropertyEditor в твоем варианте не сложно.
← →
RASkov (2006-10-08 17:36) [89]> как можно задать фильтр в диалоговом окне выбора файлов
> когда в инспекторе щелкаем [...] кнопку?
Блин, щас вот второй раз прочитал... короче вот:
в published добавил вышеописанное свойство - в инспекторе для этого свойства прикрутился FileOpenDialog - как задать фильтр на типы файлов которые можно выбрать в нем *.wav;*.mp3... Вооще одного wav"a хватит.
← →
RASkov (2006-10-08 17:41) [90]> [88] atruhin © (08.10.06 16:20)
Да не приходилось никогда иметь дело с PropertyEditor, даже не знаю с какой стороны подойти... Если не трудно в трех словах с кодом - можно рассказать про это нехитрое дело. Создание своих редакторов свойств. Или как это делает например, RxLib, подменяет обычный/стандартный редактор Caption"ов на свой диалог?
← →
atruhin © (2006-10-09 03:49) [91]В двух словах не получится. Найди в сети книгу "Создание оригинальных компонент с среде Delphi 2" Рэй Конопка, там все хорошо описано, с примерами.
← →
DimaBr (2006-10-09 11:12) [92]
TFindFileProperty = class(TStringProperty)
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
end;
{ TFindFilerProperty }
procedure TFindFolderProperty.Edit;
begin
inherited;
with TOpenDialog.Create(nil) do
try
Filter := "*.wav";
if Execute then SetValue(FileName);
finally
Free;
end;{try}
end;
function TFindFolderProperty.GetAttributes: TPropertyAttributes;
begin
Result := inherited GetAttributes + [paDialog];
end;
procedure Register;
begin
...
RegisterPropertyEditor(TypeInfo(string), TMyComponent, "NameProperty", TFindFileProperty);
end;
← →
RASkov (2006-10-09 13:32) [93]> [92] DimaBr (09.10.06 11:12)
Спасибо, помоему ничего сложного, вечером попробую.
procedure Register; я так понимаю одна и для регистрации компанента и свойства. Ну т.е. это все в одном модуле с компанентом писать? ответ наверное: можно но не обязательно. Верно?
А по второму вопросу про "звуки в компаненте"?
← →
DimaBr (2006-10-09 13:52) [94]
> Ну т.е. это все в одном модуле с компанентом писать?
Всё зависит от версии Delphi, для шестёрке и выше - отдельный модуль с регистрацией + DesignIDE.dcp в пакет
← →
RASkov (2006-10-09 14:16) [95]> [94] DimaBr (09.10.06 13:52)
Ух. Понял. У меня D7. А ведь я бы все в одном прикрутил и "заработало" бы:)
т.е. в пакете создать новый модуль в нем описать редактор свойства и добавить еще и DesignIDE.dcp в пакет? DesignIDE.dcp а че в нем? он тай большой. Спасибо.
← →
DimaBr (2006-10-09 15:01) [96]Начиная с шестёрки идёт разделение дизайн кода и Run-Time кода. Вы просто не сможете добавить DesignEditors (в котором описаны редакторы) и скомпилять в одном модуле - будет ругаться - не хватает Proxies.dcu
← →
RASkov (2006-10-09 16:52) [97]
> Начиная с шестёрки идёт разделение дизайн кода и Run-Time
> кода. Вы просто не сможете добавить DesignEditors (в котором
> описаны редакторы) и скомпилять в одном модуле - будет ругаться
> - не хватает Proxies.dcu
Я вот в прочих вопросик задавал - ответа толкового нет. Может есть соображения какие. Вопрос кое каким боком относится к компанентам.
http://delphimaster.net/view/15-1159716860/
и вот из последнего
> Paket и ни в каком другом (пакете) он не already, кроме
> как в тестовом проекте в модуле тестовой формы.....
Даже если и просто один пакет открыть в IDE и ничего более, иногда (даже без явных и неявных ошибках) т.е. проверяешь синтаксис нормально (не хинтов не варнингов ни errorов), произведешь несущественное изменение (сотрешь буковку и ее же напишешь), хочешь опять проверить синтаксис - и тут эта ошибка.:( Спасибо.
← →
RASkov (2006-10-10 01:10) [98]> помоему ничего сложного, вечером попробую.
Спасибо разобрался, минут 10 попарился с регистрацией... с толку сбило TypeInfo(string) у меня то TFileName; (TFileName = type string;)
И я у метода Edit убрал inherited, он ведь в цепочке TFindFileProperty = class(TStringProperty) вызывается непосредственно из TPropertyEditor в котором ничего путевого для OpenDialog не нашел, да еще TStringList там создается к чему то - незнаю... может я и неправ - убрав его.
DimaBr, вот уже я немного вник в редакторы свойст, спасибо большое за [92].
Близится к завершению мой чудо-юдо компанент.
>
И вот еще вопросик: как ограничить установку моего компанента только в D7?
Потому, что делал его в D7, а заморачиваться с дерективами пока нехочу.
Знаю, что это грубое решение... но пока учусь сойдет, тем более для себя его делал. Хотя сам компанент использует
Windows, SysUtils, Classes, Graphics, Controls; У меня нет уверенности, что везде они одинаковые... да еще редактор свойства
SysUtils, DesignIntf, DesignEditors, PicMenu;
То что подчеркнул сомнительные; А может я зря переживаю?
← →
DimaBr (2006-10-10 08:20) [99]
> А может я зря переживаю?
Зря, если не будите устанавливать на < Delphi 6
← →
RASkov (2006-10-10 15:44) [100]> [99] DimaBr (10.10.06 08:20)
Ну дык если кто нить попросит компанент а у него D4 или ниже?
Точнее выложу в инете для "ознакомления" без исходников:) ну и чебы ...
Ведь как то можно вопрос решить?:) Не, ну да ладно, я не сильно за это переживаю:)
← →
RASkov (2006-10-10 15:45) [101]DesignIntf в D4 такого нет помоему, там вроде DsgnInf или че то так.
← →
RASkov (2006-10-10 16:11) [102]> Не, ну да ладно, в данный момент я не сильно за это переживаю:)
Хотя потом нужно будет научится различать версии Delphi....Чебы проблем не было:)
← →
RASkov (2006-10-11 20:34) [103]Вот пару вопросиков появились:
1) можно ли как нибудь объеденять некоторые свойства(разного типа) в группы (т.е. чтоб в инспекторе был + и имя группы), ну типа как у свойства Font только без кнопки диалога? Или же опять редактор нужен, но тут уже походу непросто будет.
2) Как реализовать двойной клик по компаненту в дизайнере, что бы появилось окно свойства TCollection? ну т.е. в инспекторе у свойства типа TCollection есть кнопочка, так вот как даблкликнув по компаненту кликнуть по этой кнопочке?
Вот как сделал, а дальше чето несоображу:(procedure TPicMenusEditor.Edit;
begin
ExecuteVerb(1);
end;
procedure TPicMenusEditor.ExecuteVerb(Index: Integer);
begin
case Index of
0: MessageDlg("Author RASkov 2006"#13"Thanks DimaBr"#13
+"and www.delphimaster.ru", mtInformation, [mbOk], 0);
1: MessageDlg("Unknow edit", mtInformation, [mbOk], 0);
end;
end;
function TPicMenusEditor.GetVerb(Index: Integer): String;
begin
case Index of
0: Result:="&About PicMenus";
1: Result:="&Edit Menu";
end;
end;
function TPicMenusEditor.GetVerbCount: Integer;
begin
Result:=2;
end;
← →
RASkov (2006-10-12 04:13) [104]Кому интересно вот можно посмотреть что получается, в архиве только exe с использованием этого компанента
http://slil.ru/23237676 (610 Kb)
Вот скрин:
http://slil.ru/23237678 (110 Kb)
← →
RASkov (2006-10-12 04:25) [105]Только здесь мнения, просьба не высказывать, если необходимо можно завести ветку в прочих. Дабы эта ветка туда не перекочевала.
[103] в силе вопрос 2
по первому, я так понял, просто не получится.
← →
DimaBr (2006-10-12 08:39) [106]
> 1) можно ли как нибудь объеденять некоторые свойства(разного
> типа) в группы (т.е. чтоб в инспекторе был + и имя группы)
Можно. Это делается так.
TMyGroup = class(TPersistent)
private
fMyProperty: integer;
published
property MyProperty: integer read fMyProperty write fMyProperty;
end;
TMyComponent = class(TComponent)
private
fMyGroup: TMyGroup
published
property MyGroup: TMyGroup read fMyGroup write SetMyGroup;
end;
constructor TMyComponent.Create();
begin
inherited;
fMyGroup := TMyGroup.Create;
end;
destructor;
begin
fMyGroup.Free;
inherited;
end;
> 2) Как реализовать двойной клик по компаненту в дизайнере, что бы появилось окно свойства TCollection?
С позволения Юрия Зотова, выкладываю его творчество.
TColunmEditor = class(TComponentEditor)
private
FPropInfo: PPropInfo;
FPropEdit: IProperty;
procedure GetPropProc(const PropEdit: IProperty);
public
constructor Create(AComponent: TComponent; ADesigner: IDesigner); override;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
function GetPropertyName:string; virtual;
end;
{ TColunmEditor }
// редактор свойства - коллекции (возвращаем имя свойства)
function TColunmEditor.GetPropertyName: string;
begin //
end;
constructor TColunmEditor.Create(AComponent: TComponent; ADesigner: IDesigner);
begin
inherited;
FPropInfo := GetPropInfo(GetComponent.ClassInfo, GetPropertyName, [tkClass])
end;
procedure TColunmEditor.GetPropProc(const PropEdit: IProperty);
begin
if PropEdit.GetPropInfo = FPropInfo then FPropEdit := PropEdit
end;
procedure TColunmEditor.ExecuteVerb(Index: Integer);
var Selections: TDesignerSelections;
begin
case Index of
0: begin
if (FPropEdit = nil) and (FPropInfo <> nil) then begin
Selections := TDesignerSelections.Create;
try
Designer.GetSelections(Selections);
GetComponentProperties(Selections, [tkClass], Designer, GetPropProc)
finally
Selections.Free
end;{try}
end;{if}
if FPropEdit <> nil then FPropEdit.Edit
end
else inherited;
end;{case}
end;
function TColunmEditor.GetVerb(Index: Integer): string;
begin
case Index of
0: Result := GetPropertyName+" Editor...";
else Result := inherited GetVerb(Index);
end;
end;
function TColunmEditor.GetVerbCount: Integer;
begin
Result := inherited GetVerbCount + 1;
end;
← →
DimaBr (2006-10-12 08:50) [107]Что значит "Масштаб надписей" ???
← →
RASkov (2006-10-12 11:56) [108]> [106] DimaBr (12.10.06 08:39)
Спасибо.
> [107] DimaBr (12.10.06 08:50)
Ну это чтоб при масштабировании и текст "надписи"(Caption) тоже масштобировался:)
← →
RASkov (2006-10-12 12:35) [109]Вечером попробую..., вот по первому вопросу я в принципе так и думал что через класс их объеденять нужно, поэтому теперь доступ к непосредственно свойству необходим будет через префикс MyGroup.<бывшее не в группе свойство>:=...; Так ведь? И также я думал что можно и попросче сделать, но наверное так и сделаю.
А вот в ответе на 2 чето немного запутался. GetPropertyName virtual должна вернуть имя свойства т.е. Result:="MenuCollection";?
И Designer.GetSelections(Selections); что, только если будет выделенно свойство откроется редактор? или же это можно заменить на GetComponent(0)? которое возврощает (0) первый компанент из выделенных вроде.
И наверное правельнее будет переписать все в метод Edit; (он же на двойной клик) а в ExecuteVerb - n: Edit;... так вродебы красивее.
← →
DimaBr (2006-10-12 13:03) [110]В конструкторе запоминаем какое свойство ищем (FPropInfo), далее перебираем все свойтства компонента и сравниваем является ли текущее свойство тем самым, которое ищем. Если да то запоминае его (FPropEdit). Далее, если такое свойство нашли, вызываем его редактор (FPropEdit.Edit).
Использование:
TPicMenusEditor = class(TColunmEditor)
function GetPropertyName:string; override;
end;
function TPicMenusEditor.GetPropertyName:string;
begin
Result := "MenuCollection";
end;
procedure Register;
begin
.................
RegisterComponentEditor(TPicMenus,TPicMenusEditor);
end;
Если подразумевается несколько пунктов меню, то перекрываем несколько методов, при этом первый будет - редактирование коллекции
type TPicMenusEditor = class(TColunmEditor)
function GetPropertyName:string; override;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
end;
> или же это можно заменить на GetComponent(0)?
Нет, поскольку допустим мы вибираем сначала например Label, а потом TPicMenus. Тогда у GetComponent(0) свойства MenuCollection нет.
← →
DimaBr (2006-10-12 14:03) [111]
> Ну это чтоб при масштабировании и текст "надписи"(Caption) тоже масштобировался:)
При масштабировании чего ?
← →
Наиль © (2006-10-12 14:37) [112]С утра приготовил ответ на [103], но из-за неполадок с интернет не смог отправить. Т.к. первый вопрос достаточно ясен, то замечу только, что отличным примером является TLabeledEdit.
А вот по второму вопросу (вернее по ответам на него) есть замечания.
В [106]GetComponentProperties(Selections, [tkClass], Designer, GetPropProc)
вызываетGetPropProc
, для всех свойств всех выделеных компонент, следовательноFPropEdit.Edit
будет вызван для последнего найденого свойства, а остальные изменены не будут.
Мой облегчёный вариант (без обработки исключений) предполагает, что двойной клик производится лишь по одному компоненту. Написан по аналогии с генофондом.
Пример запуска текущего редактора свойства Font.procedure Register;
Type
TPanelEdit=class(TDefaultEditor)
private
FFontProp:IProperty;
protected
procedure CheckEdit(const Prop: IProperty);
public
procedure Edit; override;
End;
---------------------------
procedure Register;
begin
RegisterComponentEditor(TPanel,TPanelEdit);
end;
{ TPanelEdit }
procedure TPanelEdit.Edit;
var
Components: IDesignerSelections;
begin
// По аналогии с TDefaultEditor.Edit
Components := TDesignerSelections.Create;
Components.Add(Component);
FFontProp:=nil;
GetComponentProperties(Components, tkProperties, Designer, CheckEdit);
if FFontProp<>nil then FFontProp.Edit;
end;
procedure TPanelEdit.CheckEdit(const Prop: IProperty);
begin
if FFontProp<>nil then Exit;
if SameText(Prop.GetName,"FONT") then FFontProp:=Prop;
После регистрации сделай двойной щелщок по любой панели (TPanel)
← →
DimaBr (2006-10-12 15:49) [113]
> Наиль © (12.10.06 14:37) [112]
Вообще-то, как сейчас испробывал, у меня на D6 DblClick & Popup на двух выбранных компонентах не отрабатывается, поэтому можно голову не морочить и выбирать только первый.
P.S. Да кстати, свойство-коллекция должна быть published
← →
RASkov (2006-10-12 19:26) [114]Незнаю смотрели демку или нет, там (у моего компанента) есть свойство которое отвечает за "масштабирование всего компанента" (раз разговор зашол про масштаб [107], думаю смотрели демку), там есть галочка "Масштабирование", так вот если ее поставить и поменять размеры окна то... будет видно вообщем косяк с надписями.
> P.S. Да кстати, свойство-коллекция должна быть published
Оно published;
-------------------
> > или же это можно заменить на GetComponent(0)?
>
> Нет, поскольку допустим мы вибираем сначала например Label,
> а потом TPicMenus. Тогда у GetComponent(0) свойства MenuCollection
> нет.
Имелось ввиду они оба будут выделены? если так то по идее если сделать двойной клик по одному из выделенных то выделение со всех остальных снимается и производится действие по умолчанию на котором даблкликнули, если кликнуть правой кнопкой - то меню должно пренадлежать тому по которому кликнули а не всей группе. или же отсчет идет от того кого первым выделили?. Спасибо, сейчас буду пробовать все что почерпнул из новых ответов.
DimaBr, Наиль - Oгромное спасибо!
← →
RASkov (2006-10-13 03:27) [115]Ну вот вроде все основное сделал, осталось подрихтовать немного, задействовать некоторые свойства (AllowFixed, AllowAllUp, GroupIndex...) и можно хелп делать:) Спасибо Вам огромное.
А Масштаб надписей... да фик с ним.
С редактором разобрался. Свойства сгрупировал. Если все доделаю то выложу, но только не исходник а скомпилированный (про код см выше 87:)), кстати что для это надо выложить, т.е. для того чтобы установить компанент в Делфи нужна bpl и dcu модули с компанентом и редакторами?, а файл пакета dpk нужен? Сорри за такие вопросы про компаненты - первый мой компанент.
ЗЫ Моргает только зараза, если DoubleBuffered отключить. Но я думаю нужно вместо Invalidate - InvalidateRect прикрутить, все ректы есть в свойствах - только чето не получилось сначала... ну и забросил это гиблое дело.
Еще раз Огромное Спасибо всем кто не бросил меня в этой нелегкой битве:)
← →
RASkov (2006-10-13 03:40) [116]Т.е вот этих файлов достаточно будет для установки?
D7PicMenu.dcu (4 Kb)- хрен его знает, наверное D7PicMenu.dpk скомпилиный
PicMenu.dcu (39 Kb)- модуль с компанентом
PropEditPicMenu.dcu - модуль с редакторами
PicMenu.dcr (2 Kb)- иконка
D7PicMenu.bpl (48 Kb)- пакет
D7PicMenu.dcp (46 Kb)- хрен его знает, большой однако
там вот еще res, dof, cfg и dpk - они нужны?
подзабыл я стандартные расширения делфевые что в чем лежит, pas, dfm, dpr, dpk, dcu, bpl, res, dcr - вроде бы помню(знаю), а об остальных догадываюсь.
← →
DimaBr (2006-10-13 09:30) [117]Масштабирование.
Изменяйте размер шрифта, согласно размеру одного итема, неужеле это так сложно ?
При выходе с кнопки за пределы формы, кнопка остаётся нажатой. Вообще, хватит засорять форум, пишите в почту.
На счёт файлов для установки.
Необходимы: Reg.pas, dcr, dcu, dpk. Если используется редактор в виде отдельной формы, то + dfm, res,dcu формы.
Любопытно посмотреть на код (DymondBox(амперсант)yandex.ru)
← →
RASkov (2006-10-13 14:42) [118]> Изменяйте размер шрифта, согласно размеру одного итема,
> неужеле это так сложно ?
Итем может масштабироваться и по высоте и пошироте:)
> При выходе с кнопки за пределы формы, кнопка остаётся нажатой
Что верно то верно:(
> Reg.pas
?
> Любопытно посмотреть на код
Вот доделаю, нимного впорядок преведу и обязательно.
← →
RASkov (2006-10-13 17:02) [119]> [117] DimaBr (13.10.06 09:30)
Воощем отправил....
← →
RASkov (2006-10-13 23:19) [120]Если амперсант - это собака, то все равно помоему не правильный адрес, одно письмо вернулось с такой мессагой -- The following addresses had permanent fatal errors ---
Здесь в этой ветке есть мыло в моем синем нике.
Страницы: 1 2 3 вся ветка
Форум: "Компоненты";
Текущий архив: 2007.09.09;
Скачать: [xml.tar.bz2];
Память: 1.1 MB
Время: 0.104 c