Jump to content
Magno

How to make an "About" for a simple component?

Recommended Posts

I never had the real need for this but now I faced I really dunno how, making components are not my real business so here is my doubt, if one would like to help.

Well, I have an unit (about.pas) that my compo will use, but this is everything I could do. I have no clue how do go forward.

 

   TAbout = Class(TComponent)
   Private
      fsAbout: TAbout;
   Public
      Procedure AboutDialog; //really? I dunno
   Published
      Property About: TAbout Read fsAbout Write fsAbout Stored False;
   End;

 

procedure TAbout.AboutDialog;
begin
   ShowMessage('Made by me =)');
end;

-----

Now, my component has such:

 

   private
      { Private declarations }
      fsAbout: TAbout;

...

   published
      { Published declarations }
      property About: TAbout Read fsAbout Write fsAbout Stored False;

end;

 

And from here I don't know what to do. I would be happy with a read only label on my component too.

 

Thank you for any help! 😃

Edited by Magno

Share this post


Link to post

I think you need to explain a little bit better what you are trying to do.

Start with an example of how you would like to use your component. Once we understand that we can better help you with how to implement it.

Share this post


Link to post
1 hour ago, Anders Melander said:

I think you need to explain a little bit better what you are trying to do.

Start with an example of how you would like to use your component. Once we understand that we can better help you with how to implement it.

I want that one of the Published properties show an About, with that I can show the user the component version once it get installed in the Delphi IDE.

 

uses uAbout;

type
   TMyComponent = class(TComponent)
   private
      { Private declarations }
      fsAbout: TAbout;

      FUser: String;
   protected
      { Protected declarations }
   public
      { Public declarations }
   published
      { Published declarations }
      property About: TAbout Read fsAbout Write fsAbout Stored False;

      property User: String read FUser write FUser;
   end;

 

I am stuck here. The TAbout is an external unit, like I show in the OP. So, when installed the User property shows on the IDE and the About, but I don't even know what technique to make it show a dialog or become a read only text.

 

Thanks for the reply!

 

 

Edited by Magno

Share this post


Link to post

Okay. What you need is a component editor. With this you can specify what happens when the user double clicks your component (at design time) and you can add menu items to the context menu. For example a "About My Awesome Component..." menu item.

