Recent

Author Topic: overwrite a procedure of a component without creating a new component  (Read 12216 times)

Blue1987

  • Full Member
  • ***
  • Posts: 165
dear all,
I was wondering if there is some way to overwrite a component procedure without creating a new component.

I mean, inserting

somewhere here
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows, Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls, Buttons, StdCtrls, ComCtrls, Spin, FileCtrl;

type       



or here
Code: [Select]
program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, Unit1, LResources;

{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF}

begin
  Application.Title:='calcio4ever2011';
  {$I project1.lrs}
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
                 

some piece of code in order to substitute a procedure of a component.
(say the "onPaint" procedure of a label), so that people modifying my code can easily also modify the way the component react to instruction (without being forced to install a new component made by me, modifying it, compile it and so on)


is it possibile?

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: overwrite a procedure of a component without creating a new component
« Reply #1 on: September 03, 2011, 12:16:50 am »
You mean something like this?

Code: [Select]
uses Windows, Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls, Buttons, StdCtrls, ComCtrls, Spin, FileCtrl, MyComponents;

type
  TForm1 = class(TForm)
    label1: TMyLabel;
...

procedure TForm1.FormCreate(Sender: TObject);
begin
  label1:=TMyLabel.Create(self);
  with label1 do begin
    Left:=100;
    Top:=50;
    Caption:='Hello world!';
  end;
end;

Code: [Select]
unit MyComponents;

type
  TMyLabel = ...

Blue1987

  • Full Member
  • ***
  • Posts: 165
Re: overwrite a procedure of a component without creating a new component
« Reply #2 on: September 03, 2011, 12:43:15 am »
no. I mean that every label (the default TLabel) in the form does not run the default "OnPaint" procedure but a "OnPaint" customized (and easily customizable) procedure written somewhere in the code.




(even if your approach probably can solve my problem)
(the fact is that I already have created an interface with thousends TLabel in the form...)
« Last Edit: September 03, 2011, 12:45:38 am by Blue1987 »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: overwrite a procedure of a component without creating a new component
« Reply #3 on: September 03, 2011, 01:58:00 am »
you mean something like:
Code: [Select]
type
  TForm1 = class(TForm)
    ...
    procedure CustomOnPaint(Sender: TObject);
    ...
  end;

...

// assuming you want to change the handler upon form's OnCreate:
procedure TForm1.Form1Create(Sender: TObject);
begin
  Label1.OnPaint := @CustomOnPaint;
end;

Blue1987

  • Full Member
  • ***
  • Posts: 165
Re: overwrite a procedure of a component without creating a new component
« Reply #4 on: September 03, 2011, 02:05:33 am »
maybe yes!  :D
(surely this way it is quite long, but I might succed!!)

is it possibile to automatically apply it to every Tlabel in the form?

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: overwrite a procedure of a component without creating a new component
« Reply #5 on: September 03, 2011, 02:12:29 am »
TLabel nor TStaticText has no OnPaint event here.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: overwrite a procedure of a component without creating a new component
« Reply #6 on: September 03, 2011, 09:33:08 am »
Quote
is it possibile to automatically apply it to every Tlabel in the form?
Nope, you have to loop over them
Quote
TLabel nor TStaticText has no OnPaint event here.
It does have, but protected, so I guess the best way is to create a descendant control and override Paint there.

bertherngreen

  • New Member
  • *
  • Posts: 13
Re: overwrite a procedure of a component without creating a new component
« Reply #7 on: September 03, 2011, 09:50:23 am »
Quote
no. I mean that every label (the default TLabel) in the form does not run the default "OnPaint" procedure but a "OnPaint" customized (and easily customizable) procedure written somewhere in the code.

yes you can locally (the chosen form) use your 'own' Tlabel, by using the original namespace:

Code: [Select]
type

  { Tlabel }

  Tlabel = class(StdCtrls.TLabel)
  public
    // Choose a certain method to override it;
    procedure Paint; override;
  end;

  { TForm1 }

  TForm1 = class(TForm)
...

Press ctrl-shift-c for completing the TLabel class.
Code: [Select]
implementation

{ Tlabel }

procedure Tlabel.Paint;
begin
  inherited Paint;

  // Whatever code put it here....
  Showmessage('bla');
end;
       

Nothing extra has to done to support this. (No form redesign/ no own packages/ no own component registration, however this works in the form where you implemented this only.)
« Last Edit: September 03, 2011, 09:52:46 am by bertherngreen »

Blue1987

  • Full Member
  • ***
  • Posts: 165
Re: overwrite a procedure of a component without creating a new component
« Reply #8 on: September 03, 2011, 11:47:54 am »
you mean something like:
Code: [Select]
type
  TForm1 = class(TForm)
    ...
    procedure CustomOnPaint(Sender: TObject);
    ...
  end;

...

// assuming you want to change the handler upon form's OnCreate:
procedure TForm1.Form1Create(Sender: TObject);
begin
  Label1.OnPaint := @CustomOnPaint;
end;



Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure CustomPaint(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{custom procedures}
procedure CustomPaint(Sender: TObject);
var
  TR : TTextStyle;
  R : TRect;
  TextLeft, TextTop: integer;
  LabelText: string;
  OldFontColor: TColor;
begin
  R := Rect(0,0,Width,Height);
  with Canvas do
  begin
    if Enabled then
      Brush.Color := Self.Color
    else
      Brush.Color := clNone;
    Font := Self.Font;
    if (Color<>clNone) and not Transparent then
    begin
      Brush.Style:=bsSolid;
      FillRect(R);
    end else
      Brush.Style:=bsClear;
    FillChar(TR,SizeOf(TR),0);
    with TR do
    begin
      Alignment := BidiFlipAlignment(Self.Alignment, UseRightToLeftAlignment);
      WordBreak := wordWrap;
      SingleLine:= not WordWrap and not HasMultiLine;
      Clipping := True;
      ShowPrefix := ShowAccelChar;
      SystemFont := False;
      RightToLeft := UseRightToLeftReading;
      ExpandTabs := True;
    end;
    DoMeasureTextPosition(TextTop, TextLeft);
    LabelText := GetLabelText;
    OldFontColor := Font.Color;
    if not Enabled then
    begin
      Font.Color := clBtnHighlight;
      TextRect(R, TextLeft + 1, TextTop + 1, LabelText, TR);
      Font.Color := clBtnShadow;
    end;
    TextRect(R, TextLeft, TextTop, LabelText, TR);
    Font.Color := OldFontColor;
  end;
end;


{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  label2.Paint:=@custompaint;
end;

end.



for me, it did not work. he cannot identify "width", "height", "canvas" and so on...


if this worked it could be something really interesting, since in this manner I could chose a customized standard procedure for all the labels, and a customized customized  :D for some label...

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: overwrite a procedure of a component without creating a new component
« Reply #9 on: September 03, 2011, 01:34:51 pm »
Quote
{custom procedures}
procedure TForm1.CustomPaint(Sender: TObject);

Blue1987

  • Full Member
  • ***
  • Posts: 165
Re: overwrite a procedure of a component without creating a new component
« Reply #10 on: September 03, 2011, 03:36:54 pm »
Quote
{custom procedures}
procedure TForm1.CustomPaint(Sender: TObject);

thanks! that's better, but still...
Code: [Select]
unit1.pas(49,40) Error: Identifier not found "Transparent"
unit1.pas(55,16) Hint: Local variable "TR" does not seem to be initialized
unit1.pas(58,43) Error: identifier idents no member "Alignment"
unit1.pas(59,28) Error: Identifier not found "wordWrap"
unit1.pas(60,33) Error: Identifier not found "WordWrap"
unit1.pas(60,53) Error: Identifier not found "HasMultiLine"
unit1.pas(62,34) Error: Identifier not found "ShowAccelChar"
unit1.pas(67,26) Error: Identifier not found "DoMeasureTextPosition"
unit1.pas(68,30) Error: Identifier not found "GetLabelText"
unit1.pas(73,19) Warning: Local variable "TextLeft" does not seem to be initialized
unit1.pas(73,33) Warning: Local variable "TextTop" does not seem to be initialized
unit1.pas(86,9) Error: Argument can't be assigned to
unit1.pas(86,17) Error: Incompatible types: got "<procedure variable type of procedure(TObject) of object;Register>" expected "untyped"
unit1.pas(91) Fatal: There were 10 errors compiling module, stopping

some are procedures you can find in "customlabel.inc"...

Elmug

  • Hero Member
  • *****
  • Posts: 849
Re: overwrite a procedure of a component without creating a new component
« Reply #11 on: September 03, 2011, 05:05:49 pm »
dear all,
I was wondering if there is some way to overwrite a component procedure without creating a new component.

I mean, inserting

somewhere here
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows, Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls, Buttons, StdCtrls, ComCtrls, Spin, FileCtrl;

type       



or here
Code: [Select]
program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, Unit1, LResources;

{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF}

begin
  Application.Title:='calcio4ever2011';
  {$I project1.lrs}
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
                 

some piece of code in order to substitute a procedure of a component.
(say the "onPaint" procedure of a label), so that people modifying my code can easily also modify the way the component react to instruction (without being forced to install a new component made by me, modifying it, compile it and so on)


is it possibile?

Blue1987, would simply changing the name of the procedure that the component fires do what you want? You could have a button to change the event name of a component, using the Select-file dialog.

Blue1987

  • Full Member
  • ***
  • Posts: 165
Re: overwrite a procedure of a component without creating a new component
« Reply #12 on: September 03, 2011, 05:30:33 pm »
Blue1987, would simply changing the name of the procedure that the component fires do what you want? You could have a button to change the event name of a component, using the Select-file dialog.

sorry but I did not understand your suggestion! what would it imply to simply change the name of the event of a component?

I would like to override a procedure such as ".paint" (in the first message I made a mistake... did not mean "OnPaint" but "Paint")
what I want to do is to understand how:
- substitute the "paint" procedure of all label in a form
- substitute the "paint" procedure of some label in the form

without using different components then the standard TLabel.


I frankly did not have understood what you mean with your advice! can you explain it again? (maybe it is my fault since I am a beginner in programming, and I am not a native english speaker... sorry)

Elmug

  • Hero Member
  • *****
  • Posts: 849
Re: overwrite a procedure of a component without creating a new component
« Reply #13 on: September 03, 2011, 08:44:09 pm »
Blue1987, would simply changing the name of the procedure that the component fires do what you want? You could have a button to change the event name of a component, using the Select-file dialog.

sorry but I did not understand your suggestion! what would it imply to simply change the name of the event of a component?

I would like to override a procedure such as ".paint" (in the first message I made a mistake... did not mean "OnPaint" but "Paint")
what I want to do is to understand how:
- substitute the "paint" procedure of all label in a form
- substitute the "paint" procedure of some label in the form

without using different components then the standard TLabel.


I frankly did not have understood what you mean with your advice! can you explain it again? (maybe it is my fault since I am a beginner in programming, and I am not a native english speaker... sorry)

Hi Blue, you change the name of the Event (procedure) that the component fires, not the name of the component.

Blue1987

  • Full Member
  • ***
  • Posts: 165
Re: overwrite a procedure of a component without creating a new component
« Reply #14 on: September 03, 2011, 09:35:17 pm »
Quote
no. I mean that every label (the default TLabel) in the form does not run the default "OnPaint" procedure but a "OnPaint" customized (and easily customizable) procedure written somewhere in the code.

yes you can locally (the chosen form) use your 'own' Tlabel, by using the original namespace:

Code: [Select]
type

  { Tlabel }

  Tlabel = class(StdCtrls.TLabel)
  public
    // Choose a certain method to override it;
    procedure Paint; override;
  end;

  { TForm1 }

  TForm1 = class(TForm)
...

Press ctrl-shift-c for completing the TLabel class.
Code: [Select]
implementation

{ Tlabel }

procedure Tlabel.Paint;
begin
  inherited Paint;

  // Whatever code put it here....
  Showmessage('bla');
end;
       

Nothing extra has to done to support this. (No form redesign/ no own packages/ no own component registration, however this works in the form where you implemented this only.)


now I am solving my problem with this solution...
by the way... is there any way to declare a new (integer) variable, say TLabel.spaceU, for the Tlabel and set it equal to 0 by default?

 

TinyPortal © 2005-2018