Solved

Problem when creating components.

Posted on 2002-05-17
18
168 Views
Last Modified: 2012-05-04
   Hi!

I'm having some trouble creating components in Delphi3.
I'm trying to write a component that has a derived class of TComponentEditor. Everything complies ok. But when I drag the component onto a Form and try to access the component's editor through the popup menu I get an access violation error.
And I'm doing everything right and even tried the "copy-paste from delphi books" method. ;)
I'm using the Delphi 3.0 Professional version not the 3.01 version. Is there any difference between those versions ???
I have programmed in Delphi for several years now but reacently started to create my own components.

Regards,
Tomas Helgi
0
Comment
  • 7
  • 7
  • 3
  • +1
18 Comments
 
LVL 4

Expert Comment

by:max-hb
ID: 7016000
Hi!
have you registered your Component editor using RegisterComponentEditor()?
0
 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7016003
Yes! :(
0
 
LVL 4

Expert Comment

by:max-hb
ID: 7016025
Maybe you could publish / email sources for further analysis?
0
 
LVL 4

Expert Comment

by:max-hb
ID: 7016053
Maybe you could publish / email sources for further analysis?
0
 
LVL 4

Expert Comment

by:nestorua
ID: 7016875
HI, TomasHelgi,
It's not so easy to find the error in your code without
your code. But from what you say check the following:
1. In implementation of the ExecuteVerb of your Editor
did you CREATE the Dialog form (your Editor form).
2. When you call the COMPONENT's Owner.Name and Name did you do that correctly.
3. When you read the properties of your component into the Editor, did you do the type conversion.

And did you at all test your Editor as a usual form which changes the properties of your component?
Sincerely,
Nestorua.
0
 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7023530
  Hi!

Well, I found 1 error and fixed that. ;)
BUT I still have an access violation error. :(
In the component I have 2 TStringList objects with some data. When I create the dialogform for the editor I assign the data to the dialog-form's TStringLists. Then there is no problem editing that data. BUT the error arrise when I want to assign the edited data back to the components 2 TStringLists.
Yes Nestorua, I create the Editor form and as I said I can assign the data from the 2 StringLists and work with it BUT I can't "save" it back to the component. :(
The component's owner.name and name seems to be ok.
What type conversion. If you mean the (Component as ...) then yes I did.
There is a reason I don't want to publish my code but I think you could still help me if I give you the above information. ;)

Regards,
  Tomas Helgi
0
 
LVL 4

Expert Comment

by:nestorua
ID: 7023712
HI,
I don't know how you do StringList saving, so propose to do it as following:
StringListOnTheForm.Assign(StringListOnEditor)
(not "=").
And I hope you have created StringListOnTheForm when created
your Component.
Sincerely,
Nestorua.
0
 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7023722
Hi!

I create the Editor's Dialog form in the ExecuteVerb method.
And of course I do the .Assign(..) ;)

Regards,
  Tomas Helgi
0
 
LVL 4

Expert Comment

by:nestorua
ID: 7023738
Did you create StringList in your Component?
Did you do assigning before destroying the Editor?
Did you try your Editor as an usual "second" form called from main form to edit the stringlists on that main form?
And TomasHelgi, it's not so easy to guess what the problem without your code, don't you think so?
Sincerely,
Nestorua.
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7023763
Hi!

I guess I could write down some part of the code. ;)
Lets call the component MyComponent. ;)
type
 MyComponent = class(TComponent)
 private
   firstStrList : TStringList;
   secondStrList : TStringList;
  ....
 public
   constructor Create(AOwner : TComponent); override;
   ....
 end;
 MyComponentsEditorForm = class(TForm)
  strList1 : TListBox;
  strList2 : TListBox;  
  Button1 : TButton;
 ....
  end;
 MyComponentsEditor = class(TComponentEditor);
   function GetVerbCount : Integer; //returns the number 1
   function GetVerb(Index : Integer): String; //returns "MyEditor"
    procedure ExecuteVerb(Index : Integer);
 end;
 
   
I create the firstStrList and secondStrList in the components Create method and assign some data to them and free them in the Destroy method.

procedure MyComponentsEditor.ExecuteVerb(Index : Integer);
var
  theForm : MyComponentsEditorForm;