The help is a bit sparse on how to implement a component editor for VCL (there's a good example for FireMonkey though) but there's plenty of examples available on the net: https://www.google.com/search?q=delphi+component+editor

There might also be an example installed with Delphi.

Share this post


Link to post
26 minutes ago, Anders Melander said:

Okay. What you need is a component editor. With this you can specify what happens when the user double clicks your component (at design time) and you can add menu items to the context menu. For example a "About My Awesome Component..." menu item.

The help is a bit sparse on how to implement a component editor for VCL (there's a good example for FireMonkey though) but there's plenty of examples available on the net: https://www.google.com/search?q=delphi+component+editor

There might also be an example installed with Delphi.

Thank you!! This is the path I needed.

 

Share this post


Link to post
7 hours ago, Magno said:

I want that one of the Published properties show an About, with that I can show the user the component version once it get installed in the Delphi IDE.

Why not just make that property be a simple String value?  Easy to read, no popup dialog needed, and you can disable DFM streaming for that property if needed.

 

But, if you really want a popup dialog, then you need to separate your code into run-time and design-time packages.  The run-time package implements only the main component by itself, and it should have no concept of the popup dialog at all.  The design-time package uses the run-time package, and implements the actual popup dialog, as well as a component editor to display that popup dialog when the user double-clicks or right-clicks on your main component.

 

Indy implements both approaches, and Indy is pre-installed in the IDE w/ source code, so you can look at how Indy handles these steps:

 

- In the IdBaseComponent.pas unit of the IndySystem run-time package, the TIdBaseComponent class, which is a base class that all Indy components derive from, has a public Version property that returns a static String from IdVers.inc specifying the compiled version number (the Version property could have been made published in the Object Inspector with a little extra work).

 

- In the IdCoreDsnRegister.pas unit of the IndyCore design-time package, there is a TIdBaseComponentEditor class that is registered with the IDE at design-time using the RTL's RegisterComponentEditor() function, to display a popup dialog when double/right-clicking on any Indy component in the Form Designer.

 

- Also in IdCoreDsnRegister.pas is a 3rd way that Indy displays its version number - in the IDE's own About dialog!  When the IndyCore design-time package is loaded in the IDE, it registers some custom Strings with the IDE's About box using the IDE's OpenTools API, specifically the IOTAAboutBoxServices.AddPluginInfo() interface method.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

Why the component designer? I'd do it a bit simpler and design an About form and fetch as much as possible about the application at runtime - such as the icon from the resources, and title, version, etc from the version resource.  The company and contact info could be static text, or you put it into properties on the form. The form could have a simple memo where you would put in any additional info you would want to show.

 

Share this post


Link to post
9 hours ago, Remy Lebeau said:

But, if you really want a popup dialog, then you need to separate your code into run-time and design-time packages. 

There's no requirement for both run- and design-time packages. A design time package alone is enough.

 

1 hour ago, Lars Fosdal said:

Why the component designer?

Assuming you mean component editor the purpose is to separate run- and design-time functionality.

The end-user doesn't need to know that the application uses TAwesomeComponent version x.y.z and there's no need to include the about form in the compiled application.

Share this post


Link to post

Thank you guys for all these information! Very useful and one who need can dig on this to make it work for he needs. Remy I will check the Indy approach.

My awesome component needs no more than a label informing the version or a ShowMessage() kind of dialog. Thanks again!

Share this post


Link to post
10 hours ago, Anders Melander said:

There's no requirement for both run- and design-time packages. A design time package alone is enough.

You can't use design-time code in a runtime executable.  A popup dialog that is meant to be viewed only at design-time needs to be in a design-time package only.  Yes, a single package CAN be marked for both run-time and design-time usage, but when property/component editors are involved, you need to use separate run-time and design-time packages.

Share this post


Link to post
3 hours ago, Remy Lebeau said:

You can't use design-time code in a runtime executable.

The OP asked for design time functionality. I replied with a design time solution and stated that there's no need for a run time package, so I don't understand what you are arguing about; You are the only one mentioning run-time executables.

 

Here's a complete solution in a single design-time package:

The component unit:

unit amAwesome;

interface

uses
  Classes;

type
  TMyAwesomeComponent = class(TComponent)
    // You awesome code here
  end;

implementation

end.

The design time unit:

unit amAwesomeDesign;

interface

procedure Register;

implementation

uses
  Classes,
  VCL.Dialogs,
  DesignIntf,
  DesignEditors,
  amAwesome;

type
  TMyAwesomeComponentEditor = class(TComponentEditor)
  public
    function GetVerb(Index: Integer): string; override;
    function GetVerbCount: Integer; override;
    procedure ExecuteVerb(Index: Integer); override;
  end;

procedure Register;
begin
  RegisterComponents('Awesome', [TMyAwesomeComponent]);
  RegisterComponentEditor(TMyAwesomeComponent, TMyAwesomeComponentEditor);
end;

procedure TMyAwesomeComponentEditor.ExecuteVerb(Index: Integer);
begin
  var LocalIndex := Index - inherited GetVerbCount;
  case (LocalIndex) of
    0: ShowMessage('TMyAwesomeComponent 1.0');
  else
    inherited ExecuteVerb(Index);
  end;
end;

function TMyAwesomeComponentEditor.GetVerb(Index: Integer): string;
begin
  var LocalIndex := Index - inherited GetVerbCount;
  case (LocalIndex) of
    0: Result := 'About...';
  else
    Result := inherited GetVerb(Index);
  end;
end;

function TMyAwesomeComponentEditor.GetVerbCount: Integer;
begin
  Result := inherited GetVerbCount + 1;
end;

end.

The design time package source:

package AwesomeSuite;

{$R *.res}
{yada yada yada lots of options here...}
{$DESIGNONLY}

requires
  rtl,
  designide;

contains
  amAwesome in 'amAwesome.pas',
  amAwesomeDesign in 'amAwesomeDesign.pas';
end.

 

Share this post


Link to post
10 minutes ago, Anders Melander said:

The OP asked for design time functionality. I replied with a design time solution and stated that there's no need for a run time package, so I don't understand what you are arguing about; You are the only one mentioning run-time executables.

The OP asked to implement a component with additional design-time functionality. The actual component itself needs to be in a run-time package, it can't be in a design-time package.  In the simple case where no design-time editors are being used, the run-time package and the design-time package can be the same package.  But as soon as editors are involved, that is no longer the case.  And you proposed using a component editor.  So that means implementing the component in a run-time package, and the editor in a separate design-time package.

10 minutes ago, Anders Melander said:

Here's a complete solution in a single design-time package:

TMyAwesomeComponent MUST be in a separate run-time package that the design-time package requires.  A design-time package is not linked into a compiled executable, only a run-time package is, so if you were to place TMyAwesomeComponent onto a Form Designer at design-time, it will certainly be visible at design-time, and its editor would work as expected, but at runtime when the compiled executable is actually run, TMyAwesomeComponent won't be available so the Form will fail to load properly.

Share this post


Link to post
1 hour ago, Remy Lebeau said:

The OP asked to implement a component with additional design-time functionality. The actual component itself needs to be in a run-time package

No one has mentioned run-time packages except you, so where does that requirement come from?

 

1 hour ago, Remy Lebeau said:

TMyAwesomeComponent MUST be in a separate run-time package that the design-time package requires.  A design-time package is not linked into a compiled executable, only a run-time package is, so if you were to place TMyAwesomeComponent onto a Form Designer at design-time, it will certainly be visible at design-time, and its editor would work as expected, but at runtime when the compiled executable is actually run, TMyAwesomeComponent won't be available so the Form will fail to load properly.

Again I'm puzzled why you keep explaining these things. I'm pretty sure you must be aware that I know all this already.

Besides that your explanation is wrong. The form will load just fine since the component unit has been linked directly into the application because it's not in a run-time package.

Share this post


Link to post
18 hours ago, Anders Melander said:

No one has mentioned run-time packages except you, so where does that requirement come from?

From Borland/Embarcadero.  A component used in an application can't be implemented in a design-time package, it must be implemented either in the application itself, or in a run-time package that is linked into the application.   Why are you contesting that?

18 hours ago, Anders Melander said:

Again I'm puzzled why you keep explaining these things. I'm pretty sure you must be aware that I know all this already.

I'm sure YOU know this, but not EVERYONE ELSE does.  And since the OP is delving into component development, this is important for the OP to understand this, since this is how components are intended to be designed.  Components go in run-time packages.  Editors go in design-time packages.

18 hours ago, Anders Melander said:

The form will load just fine since the component unit has been linked directly into the application because it's not in a run-time package.

True, it is not, because it is in a design-time package instead, BY YOUR OWN EXAMPLE.  A design-time package is NOT linked into an application, only the IDE itself uses a design-time package.  So, how do you expect the application to link to the component unit when it is inside a design-time package?  The application would have to static link to the unit directly instead, which would happen only if the unit's DCU or PAS file is on the application's search path, bypassing the design-time package entirely.

Share this post


Link to post
40 minutes ago, Remy Lebeau said:

A component used in an application can't be implemented in a design-time package, it must be implemented either in the application itself, or in a run-time package that is linked into the application.   Why are you contesting that?

I'm contesting the requirement to use run-time packages on the basis that I've written hundreds of components and I don't think I've ever had to use run time packages. There might have been cases where code was shared between different design-time packages, but that has apparently been so rare that I'm not sure if I remember it correctly.

I can't find any documentation that backs your claim (if I've understood you correctly) that the component must go into a run-time package regardless if you use run-time packages or not.

 

58 minutes ago, Remy Lebeau said:

Components go in run-time packages.  Editors go in design-time packages.

I agree that design-time editors (and component registration) go into design-time packages but unless you make the (often bad) choice to build your application with run-time packages there is no need to put the component into a run-time package. Who/what will use that package? The IDE will only use it because you've forced it to do so by creating a dependency from the design-time package to the run-time package.

 

46 minutes ago, Remy Lebeau said:

So, how do you expect the application to link to the component unit when it is inside a design-time package?  The application would have to static link to the unit directly instead, which would happen only if the unit's DCU or PAS file is on the application's search path, bypassing the design-time package entirely.

Yes, I expect the project to either have the pas or the dcu in the search path and I expect the compiler to static link to the dcu.

The design-time package isn't bypassed. It's used by the IDE and only by the IDE - at design-time.

Share this post


Link to post
4 hours ago, Anders Melander said:

I'm contesting the requirement to use run-time packages on the basis that I've written hundreds of components and I don't think I've ever had to use run time packages. There might have been cases where code was shared between different design-time packages, but that has apparently been so rare that I'm not sure if I remember it correctly.

I can't find any documentation that backs your claim (if I've understood you correctly) that the component must go into a run-time package regardless if you use run-time packages or not.

Well, then you are doing it differently than how the majority of other component developers do it.  Components are meant to be implemented in run-time packages.  If an application is built with run-time packages disabled, then the component's run-time package would be built statically into the application executable.  Otherwise the run-time package would be linked into the application dynamically via BPL file.  Either way, the application should not be linking in the actual component unit directly, it should be importing it from the run-time package, whether statically or dynamcially.

4 hours ago, Anders Melander said:

unless you make the (often bad) choice to build your application with run-time packages there is no need to put the component into a run-time package. Who/what will use that package? The IDE will only use it because you've forced it to do so by creating a dependency from the design-time package to the run-time package.

The application itself would have a linkage to the same runtime package, and the compiler would choose the static or dynamic version of the run-time package as needed by the application's build settings.

4 hours ago, Anders Melander said:

Yes, I expect the project to either have the pas or the dcu in the search path and I expect the compiler to static link to the dcu.

That means you run the risk of separate applications compiling against different copies of the component's PAS/DCU over time.  Rather than installing a single copy in the IDE for it to link into each application as needed.  Using a runtime package would also ensure the same version of the component that the IDE uses is the same version that is compiled/linked into each application.  And, in the case where you DO want to enable run-time packages, the component's DCU won't be linked statically.

 

Just because a component's source is compiled into a run-time package doesn't require the package to be DEPLOYED with the application, if the application has run-time packages disabled.  The package may be compiled statically into the application instead.  But, it does ensure that there is only 1 copy of the compiled component unit, in a place where it can be easily shared and reused as needed.  Sure, you can do the same thing by simply configuring separate application projects to link in the component's DCU directly, but that is not the appropriate or typical setup.  Maybe that is how YOU do it.  But that is not how MOST PEOPLE do it.

