 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Dietmar Brueckmann Guest
|
Posted: Tue Nov 18, 2003 8:07 am Post subject: How to mix components context menu |
|
|
Hi,
I've written a descendent from TClientdataset.
Now I want to add one new Item to the context menu.
I've read in TFM how to make my own context Items:
____________________________________________
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := IntToStr(Index)+'?';
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
inherited;
case Index of
0 : DoThis;
else assert(false,'Tdb_dbCDS_Editor.ExecuteVerb:');
end;
end;
____________________________________________
But in this way the existing 5 entries (especially the fields-editor from
TDataset) of TClientdataset disappear.
I've looked at CDSEdit but I didn't found the point where EditClientDataSet
is called.
And where it is mixed into the TDataset-menu.
I've looked at DBReg, it is instructive but I didn't see an entrypoint to do
what I want.
Possibly someone could show me a way to do it
Best regards
Dietmar
|
|
| Back to top |
|
 |
Constantine Yannakopoulos Guest
|
Posted: Tue Nov 18, 2003 8:41 am Post subject: Re: How to mix components context menu |
|
|
Author := "Dietmar Brueckmann";
| Quote: | Possibly someone could show me a way to do it
|
Unfortunately the component editor for TClientDataset is not available,
but you can get an instance of it before you register your component
editor by creating a TClientDataset on the fly and calling
DesignEditors.GetComponentEditor(). Then save its class in a global
variable and in your component editor create an instance of Borland's
component editor and use its methods to put the standard menuitems in
the popup-menu.
--
Constantine
|
|
| Back to top |
|
 |
Maris Janis Vasilevskis Guest
|
Posted: Tue Nov 18, 2003 10:11 am Post subject: Re: How to mix components context menu |
|
|
To keep all previous items and have the new item on top, do the following:
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := inherited GetVerbCount + 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := inherited GetVerb(Index-1);
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
case Index of
0 : DoThis;
else inherited ExecuteVerb(Index-1);
end;
end;
If not on top, use GetVerbCount in GetVerb and ExecuteVerb
(or direct number)
Mahris
Dietmar Brueckmann wrote:
| Quote: | Hi,
I've written a descendent from TClientdataset.
Now I want to add one new Item to the context menu.
I've read in TFM how to make my own context Items:
____________________________________________
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := IntToStr(Index)+'?';
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
inherited;
case Index of
0 : DoThis;
else assert(false,'Tdb_dbCDS_Editor.ExecuteVerb:');
end;
end;
____________________________________________
But in this way the existing 5 entries (especially the fields-editor from
TDataset) of TClientdataset disappear.
I've looked at CDSEdit but I didn't found the point where EditClientDataSet
is called.
And where it is mixed into the TDataset-menu.
I've looked at DBReg, it is instructive but I didn't see an entrypoint to do
what I want.
Possibly someone could show me a way to do it
Best regards
Dietmar
|
|
|
| Back to top |
|
 |
Dietmar Brueckmann Guest
|
Posted: Tue Nov 18, 2003 11:11 am Post subject: Re: How to mix components context menu |
|
|
"Constantine Yannakopoulos" <kyan (AT) deltasingular (DOT) remove.this.gr> schrieb im
Newsbeitrag news:3fb9e953 (AT) newsgroups (DOT) borland.com...
| Quote: | Author := "Dietmar Brueckmann";
| Possibly someone could show me a way to do it
Unfortunately the component editor for TClientDataset is not available,
but you can get an instance of it before you register your component
editor by creating a TClientDataset on the fly and calling
DesignEditors.GetComponentEditor(). Then save its class in a global
variable and in your component editor create an instance of Borland's
component editor and use its methods to put the standard menuitems in
the popup-menu.
Thanks for that. |
But sorry I've to bother you with some questions
1. GetComponentEditor gives me a created Editor - can I use it?
2. If not how to get the Class from it
the Create I could do with
Result := EditorClass.Create(Component, Designer) as IComponentEditor;
3. I've never before worked with Interfaces.
Have I to free the aIComponentEditor in finally/destroy
The following example is using the Result of GetComponentEditor as the
editor.
Is this the way?
Best regards
Dietmar
________________________________________________________________
{ TdbCDS_Editor }
(*
TdbCDS_Editor = class(TComponentEditor)
protected
aIComponentEditor: IComponentEditor;
...
end;
*)
constructor TdbCDS_Editor.Create(AComponent: TComponent;
ADesigner: IDesigner);
var
cds : TClientDataSet;
begin
inherited;
cds := TClientDataSet.Create(nil);
try
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
finally
FreeAndNil(cds);
end;
end;
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := aIComponentEditor.GetVerbCount+1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
if Index=0 then Result := 'DoSomething'
else aIComponentEditor.GetVerb(Index-1);
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
if Index=0 then DoSomething
else aIComponentEditor.ExecuteVerb(Index-1);
end;
___________________________________________________
|
|
| Back to top |
|
 |
Constantine Yannakopoulos Guest
|
Posted: Tue Nov 18, 2003 11:35 am Post subject: Re: How to mix components context menu |
|
|
Author := "Dietmar Brueckmann";
| Quote: | 2. If not how to get the Class from it
|
Oops! You are right, i'm afraid you can't, at least not without some
ugly hack.
So my suggestion cannot work. I am sorry for misleading you but this
technique used to work in D5 (when GetComponentEditor returned an
object and not an interface pointer) but apparently it does not work
anymore.
--
Constantine
|
|
| Back to top |
|
 |
Maris Janis Vasilevskis Guest
|
Posted: Tue Nov 18, 2003 4:24 pm Post subject: Re: How to mix components context menu |
|
|
Constantine Yannakopoulos wrote:
| Quote: | So my suggestion cannot work. I am sorry for misleading you but this
technique used to work in D5 (when GetComponentEditor returned an
object and not an interface pointer) but apparently it does not work
anymore.
|
Hi Constantine,
The Dietmar question really contained two parts, from what to inherit,
and how to inherit. I answered the easiest, second part.
Your exciting idea of the first part answer was really new for me.
I regret that starting from D6 it cannot be implemented in the
original form.
So, I added Hallvard Vassbotn function from
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3c887a0d_1%40dnews
It gives a solution for D6 and D7.
Mahris
implementation
uses SysUtils,DesignIntf,DesignEditors,DSDesign,DBReg,DesignMenus,Dialogs;
type
// Class author - Constantine Yannakopoulos
TExClientDataSetEditor = class(TDataSetEditor)
private
FOldEditor: TDataSetEditor;
protected
function GetDSDesignerClass: TDSDesignerClass; override;
public
constructor Create(AComponent: TComponent; ADesigner: IDesigner); override;
destructor Destroy; override;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
procedure Edit; override;
procedure Copy; override;
procedure PrepareItem(Index: Integer; const AItem: IMenuItem); override;
end;
var
PrevEditorClass: TClass;
// Function author - Hallvard Vassbotn
function GetImplementingObject(const I: IInterface): TObject;
const
AddByte = $04244483; // opcode for ADD DWORD PTR [ESP+4], Shortint
AddLong = $04244481; // opcode for ADD DWORD PTR [ESP+4], Longint
type
PAdjustSelfThunk = ^TAdjustSelfThunk;
TAdjustSelfThunk = packed record
case AddInstruction: longint of
AddByte : (AdjustmentByte: shortint);
AddLong : (AdjustmentLong: longint);
end;
PInterfaceMT = ^TInterfaceMT;
TInterfaceMT = packed record
QueryInterfaceThunk: PAdjustSelfThunk;
end;
TInterfaceRef = ^PInterfaceMT;
var
QueryInterfaceThunk: PAdjustSelfThunk;
begin
Result := Pointer(I);
if Assigned(Result) then
try
QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;
case QueryInterfaceThunk.AddInstruction of
AddByte: Inc(PChar(Result), QueryInterfaceThunk.AdjustmentByte);
AddLong: Inc(PChar(Result), QueryInterfaceThunk.AdjustmentLong);
else Result := nil;
end;
except
Result := nil;
end;
end;
procedure Register;
var
CDS: TClientDataset;
PrevEditor: TComponentEditor;
ComponentEditor:IComponentEditor;
begin
// First get the class pointer of the previously registered
// component editor for TClientDataset (TClientDatasetEditor).
CDS := TClientDataset.Create(nil);
try
ComponentEditor:=GetComponentEditor(CDS, nil);
PrevEditor := TComponentEditor(
GetImplementingObject(ComponentEditor));
PrevEditorClass := PrevEditor.ClassType;
finally
CDS.Free;
end;
// Now register our component editor.
RegisterComponents('Samples',[TMyClientDataSet]);
RegisterComponentEditor(TClientDataset, TExClientDataSetEditor);
end;
{ TExClientDataSetEditor }
procedure TExClientDataSetEditor.Copy;
begin
FOldEditor.Copy;
end;
constructor TExClientDataSetEditor.Create(AComponent: TComponent; ADesigner: IDesigner);
begin
inherited;
FOldEditor :=
TComponentEditorClass(PrevEditorClass).Create(AComponent, ADesigner)
as TDatasetEditor;
end;
destructor TExClientDataSetEditor.Destroy;
begin
FreeAndNil(FOldEditor);
inherited;
end;
procedure TExClientDataSetEditor.Edit;
begin
FOldEditor.Edit;
end;
procedure TExClientDataSetEditor.ExecuteVerb(Index: Integer);
var
I: Integer;
begin
I := Index - FOldEditor.GetVerbCount;
case I of
0: ShowMessage('My Verb 1');
1: ShowMessage('My Verb 2');
else
FOldEditor.ExecuteVerb(Index)
end;
end;
function TExClientDataSetEditor.GetDSDesignerClass: TDSDesignerClass;
begin
Result := TExClientDataSetEditor(FOldEditor).GetDSDesignerClass;
// hack to access protected method
end;
function TExClientDataSetEditor.GetVerb(Index: Integer): string;
var
I: Integer;
begin
I := Index - FOldEditor.GetVerbCount;
case I of
0: Result := 'My Verb 1';
1: Result := 'My Verb 2';
else
Result := FOldEditor.GetVerb(Index)
end;
end;
function TExClientDataSetEditor.GetVerbCount: Integer;
begin
Result := FOldEditor.GetVerbCount + 2;
end;
procedure TExClientDataSetEditor.PrepareItem(Index: Integer;
const AItem: IMenuItem);
var
I: Integer;
begin
I := Index - FOldEditor.GetVerbCount;
case I of
0: AItem.Caption := 'My Verb 1 - prepared' ;
1: AItem.Caption := 'My Verb 2 - prepared' ;
else
FOldEditor.PrepareItem(Index, AItem);
end;
end;
end.
|
|
| Back to top |
|
 |
Maris Janis Vasilevskis Guest
|
Posted: Tue Nov 18, 2003 4:30 pm Post subject: Re: How to mix components context menu |
|
|
Sorry, the last line in Register, of course, should be
RegisterComponentEditor(TMyClientDataset, TExClientDataSetEditor);
Mahris
|
|
| Back to top |
|
 |
Dietmar Brueckmann Guest
|
Posted: Wed Nov 19, 2003 8:57 am Post subject: Done: How to mix components context menu |
|
|
Hi,
It seems that I've implemented it 75% successfully.
Only the entry "assign local data" (translation from german. It is the 3rd
of the 4 original menu entries, the 4th of TDemoClientDataSet )
fails with an AV.
A pure TClientDataSet doesn't,
and if I do not "RegisterComponentEditor(TDemoClientDataSet,
TdbCDS_DemoEditor)"
its also ok)
But a second question is open:
what is to do with aIComponentEditor do in Destroy.
_____________________________________________
unit PropEdCdsDemoReg;
interface
uses Classes, DesignIntf, DesignEditors, DBClient;
type
TDemoClientDataSet = class(TClientDataSet)
end;
{ TdbCDS_DemoEditor }
TdbCDS_DemoEditor = class(TComponentEditor)
private
protected
cds : TClientDataSet;
aIComponentEditor : IComponentEditor;
procedure DoSomething;
public
constructor Create(AComponent: TComponent; ADesigner: IDesigner);
override;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
end;
procedure Register;
implementation
uses Dialogs;
procedure Register;
begin
RegisterComponents('DBrS', [TDemoClientDataSet]);
RegisterComponentEditor(TDemoClientDataSet, TdbCDS_DemoEditor);
end;
constructor TdbCDS_DemoEditor.Create(AComponent: TComponent;
ADesigner: IDesigner);
begin
inherited;
cds := TClientDataSet.Create(nil);
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
end;
function TdbCDS_DemoEditor.GetVerbCount: Integer;
begin
Result := aIComponentEditor.GetVerbCount+1;
end;
function TdbCDS_DemoEditor.GetVerb(Index: Integer): string;
begin
if Index=0 then Result := 'DoSomething'
else Result := aIComponentEditor.GetVerb(Index-1);
end;
procedure TdbCDS_DemoEditor.ExecuteVerb(Index: Integer);
begin
if Index=0 then DoSomething
else aIComponentEditor.ExecuteVerb(Index-1);
end;
procedure TdbCDS_DemoEditor.DoSomething;
begin
ShowMessage('DoSomething for CDS');
end;
end.
______________________________________________________
|
|
| Back to top |
|
 |