begin
   theForm := MyComponentsEditorForm.Create(Application);
   theForm.strList1.Items.Assign(firstStrList);
   theForm.strList2.Items.Assign(secondStrList);
   //here so far so good
   if theForm.ShowModal = mrOk then
   begin
      (Component as MyComponent).firstStrList.Assign(theForm.StrList1.Items); // here comes the access violation error :(
      (Component as MyComponent).secondStrList.Assign(theForm.StrList2.Items);
   end;
   theForm.Free;
   Designer.Modified;
end;

Regards,
  Tomas Helgi
0
 
LVL 4

Expert Comment

by:nestorua
ID: 7023980
HI, once more,
The code you wrote is not good.
It must be like that:
procedure TYourComponentEditor.ExecuteVerb(Index: integer);
var Dialog: TYourComponentEditorDlg;
begin
  Dialog:=TYourComponentEditorDlg.Create(Application);
   try
     Dialog.Caption:=Component.Owner.Name+'.'+
                     Component.Name+' - '+
                     Dialog.Caption;

     with Dialog do
      begin
       YourListBox.Items.Assign
        (TYourComponent(Component).YourStringList);
//
       if ShowModal=mrOK
        then TYourComponent(Component).YourStringList.Assign
         (YourListBox.Items)
        else EXIT;
      end;
//
     Designer.Modified;
   finally
     Dialog.Free;
   end;
end;

This code is good and works.
Still you ddn't show the code (part of it) of your component, is it good in that part concerned your stringlists.
Sincerely,
Nestorua.
0
 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7024098
