Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Компоненты";
Текущий архив: 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 есть только у TPaintBox
procedure 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]


> Где, как отловить/перекрыть момент заполнения списка поля
> CanvasControls

Type
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.055 c
15-1187082510
Kostafey
2007-08-14 13:08
2007.09.09
Всякий раз при запуске Win стало появляться это сообщение


15-1187075670
Руслан56
2007-08-14 11:14
2007.09.09
Запрос


15-1186726846
stanislav
2007-08-10 10:20
2007.09.09
Вопрос по CVS


15-1186638140
leonid
2007-08-09 09:42
2007.09.09
Подскажите сервис


3-1178904669
Dmitry_177
2007-05-11 21:31
2007.09.09
SQL запрос





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский