-
Добрый день! Помогите пожалуйста, есть компонент, у него есть свойство типа TCollection, соотвтетственно описан класс TCollectionItems. Итого: кладу компонент на форму, по клику вызывается окно редактора, но в нем я не могу добавить новый Item. procedure TFilterEditor2006.Edit; Var Addr: Integer; begin // inherited; Addr := GetOrdValueAt(0); F.Component := Pointer(Addr); // if F.Component = nil // then F.Component := TSmcFilters.Create; F.OnItemClick := DoItemClick; F.Show; end; Как только разкоментирую строки с TSmcFilters.Create - все работает, но как только появляется Item, я на него кликаю, свойства его появляются в инспекторе объектов, а вот окно редактора исчезает. В этом деле новичек, все сделал по аналогии найденного примера, но что-то не так все работает как хотелось...
P.S. TSmcFilters: TCollection, TSmcFilter: TCollectionItem
-
Прочитал множество статей здесь на форуме, но что-то все равно не разобрался... :(
-
Народ, плиз... могу и исходники показать... только стоит ли все сюда вылаживать - много получится...
-
1. Редактор уберите совсем, будет работать встроенный редактор свойства. 2. В конструкторе компонента коллецию создаете, в деструкторе - убиваете. 3. Для свойства-коллекции пишете метод Set, в нем вызываете Assign.
-
Юрий, а как мне тогда вызвать встроенный редактор свойств в процедуре Edit? Заранее спасибо
-
-
Ребята, больщое спасибо, но что-то у меня не получается, редактор не появляется, наверное, я какую-нибудь глупость упустил... :( Вы не могли бы посмотреть код ??? заранее спасибо: unit SmcFilterEditor2006;
interface
uses DesignEditors, DesignIntf, Classes, Dialogs, SysUtils, TypInfo;
type TFilterEditor2006 = class(TComponentEditor) private FPropInfo : PPropInfo; FPropEdit : IProperty; procedure GetPropProc(const PropEdit: IProperty); protected public constructor Create(AComponent: TComponent; ADesigner: IDesigner); override; function GetVerb(Index: Integer): string; override; function GetVerbCount: Integer; override; procedure ExecuteVerb(Index: Integer); override; function GetPropertyName: String; virtual; procedure Edit; override; end;
procedure Register;
implementation
uses SmcFilter2006;
procedure Register; begin RegisterComponentEditor(TSmcFilter2006,TFilterEditor2006); end;
{ TFilterEditor2006 }
constructor TFilterEditor2006.Create(AComponent: TComponent; ADesigner: IDesigner); begin inherited; FPropInfo := GetPropInfo(GetComponent.ClassInfo, GetPropertyName, [tkClass]); end;
procedure TFilterEditor2006.Edit; Var Addr: Integer; Selection: TDesignerSelections; begin if (FPropEdit = nil) and (FPropInfo <> nil) then begin Selection := TDesignerSelections.Create; try Designer.GetSelections(Selection); GetComponentProperties(Selection, [tkClass], Designer, GetPropProc); finally Selection.Free; end; end; if FPropEdit <> nil then FPropEdit.Edit; end;
procedure TFilterEditor2006.ExecuteVerb(Index: Integer); begin inherited; case Index of 0: Edit; end; end;
function TFilterEditor2006.GetPropertyName: String; begin Result := 'SmcFilter'; end;
procedure TFilterEditor2006.GetPropProc(const PropEdit: IProperty); begin if PropEdit.GetPropInfo = FPropInfo then FPropEdit := PropEdit; end;
function TFilterEditor2006.GetVerb(Index: Integer): string; begin case Index of 0: Result := 'Edit'; else inherited GetVerb(Index); end; end;
function TFilterEditor2006.GetVerbCount: Integer; begin Result := inherited GetVerbCount + 1; end;
end.
-
unit SmcFilter2006;
interface
uses SysUtils, Classes, DB, DBClient, Dialogs, TypInfo, DesignIntf;
type TSmcTypeFilterExpr = (tfeInt, tfeStr, tfeDat, tfeCheck, tfeMatExp, tfeCheckBox, tfeCombo);
TSmcFilter = class;
TSmcFilters = class(TCollection) private function GetItem(Index: Integer): TSmcFilter; procedure SetItem(Index: Integer; const Value: TSmcFilter); public constructor Create; overload; procedure AddFilter(Value: TSmcFilter); procedure DelFilter(Value: TSmcFilter); function CreateFilter(AFileld: TField; const ADetailDataSet: TClientDataSet; ATypeExpr: TSmcTypeFilterExpr): TSmcFilter; procedure GetFilterList(List: TList; const Name: String); function ParamByName(const Value: String): TSmcFilter; function FindFilter(const Value: String): TSmcFilter; procedure AssignValue(Value: TSmcFilters); property Items[Index: Integer]: TSmcFilter read GetItem write SetItem; default; end;
TSmcFilter = class(TCollectionItem) private FField: TField; FDetailDataSet: TClientDataSet; FTypeFilterExpr: TSmcTypeFilterExpr; FFilterName: String; public constructor Create(Collection: TCollection); overload; override; constructor Create(AFilters: TSmcFilters; AField: TField; ADetailDataSet: TClientDataSet; ATypeFilterExpr: TSmcTypeFilterExpr); reintroduce; overload; published property Field: TField read FField write FField; property DetailDataSet: TClientDataSet read FDetailDataSet write FDetailDataSet; property TypeFilterExpr: TSmcTypeFilterExpr read FTypeFilterExpr write FTypeFilterExpr; property FilterName: String read FFilterName write FFilterName; end;
TSmcFilter2006 = class(TComponent) private FDataSet: TDataSet; FFilters: TSmcFilters; procedure SetFilters(const Value: TSmcFilters); procedure SetDataSet(const Value: TDataSet); { Private declarations } protected { Protected declarations } public constructor Create; reintroduce; destructor Destroy; reintroduce; { Public declarations } published property DataSet: TDataSet read FDataSet write SetDataSet; property Filters: TSmcFilters read FFilters write SetFilters; { Published declarations } end;
procedure Register;
implementation
procedure Register; begin RegisterComponents('SmcLib2006', [TSmcFilter2006]); end;
{ TSmcFilter2006 }
constructor TSmcFilter2006.Create; begin FFilters.Create; end;
destructor TSmcFilter2006.Destroy; begin FFilters.Free; FFilters := nil; end;
procedure TSmcFilter2006.SetDataSet(const Value: TDataSet); begin if FDataSet <> Value then FDataSet := Value; end;
procedure TSmcFilter2006.SetFilters(const Value: TSmcFilters); begin FFilters.Assign(Value); end;
{ TSmcFilters }
procedure TSmcFilters.AddFilter(Value: TSmcFilter); begin Value.Collection := Self; end;
procedure TSmcFilters.AssignValue(Value: TSmcFilters); Var i: Integer; Fil: TSmcFilter; begin for I := 0 to Value.Count - 1 do begin Fil := FindFilter(Value[i].FilterName); if Fil <> nil then Fil.Assign(Value[i]); end; end;
constructor TSmcFilters.Create; begin inherited Create(TSmcFilter); end;
function TSmcFilters.CreateFilter(AFileld: TField; const ADetailDataSet: TClientDataSet; ATypeExpr: TSmcTypeFilterExpr): TSmcFilter; begin Result := Add as TSmcFilter; Result.Field := AFileld; Result.DetailDataSet := ADetailDataSet; Result.TypeFilterExpr := ATypeExpr; end;
procedure TSmcFilters.DelFilter(Value: TSmcFilter); begin Value.Collection := nil; end;
function TSmcFilters.FindFilter(const Value: String): TSmcFilter; Var I: Integer; begin for I := 0 to Count - 1 do begin Result := TSmcFilter(inherited Items[i]); if CompareText(Result.FilterName, Value) = 0 then Exit; end; Result := nil; end;
procedure TSmcFilters.GetFilterList(List: TList; const Name: String); Var Pos: Integer; begin Pos := 1; while Pos <= Length(Name) do List.Add(ParamByName(ExtractFieldName(Name, Pos))); end;
function TSmcFilters.GetItem(Index: Integer): TSmcFilter; begin Result := TSmcFilter(inherited Items[Index]); end;
function TSmcFilters.ParamByName(const Value: String): TSmcFilter; begin Result := FindFilter(Value); if Result = nil then ShowMessage('Ошибка'); end;
procedure TSmcFilters.SetItem(Index: Integer; const Value: TSmcFilter); begin inherited SetItem(Index, TCollectionItem(Value)); end;
{ TSmcFilter }
constructor TSmcFilter.Create(Collection: TCollection); begin inherited Create(Collection); Field := nil; DetailDataSet := nil; TypeFilterExpr := tfeInt; FilterName := 'NewFilter'; end;
constructor TSmcFilter.Create(AFilters: TSmcFilters; AField: TField; ADetailDataSet: TClientDataSet; ATypeFilterExpr: TSmcTypeFilterExpr); begin Create(AFilters); Field := AField; DetailDataSet := ADetailDataSet; TypeFilterExpr := ATypeFilterExpr; end;
end.
-
В код вчитываться не стал, есть прще вариант. Подключить модуль ColnEdit и вызвать один из вариантов
procedure ShowCollectionEditor(ADesigner: IDesigner; AComponent: TComponent;
ACollection: TCollection; const PropertyName: string);
function ShowCollectionEditorClass(ADesigner: IDesigner;
CollectionEditorClass: TCollectionEditorClass; AComponent: TComponent;
ACollection: TCollection; const PropertyName: string;
ColOptions: TColOptions = [coAdd, coDelete, coMove]): TCollectionEditor;
-
т.е. в процедуре Edit вызвать ShowCollectionEditor ???
-
Вот тут наверное ошибка
function TFilterEditor2006.GetPropertyName: String;
begin
Result := 'SmcFilter'; end;
-
Спасибо большое, сейчас попробую
-
> т.е. в процедуре Edit вызвать
Угу !!! Можно например породить свой редактро от стандартного, добавив некую функциональность. Я таким образом добавлял DblClick в редакторе.
-
Продолжаю тупить... в процедуре все равено не отрабатывает if FPropEdit <> nil then FPropEdit.Edit; FPropEdit - не nill, но редактор не запускается (проблема действительно была в Result := 'SmcFilter'; // долно быть наверное - Filters) procedure TFilterEditor2006.Edit; Var Selection: TDesignerSelections; begin if (FPropEdit = nil) and (FPropInfo <> nil) then begin Selection := TDesignerSelections.Create; try Designer.GetSelections(Selection); GetComponentProperties(Selection, [tkClass], Designer, GetPropProc); finally Selection.Free; end; end;
if FPropEdit <> nil then FPropEdit.Edit; end;
-
Я вот тут подумал, а правильно ли как я сделал - TFilterEditor2006 = class(TComponentEditor)... ???
-
Вы переопределили метод Edit и в нём же ЕГО же и вызываете
procedure TFilterEditor2006.Edit;
Var
Addr: Integer;
Selection: TDesignerSelections;
begin
if (FPropEdit = nil) and (FPropInfo <> nil) then begin
Selection := TDesignerSelections.Create;
try
Designer.GetSelections(Selection);
GetComponentProperties(Selection, [tkClass], Designer, GetPropProc);
finally
Selection.Free;
end;
end;
if FPropEdit <> nil
then FPropEdit.Edit;
end;
-
А как тогда будет правильно сделать ? (я собственно говря это и подозревал, но брал с примера... мне главное понять суть...)
-
А разве в примере так ??? Скопируйте пример, унаследуйтесь от него, переопределите GetPropertyName с усё !!!
-
Подозреваю что не хватает регистрации !!!
procedure Register;
begin
RegisterComponentEditor(TMyComponent,TMyEditor);
end; Суть поста В момент создания редактора ищем свойство в классе.
FPropInfo := GetPropInfo(GetComponent.ClassInfo, GetPropertyName, [tkClass])
Если таково свойство есть -
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;
end;
if FPropEdit <> nil then FPropEdit.Edit
end
-
1. Регистрация есть (в коде ее можно найти выше) 2. В регистрации действительно стоит поиск свойства класса 3. Код, написанный Вами ниже, у меня находится в процедуре Edit, но Вы выше написаои что я этот метод переопределяю и там же вызываю, где же тогда выполнять этот код???
а так по тексту у меня все так же и написано
-
Возможно проблема в том что ваша коллекция на знает хозяина, так как вы не переопределили GetOwner
function TPersistent.GetOwner: TPersistent;
begin
Result := nil;
end;
procedure TCollectionProperty.Edit;
var
Obj: TPersistent;
begin
Obj := GetComponent(0);
while (Obj <> nil) and not (Obj is TComponent) do
Obj := TPersistentCracker(Obj).GetOwner;
ShowCollectionEditorClass(Designer, GetEditorClass,
TComponent(Obj), TCollection(GetOrdValue), GetName, GetColOptions);
end; Попробуйте унаследоваться так TSmcFilters = class(TOwnedCollection)
-
В таком случае я не знаю как (куда) добавить функцию function TPersistent.GetOwner: TPersistent; begin Result := nil; end; И не знаю кто такой TPersistentCracker... - ругается на него. :(
-
> И не знаю кто такой TPersistentCracker... - ругается на него. :(
TPersistentCracker = class(TPersistent);
-
её никуда ненадо добавлять. Это я код из VCL привёл.
-
Дмитрий, если Вам не тяжело, то объясните специфику... я считаю что я залез в дебри для уровня на котором в данный момент нахожусь... меня интересует такая вещь. Есть мой компонент, мне необходимо снабдить его свойством, которое можно в дизайн тайме изменять так же как, например, добавляются, удаляются, изменяются поля в DataSet. Тут я так понимаю мне необходимо сделать свои классы TCollection и TCollectionItem (что я и сделал). Потом на компоненте, на этом свойстве должен вызываться редактор - я так понимаю стандартный. Может все на много проще, а я не в ту степь полез :) ???
-
В принципе - правильно рассуждаете, единственное НО. Для того чтобы редактор смог заработать нужно чтобы по вашей коллекции можно было отыскать компонент. Это всё реализовано в редакторе вот таким способом. Это вам писать не нужно
procedure TCollectionProperty.Edit;
var
Obj: TPersistent;
begin
Obj := GetComponent(0);
while (Obj <> nil) and not (Obj is TComponent) do
Obj := TPersistentCracker(Obj).GetOwner;
ShowCollectionEditorClass(Designer, GetEditorClass,
TComponent(Obj), TCollection(GetOrdValue), GetName, GetColOptions);
end; То есть когда вызывается метод EDIT для свойства - коллекции, ищется компонент , которому пренадлежит коллекция и вызывается редактор. Чтобы правильно найти компонент Вы должны: 1. Переопределить метод GetOwner чтобы он возвращал ссылку на родителя
TMyCollection = class(TCollection)
private
fOwner: TPersistent;
protected
function GetOwner: TPersistent;override;
public
constructor Create(AOwner:TPersistent);
end;
constructor TMyCollection.Create(AOwner:TPersistent);
begin
fOwner := AOwner;
inherited Create(TClass_MyCollectionItem);
end;
function TMyCollection.GetOwner: TPersistent;
begin
Result := fOwner;
end;
2. Или же (что значительно проще) унаследоваться от TOwnedCollection, в котором всё это уже реализовано.
|