Well at runtime I can add or delete strings from the component using the components methods and let the component work with that data without any errors.
It is the design-time part that is not working.  :(
I will try this tonight and se if that changes anything.

Regards,
  Tomas Helgi
0
 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7026547
Hi!

I tested it last night and found out that the error is not comming from the stringlists. It's commming from the Designer.Modified. When I commented that line the error disappeared.
But I still have some technical difficulties. ;)
The data I edit at design time does not appear to be accessible at runtime. :(
What am I forgeting or doing wrong ??
I have experienced this "error" also in the PropertyEditor where I'm calling the same dialog and editing the same stringlists ( http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=delphi&qid=20260174 )
Nestorua! You told me there that I had to implement the DefineProperties method. I did but that didn't work. :(
Should I use some other datacollection objects rather than the TStringList ???

Regards,
  Tomas Helgi
0
 
LVL 4

Expert Comment

by:nestorua
ID: 7026939
HI,
If you use TStringList for Strings only, it's OK.
But if you use its Objects as well, then you must teach DELPHI
to load and save those data in its STREAM.
In this case you usually must override defineproperties method
and so on (DefineProperty...).
If Designer.Modified is commented then your changes done with
Editor are not supposed to be remembered in the Form designed.
Sincerely,
Nestorua.
0
 
LVL 24

Author Comment

by:Tomas Helgi Johannsson
ID: 7029185
Hi!

>If you use TStringList for Strings only, it's OK.
I'm using TStringList for strings only and I thought that should be ok but it's not. :(
>If Designer.Modified is commented then your changes done with
>Editor are not supposed to be remembered in the Form designed.
I know that. :)
As I said before then the access violation error pops up when Designer.Modified is called. =>(

Regards,
  Tomas Helgi

0
 
LVL 4

Expert Comment

by:nestorua
ID: 7029278
HI, Tomas,
Then I must (or am supposed) to give you the working example
of the component (as simple as possible) with additional
property of the type TStrings and the corresponding Component Editor.
I will do that today or tomorrow, OK?
Sincerely,
Nestorua.
0
 
LVL 4

Accepted Solution

by:
nestorua earned 50 total points
ID: 7034216
HI, Tomas,
Send you codes I promised to send.
You can compare what I wrote with what you have and I hope you
will find your error.

unit EdcStrings;

{---------------------------------------------------------------------}
{---------------------------------------------------------------------}
INTERFACE
{---------------------------------------------------------------------}
{---------------------------------------------------------------------}


uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, Buttons, ExtCtrls,
  DesignConst, DesignIntf, DesignEditors,
  ToolWin, ComCtrls, ExtDlgs, ComponentWithStrings;

TYPE

  TComponentWithStringsEditor= class(TComponentEditor)
    function GetVerbCount: integer; override;
    function GetVerb(Index: integer): string; override;
    procedure ExecuteVerb(Index: integer); override;
   end;

  procedure Register;

{---------------------------------------------------------------------}
{---------------------------------------------------------------------}
IMPLEMENTATION

uses ComponentWithStringsDlg;
{---------------------------------------------------------------------}
{---------------------------------------------------------------------}

{--------------------------------------------------------------}
procedure Register;
begin
  RegisterComponentEditor(TComponentWithStrings,
                          TComponentWithStringsEditor);
end;
{--------------------------------------------------------------}
//TComponentWithStringsEditor
{--------------------------------------------------------------}
function TComponentWithStringsEditor.GetVerbCount: integer;
begin
  Result:=1;
end;
{---}
function TComponentWithStringsEditor.GetVerb(Index: integer): string;
begin
 if Index=0 then Result:='Edit ComponentWithStrings...';
end;
{---}
procedure TComponentWithStringsEditor.ExecuteVerb(Index: integer);
var Dialog: TFormComponentWithStringsDlg;
begin
  Dialog:=TFormComponentWithStringsDlg.Create(Application);
   try
     Dialog.Caption:=Component.Owner.Name+'.'+
                     Component.Name+' - '+
                     Dialog.Caption;

     with Dialog do
      begin
       mmMain.Lines.Assign(TComponentWithStrings(Component).Items);

       if ShowModal=mrOK
        then TComponentWithStrings(Component).Items.Assign(mmMain.Lines)
        else EXIT;
      end;
//
     Designer.Modified;
   finally
     Dialog.Free;
     MessageBeep(0);
   end;
end;
{----------------------------------------------------------------------}
{----------------------------------------------------------------------}
END.
unit ComponentWithStringsDlg;

{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
INTERFACE
{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons;

type
  TFormComponentWithStringsDlg = class(TForm)
    mmMain: TMemo;
    bbOK: TBitBtn;
    bbCancel: TBitBtn;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormComponentWithStringsDlg: TFormComponentWithStringsDlg;

{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
IMPLEMENTATION
{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}

{$R *.dfm}

{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
END.

unit ComponentWithStrings;

{-----------------------------------------------------------------------------}
{-----------------------------------------------------------------------------}
INTERFACE
{-----------------------------------------------------------------------------}
{-----------------------------------------------------------------------------}

uses
  Windows, Messages, SysUtils, Classes;

type
  TComponentWithStrings = class(TComponent)
  private
    FItems: TStrings;
    procedure SetItems(const Value: TStrings);
    { Private declarations }
  protected
    { Protected declarations }
  public
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
    { Public declarations }
  published
    property Items: TStrings read FItems
                             write SetItems;
    { Published declarations }
  end;

procedure Register;

{-----------------------------------------------------------------------------}
{-----------------------------------------------------------------------------}
IMPLEMENTATION
{-----------------------------------------------------------------------------}
{-----------------------------------------------------------------------------}

{-----------------------------------------------------------------------------}
procedure Register;
begin
  RegisterComponents('MyCo', [TComponentWithStrings]);
end;
{-----------------------------------------------------------------------------}
{ TComponentWithStrings }
{-----------------------------------------------------------------------------}
constructor TComponentWithStrings.Create(AOwner: TComponent);
begin
  INHERITED;
//
  FItems:=TStringList.Create;
end;
{-----------------------------------------------------------------------------}
destructor TComponentWithStrings.Destroy;
begin
  FItems.Free;
//
  INHERITED;
end;
{-----------------------------------------------------------------------------}
procedure TComponentWithStrings.SetItems(const Value: TStrings);
begin
  FItems.Assign(Value);
end;
{-----------------------------------------------------------------------------}
{-----------------------------------------------------------------------------}
END.

Everything works fine.
Sincerely,
Nestorua.
0
 
LVL 1

Expert Comment

by:pnh73
ID: 9005930
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Accept answer from nestorua

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
Paul (pnh73)
EE Cleanup Volunteer
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now