4 hours ago, Anders Melander said:

The design-time package isn't bypassed. It's used by the IDE and only by the IDE - at design-time.

As it should be.  But the component itself SHOULD be implemented in a run-time package that is shared by the design-time package and application projects, whether statically or dynamically, that doesn't change the fact that the component should be in a project for a run-time package.

Share this post


Link to post
9 hours ago, Remy Lebeau said:

Well, then you are doing it differently than how the majority of other component developers do it.

There are plenty of them here. It would be interesting to hear a Yea or Nay from some.

My understanding is that the only reason commercial component vendors ship run-time packages is to cater for users that build their applications with them - i.e. run-time linking.

 

9 hours ago, Remy Lebeau said:

That means you run the risk of separate applications compiling against different copies of the component's PAS/DCU over time. 

That is a separate problem with a very simple solution:

9 hours ago, Remy Lebeau said:

Sure, you can do the same thing by simply configuring separate application projects to link in the component's DCU directly, but that is not the appropriate or typical setup.

It may not be typical but that is exactly the way to do it.

By having the component source in the project path instead of the global path and by linking against the project's local copy of the dcu you avoid duplicate dcu and version conflicts.

 

The project I'm working on right now has something like 20-30 different branches under active development. I change my active branch maybe twice that amount during the day.
If I were to work by your model every time I changed the active branch I would need to recompile the close to 100 different design- and run-time packages related to this project, including 3rd party packages.
What I do now is just change the branch and keep on trucking.

And that's just on my local machine; I would need to do the same on all the build servers since apparently they have also been compiling and linking the wrong way all these years.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×