Maris Janis Vasilevskis Guest
|
Posted: Wed Nov 19, 2003 12:54 pm Post subject: Re: Done: How to mix components context menu |
|
|
You should do nothing with aIComponentEditor. It is an interface, and
system destroys it, when needed. Of course, you should destroy cds.
But this solution will not work in inherited part.
Not only "assign local data", all other items are incorrect too.
They deal with your cds, not your component.
To work with your component, you need inherited editor created
specially for it. See my previous posting.
Mahris
Dietmar Brueckmann wrote:
| Quote: | Hi,
It seems that I've implemented it 75% successfully.
Only the entry "assign local data" (translation from german. It is the 3rd
of the 4 original menu entries, the 4th of TDemoClientDataSet )
fails with an AV.
A pure TClientDataSet doesn't,
and if I do not "RegisterComponentEditor(TDemoClientDataSet,
TdbCDS_DemoEditor)"
its also ok)
But a second question is open:
what is to do with aIComponentEditor do in Destroy.
|
|
|
| Back to top |
|
 |
Dietmar Brueckmann Guest
|
Posted: Thu Nov 20, 2003 6:46 am Post subject: Re: How to mix components context menu |
|
|
"Maris Janis Vasilevskis" <mahris (AT) myself (DOT) com> schrieb im Newsbeitrag
news:3fb9f060$1 (AT) newsgroups (DOT) borland.com...
| Quote: | To keep all previous items and have the new item on top, do the following:
function TdbCDS_Editor.GetVerbCount: Integer;
begin
Result := inherited GetVerbCount + 1;
end;
function TdbCDS_Editor.GetVerb(Index: Integer): string;
begin
case Index of
0 : Result := 'Do This';
else Result := inherited GetVerb(Index-1);
end;
end;
procedure TdbCDS_Editor.ExecuteVerb(Index: Integer);
begin
case Index of
0 : DoThis;
else inherited ExecuteVerb(Index-1);
end;
end;
Sorry, possibly I've misunderstood you, but because of |
TdbCDS_Editor = class(TComponentEditor)
"inherited GetVerbCount" results in 0.
I'd need something like this:
TdbCDS_Editor = class(TClientDatasetEditor)
Best regards
dietmar
|
|
| Back to top |
|
 |
Dietmar Brueckmann Guest
|
Posted: Thu Nov 20, 2003 7:39 am Post subject: Re: Done: How to mix components context menu |
|
|
"Maris Janis Vasilevskis" <mahris (AT) myself (DOT) com> schrieb im Newsbeitrag
news:3fbb67ff$1 (AT) newsgroups (DOT) borland.com...
| Quote: | You should do nothing with aIComponentEditor. It is an interface, and
system destroys it, when needed. Of course, you should destroy cds.
But this solution will not work in inherited part.
Not only "assign local data", all other items are incorrect too.
They deal with your cds, not your component.
|
I've seen it too - after posting "done" before testing - foolish - only the
menuitems are there and the belong to the private cds. Nice but unusable.
I've tried to change
cds := TClientDataSet.Create(nil);
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
in
cds := TClientDataSet(Component);
aIComponentEditor := DesignEditors.GetComponentEditor(cds,ADesigner);
but it goes into a stack overflow - and so I give up.
| Quote: | To work with your component, you need inherited editor created
specially for it. See my previous posting.
Sorry but this all is far of that I've done previously. |
Should I use "GetImplementingObject" - it looks quite horrible.
should I try
constructor TdbCDS_DemoEditor.Create(AComponent: TComponent;
ADesigner: IDesigner);
begin
inherited;
aIComponentEditor := GetImplementingObject(ADesigner);
end;
and all is ok?
Sorry for bothering you - but it would be a "nice to have" !
Best regards
Dietmar
|
|
| Back to top |
|
 |
Maris Janis Vasilevskis Guest
|
Posted: Thu Nov 20, 2003 12:22 pm Post subject: Re: Done: How to mix components context menu |
|
|
There is no easy way for your task.
I posted a working code made by mixing two other publications,
you can copy it and use.
About GetImplementingObject - see discussion in the mentioned link.
Of course, no warranty for D8, but OK for D6 and D7.
Mahris
Dietmar Brueckmann wrote:
| Quote: | Sorry but this all is far of that I've done previously.
Should I use "GetImplementingObject" - it looks quite horrible.
|
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|