* * *

Author Topic: class of graphical objects  (Read 1035 times)

GregB

  • New member
  • *
  • Posts: 14
class of graphical objects
« on: August 10, 2017, 01:15:44 pm »
I am trying to  make a mainform with a mainmenu that displays a textbox a stringgrid and a static text.
the stringgrid is to allow a user to enter data and the code is in a separate unit. The static text displays hints depending on which column in the stringgrid is active

the code below is a test to see how i can achieve this.  Why am i not able to access the events such as onKeyPress without having to point to the method.

I am guessing there is an easier way to achieve this - any suggestions greatly appreciated.
 
Code: Pascal  [Select]
  1. unit uMain;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  9.   Grids, ActnList, Menus,
  10.   ueditor;
  11.  
  12. type
  13.  
  14.   { TMainForm }
  15.  
  16.   TMainForm = class(TForm)
  17.     myeditor: TMyEditor;
  18.     MainMenu1: TMainMenu;
  19.     MenuItem1: TMenuItem;
  20.     mnu_fileopen: TMenuItem;
  21.     mnu_filenew: TMenuItem;
  22.     mnu_calc: TMenuItem;
  23.     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  24.     procedure FormCreate(Sender: TObject);
  25.     procedure mnu_filenewClick(Sender: TObject);
  26.   private
  27.  
  28.   public
  29.  
  30.   end;
  31.  
  32. var
  33.   MainForm: TMainForm;
  34.   myEditor: TMyEditor;
  35.  
  36. const
  37.   Count: integer = 0;
  38.  
  39. implementation
  40.  
  41. {$R *.lfm}
  42.  
  43. { TMainForm }
  44. //uses
  45. //  uEditor;
  46.  
  47.  
  48. procedure TMainForm.FormCreate(Sender: TObject);
  49. begin
  50.   myEditor := TMyEditor.Create(MainForm);
  51.   myEditor.Parent := MainForm;
  52.  
  53.   myEditor.InitialiseEditor(Sender);
  54. end;
  55.  
  56.  
  57. procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  58. begin
  59.   myEditor.CloseEditor(Sender);
  60. end;
  61.  
  62.  
  63. procedure TMainForm.mnu_filenewClick(Sender: TObject);
  64. var
  65.   self: TComponent;
  66. begin
  67.   Inc(Count);
  68.   myeditor.sgeditor.Clean([gzNormal]);
  69.   myeditor.Edit1.Text := Count.ToString;
  70. end;
  71.  
  72. end.                    
  73.  


Code: Pascal  [Select]
  1. unit uEditor;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$M+}
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Grids, Dialogs,
  9.   StdCtrls, Forms, Controls;
  10.  
  11. type
  12.   TmyEditor = class(TControl)
  13.     // TControl is the base class for all graphical objects - defined in controls
  14.     sgeditor: TStringGrid;
  15.     Edit1: TEdit;
  16.     StaticText1: TStaticText;
  17.     procedure InitialiseEditor(Sender: TObject);
  18.     procedure CloseEditor(Sender: TObject);
  19.  
  20.  
  21.   public
  22.     //Constructor Create(sender : TObject);
  23.  
  24.   private
  25.     procedure sgGetCellHint(Sender: TObject; ACol, ARow: integer;
  26.       var HintText: string);
  27.     procedure sgValidateEntry(Sender: TObject; aCol, aRow: integer;
  28.       const OldValue: string; var NewValue: string);
  29.     procedure sgKeyPress(Sender: TObject; var Key: char);
  30.  
  31.   end;
  32.  
  33.  
  34. implementation
  35.  
  36. uses
  37.   uMain;
  38.  
  39. procedure TmyEditor.CloseEditor(Sender: TObject);
  40. begin
  41.   myeditor.Free;
  42. end;
  43.  
  44.  
  45. procedure TmyEditor.InitialiseEditor(Sender: TObject);
  46. var
  47.   self: TComponent;
  48. begin
  49.  
  50.   {------------EDIT BOX------------}
  51.   edit1 := TEdit.Create(self);
  52.   edit1.Parent := MainForm;
  53.  
  54.   edit1.AnchorSideLeft.Control := MainForm;
  55.   edit1.AnchorSideTop.Control := MainForm;
  56.   edit1.AnchorSideRight.Control := MainForm;
  57.   edit1.AnchorSideRight.Side := asrBottom;
  58.   edit1.AnchorSideBottom.Side := asrBottom;
  59.   edit1.Anchors := [akTop, akLeft, akRight];
  60.   edit1.BorderSpacing.Left := 25;
  61.   edit1.BorderSpacing.Top := 10;
  62.   edit1.BorderSpacing.Right := 25;
  63.   edit1.BorderSpacing.Bottom := 10;
  64.  
  65.  
  66.   {------------STATIC TEXT------------}
  67.   statictext1 := TStaticText.Create(self);
  68.   statictext1.Parent := MainForm;
  69.  
  70.   statictext1.Height := 35;
  71.   statictext1.Visible := True;
  72.   statictext1.AnchorSideLeft.Control := MainForm;
  73.   statictext1.AnchorSideTop.Side := asrCenter;
  74.   statictext1.AnchorSideRight.Control := MainForm;
  75.   statictext1.AnchorSideRight.Side := asrBottom;
  76.   statictext1.AnchorSideBottom.Control := MainForm;
  77.   statictext1.AnchorSideBottom.Side := asrBottom;
  78.   statictext1.Anchors := [akLeft, akRight, akBottom];
  79.   statictext1.BorderSpacing.Bottom := 5;
  80.   statictext1.BorderSpacing.Around := 10;
  81.  
  82.  
  83.   {------------STRING GRID------------}
  84.   sgEditor := TStringGrid.Create(self);
  85.   sgEditor.Parent := MainForm;
  86.  
  87.   //sgEditor.Visible:=True;
  88.   sgeditor.Options := sgeditor.options + [goEditing, goAlwaysShowEditor, goCellHints];
  89.   sgeditor.ColCount := 10;
  90.   sgeditor.RowCount := 10;
  91.   sgeditor.AnchorSideLeft.Control := MainForm;
  92.   sgeditor.AnchorSideTop.Control := Edit1;
  93.   sgeditor.AnchorSideTop.Side := asrBottom;
  94.   sgeditor.AnchorSideRight.Control := MainForm;
  95.   sgeditor.AnchorSideRight.Side := asrBottom;
  96.   sgeditor.AnchorSideBottom.Control := StaticText1;
  97.   sgeditor.AnchorSideBottom.Side := asrTop;
  98.   sgeditor.Anchors := [akTop, akLeft, akRight, akBottom];
  99.   sgeditor.BorderSpacing.Left := 25;
  100.   sgeditor.BorderSpacing.Top := 10;
  101.   sgeditor.BorderSpacing.Right := 25;
  102.   sgeditor.BorderSpacing.Bottom := 10;
  103.  
  104.  
  105.   sgeditor.OnGetCellHint := @sgGetCellHint;
  106.   sgeditor.OnGetEditText := @sgGetCellHint;
  107.   sgeditor.OnValidateEntry := @sgValidateEntry;
  108.   sgeditor.OnKeyPress := @sgKeyPress;
  109. end;
  110.  
  111.  
  112. procedure TMyEditor.sgKeyPress(Sender: TObject; var Key: char);
  113. var
  114.   validkeys: set of char;
  115. begin
  116.   case (Sender as TStringGrid).col of
  117.     1: validkeys := ['0'..'9'];
  118.     2: validkeys := ['a'..'z'];
  119.     3: validkeys := ['A'..'Z'];
  120.     else
  121.       validkeys := [#0..#255];
  122.   end;
  123.   if not (key in validkeys) then
  124.     key := #0;
  125. end;
  126.  
  127.  
  128. procedure TMyEditor.sgValidateEntry(Sender: TObject; aCol, aRow: integer;
  129.   const OldValue: string; var NewValue: string);
  130. begin
  131.   case aCol of
  132.     1: edit1.Text := sgeditor.Cells[aCol, aRow];
  133.   end;
  134. end;
  135.  
  136.  
  137. {===============================================================================
  138.   shows a hint in statictext1 when cursor moves over cell
  139.  ===============================================================================}
  140. procedure TmyEditor.sgGetCellHint(Sender: TObject; ACol, ARow: integer;
  141.   var HintText: string);
  142. begin
  143.   statictext1.Caption := '';
  144.   case acol of
  145.     1: statictext1.Caption := 'Traverse (T) or Radiation (R)   ... default is Traverse';
  146.     2: statictext1.Caption := 'Metres (M), Links (L), Feet (F) ... default is metres';
  147.     3: statictext1.Caption :=
  148.         '+ve includes sector in area, -ve excludes sector from area';
  149.     4: statictext1.Caption :=
  150.         '"." => repeat previous bearing' + #13#10 + '"R" => reverse bearing';
  151.     5: statictext1.Caption := '"." => repeat previous distance';
  152.  
  153.   end;
  154. end;
  155.  
  156.  
  157. end.
  158.  
« Last Edit: August 10, 2017, 01:41:51 pm by GregB »

Handoko

  • Hero Member
  • *****
  • Posts: 1768
  • My goal: build my own game engine using Lazarus
Re: class of graphical objects
« Reply #1 on: August 10, 2017, 06:33:37 pm »
I can't compile the code you provided. Can you please copy all the necessary files (except binaries, *.bak and lib folder) to a new folder, compress the folder and attach the zip file to this forum?

Why am i not able to access the events such as onKeyPress without having to point to the method.

On which form? Which method?

howardpc

  • Hero Member
  • *****
  • Posts: 2421
Re: class of graphical objects
« Reply #2 on: August 10, 2017, 07:09:28 pm »
Rather than detail the various shortcomings in your code, see the attached project, adapted from your code. I think it may do what you want.
The TEditor class need only descend from TObject, since it is basically just a container for controls that are parented elsewhere.

I have not changed your validation event handler, but I doubt that it would prove satisfactory in use.

GregB

  • New member
  • *
  • Posts: 14
Re: class of graphical objects
« Reply #3 on: August 12, 2017, 09:50:23 am »
Thanks Handoko and Howard.

I have had a close look at your code Howard and it does precisely what I wanted .. the only thing I do not understand with your code is why you declare

Code: Pascal  [Select]
  1. var
  2.   validkeys: set of Char;
  3.   [color=red]sgrid: TStringGrid absolute Sender;[/color]
  4. begin
  5.   if not (Sender is TStringGrid) then
  6.     Exit;
  7.   case sgrid.Col of
  8.     1: validkeys := ['0'..'9'];
  9.     2: validkeys := ['a'..'z'];
  10.     3: validkeys := ['A'..'Z'];
  11.     else
  12.        validkeys := [#0..#255];
  13.   end;
  14.   if not (Key in validkeys) then
  15.     Key := #0;
  16. end;
  17.  

What is the advantage of using the absolute declaration instead of

Code: Pascal  [Select]
  1.     case (Sender as TStringGrid).col of
  2.  


Thanks again for your help.
« Last Edit: August 12, 2017, 09:56:25 am by GregB »

Handoko

  • Hero Member
  • *****
  • Posts: 1768
  • My goal: build my own game engine using Lazarus
Re: class of graphical objects
« Reply #4 on: August 12, 2017, 10:01:09 am »
Basically they they are same. But if you need to access that item several times, it will be less typing and more readable.

howardpc

  • Hero Member
  • *****
  • Posts: 2421
Re: class of graphical objects
« Reply #5 on: August 12, 2017, 11:30:52 am »
They are not the same.
The construction using "as" will raise an exception if Sender is not a TStringGrid.
The alternative I mostly prefer tests the classtype of Sender and exits silently without raising an exception if for some reason Sender is not the expected type, otherwise the code proceeds with a safe direct typecast.

Exceptions are often over-used, and they are not at all user friendly. Often they are a symptom of programmer error, in which case users should not be forced to deal with them or have their application end unexpectedly because of some error that is not their fault.
As in this case.
It is hard to think of a scenario in which Sender would not be the expected type, but it could happen, and production quality code should provide for it. Indeed, the only such situation I can envisage is if the programmer intervened to change Sender deliberately, or if, for other reasons, it were Nil. This is pure programming error territory. Not something you want to make a user have to deal with by forcing an exception with "as".
« Last Edit: August 12, 2017, 11:45:50 am by howardpc »

GregB

  • New member
  • *
  • Posts: 14
Re: class of graphical objects
« Reply #6 on: August 16, 2017, 12:15:52 pm »
I have now extended this by putting the editor (stringgrid, statictext and edit) on a TabSheet in a TPageControl.

I have a memory leak that i cannot eliminate ... I am only able to free the editor on one of the pages.

Greatly appreciate any help.


Code: Pascal  [Select]
  1. unit uMain;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils, Forms, Menus, ComCtrls,
  9.   ueditor, Classes, Dialogs, StdCtrls;
  10.  
  11. type
  12.  
  13.   { TMainForm }
  14.   TMainForm = class(TForm)
  15.     Edit1: TEdit;
  16.     PageControl1: TPageControl;
  17.     MainMenu1: TMainMenu;
  18.     MenuItem1: TMenuItem;
  19.  
  20.     mnu_newtraverse: TMenuItem;
  21.     mnu_fileopen: TMenuItem;
  22.     mnu_filenew: TMenuItem;
  23.     mnu_calc: TMenuItem;
  24.  
  25.     procedure FormCreate(Sender: TObject);
  26.     procedure FormDestroy(Sender: TObject; var CloseAction: TCloseAction);
  27.     procedure mnu_newtraverseClick(Sender: TObject);
  28.     procedure PageControl1Change(Sender: TObject);
  29.  
  30.   private
  31.     myeditor : TMyEditor;
  32.     procedure FileNewOnClick(Sender: TObject);
  33.  
  34.   public
  35.  
  36.   end;
  37.  
  38. var
  39.   MainForm: TMainForm;
  40.   idx : integer;
  41.  
  42. implementation
  43.  
  44. {$R *.lfm}
  45.  
  46. {Self = TMainForm, Sender = TMenuItem}
  47. procedure TMainForm.FileNewOnClick(Sender: TObject);
  48. begin
  49.   //ShowMessage('FileNewOnClick' + #13#10 + 'Self = ' + Self.ClassName +#13#10 + 'Sender = ' + sender.ClassName);
  50.   myEditor := TMyEditor.Create(PageControl1);
  51.   myeditor.ShowEditor;
  52. end;
  53.  
  54.  
  55. {Self = TMainForm, Sender = TMainForm}
  56. procedure TMainForm.FormCreate(Sender: TObject);
  57. begin
  58.   //ShowMessage('FormCreate' + #13#10 + 'Self = ' + Self.ClassName +#13#10 + 'Sender = ' + sender.ClassName);
  59.   mnu_FileNew.OnClick:=@FileNewOnClick;
  60.  
  61. end;
  62.  
  63.  
  64. {Self = TMainForm, Sender = TMainForm}
  65. procedure TMainForm.FormDestroy(Sender: TObject; var CloseAction: TCloseAction);
  66. var
  67.   i : integer;
  68. begin
  69.   for idx := PageControl1.PageCount-1 downto 0 do
  70.   begin
  71.  
  72.     PageControl1.Pages[idx].Free;
  73.     //PageControl1.ActivePage.Free;
  74.     //PageControl1.SelectNextPage(True,False);
  75.   end;
  76.   myeditor.Free;
  77. end;
  78.  
  79.  
  80. {Self = TMainForm, Sender = TMenuItem}
  81. procedure TMainForm.mnu_newtraverseClick(Sender: TObject);
  82. begin
  83.   //ShowMessage('NewTraverseClick' + #13#10 + 'Self = ' + Self.ClassName +#13#10 + 'Sender = ' + sender.ClassName);
  84.   myEditor := TMyEditor.Create(PageControl1);
  85.   myeditor.ShowEditor;
  86. end;
  87.  
  88.  
  89. procedure TMainForm.PageControl1Change(Sender: TObject);
  90. begin
  91.   edit1.text:= 'Page control change .. ' + PageControl1.ActivePageIndex.ToString;
  92. end;
  93.  
  94.  
  95. end.
  96.  
  97.  


Code: Pascal  [Select]
  1. unit uEditor;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Grids, StdCtrls, Forms, Controls, Comctrls,
  9.   Dialogs;
  10.  
  11. // http://www.drbob42.com/delphi/componen.htm
  12. Type
  13.   TmyEditor = Class(TObject)   //*TControl // TControl is the base class for all graphical objects - defined in controls
  14.   private
  15.     TabSheet: TTabSheet;
  16.  
  17.     sgeditor : TStringGrid;
  18.     Edit1: TEdit;
  19.     StaticText1: TStaticText;
  20.  
  21.     procedure sgGetCellHint(Sender: TObject; ACol, ARow: Integer;
  22.       var HintText: String);
  23.     procedure sgValidateEntry(sender: TObject; aCol, aRow: Integer;
  24.       const OldValue: string; var NewValue: String);
  25.     procedure sgKeyPress(Sender: TObject; var Key: char);
  26.  
  27.   public
  28.     Constructor Create(anOwnerPgCtrl : TPageControl);   //*sender : TObject
  29.  
  30.     Procedure ShowEditor;
  31.     Procedure HideEditor;
  32.  
  33.   end;
  34.  
  35.  
  36. implementation
  37.  
  38.  
  39. Procedure TmyEditor.ShowEditor;
  40. begin
  41.   sgeditor.Show;
  42.   edit1.Show;
  43.   statictext1.Show;
  44. end;
  45.  
  46.  
  47. Procedure TmyEditor.HideEditor;
  48. begin
  49.   sgeditor.Hide;
  50.   edit1.Hide;
  51.   statictext1.Hide;
  52. end;
  53.  
  54.  
  55.  
  56. {Self = TMyEditor, Sender = }
  57. Constructor TmyEditor.Create(anOwnerPgCtrl : TPageControl);
  58. begin
  59.   TabSheet := TTabSheet.Create(anOwnerPgCtrl);  //PageControl1
  60.   TabSheet.PageControl := anOwnerPgCtrl;
  61.  
  62.   anOwnerPgCtrl.SelectNextPage(True,False);
  63.   TabSheet.Caption := 'Tab Sheet ' + TabSheet.TabIndex.ToString;
  64.  
  65.   {------------EDIT BOX------------}
  66.   edit1 := TEdit.Create(anOwnerPgCtrl.ActivePage);
  67.  
  68.   edit1.Anchors := [akTop, akLeft, akRight];
  69.   edit1.AnchorSideLeft.Control := anOwnerPgCtrl.ActivePage;
  70.   edit1.AnchorSideTop.Control := anOwnerPgCtrl.ActivePage;
  71.   edit1.AnchorSideRight.Control := anOwnerPgCtrl.ActivePage;
  72.  
  73.   edit1.AnchorSideRight.Side := asrRight;
  74.   //edit1.AnchorSideBottom.Side := asrBottom;
  75.  
  76.   edit1.BorderSpacing.Left := 25;
  77.   edit1.BorderSpacing.Top := 10;
  78.   edit1.BorderSpacing.Right := 25;
  79.   edit1.BorderSpacing.Bottom := 10;
  80.   edit1.Parent := anOwnerPgCtrl.ActivePage;
  81.  
  82.   {------------STATIC TEXT------------}
  83.   statictext1 := TStaticText.Create(anOwnerPgCtrl.ActivePage); //*(self)
  84.  
  85.   statictext1.Anchors := [akLeft, akRight, akBottom];
  86.  
  87.   statictext1.Visible:=True;
  88.   statictext1.AnchorSideLeft.Control := anOwnerPgCtrl.ActivePage;
  89.   statictext1.AnchorSideRight.Control := anOwnerPgCtrl.ActivePage;
  90.   statictext1.AnchorSideBottom.Control := anOwnerPgCtrl.ActivePage;
  91.  
  92.   //statictext1.AnchorSideTop.Side := asrCenter;
  93.   statictext1.AnchorSideRight.Side := asrBottom;
  94.   statictext1.AnchorSideBottom.Side := asrBottom;
  95.  
  96.   statictext1.Height:=35;
  97.   statictext1.BorderSpacing.Bottom := 5;
  98.   statictext1.BorderSpacing.Around := 10;
  99.   statictext1.Parent := anOwnerPgCtrl.ActivePage;
  100.  
  101.   {------------STRING GRID------------}
  102.   sgEditor := TStringGrid.Create(anOwnerPgCtrl.ActivePage); //*(self)
  103.  
  104.   sgeditor.Options:=sgeditor.options+[goEditing, goAlwaysShowEditor, goCellHints];
  105.   sgeditor.ColCount:=10;
  106.   sgeditor.RowCount:=10;
  107.  
  108.   sgeditor.Anchors := [akTop, akLeft, akRight, akBottom];
  109.   sgeditor.AnchorSideLeft.Control := anOwnerPgCtrl.ActivePage;
  110.   sgeditor.AnchorSideRight.Control := anOwnerPgCtrl.ActivePage;
  111.   sgeditor.AnchorSideTop.Control := Edit1;
  112.   sgeditor.AnchorSideBottom.Control := StaticText1;
  113.  
  114.   sgeditor.AnchorSideTop.Side := asrBottom;
  115.   sgeditor.AnchorSideRight.Side := asrBottom;
  116.   sgeditor.AnchorSideBottom.Side := asrTop;
  117.  
  118.   sgeditor.BorderSpacing.Left := 25;
  119.   sgeditor.BorderSpacing.Top := 10;
  120.   sgeditor.BorderSpacing.Right := 25;
  121.   sgeditor.BorderSpacing.Bottom := 10;
  122.   sgeditor.Parent := anOwnerPgCtrl.ActivePage;
  123.  
  124.   sgeditor.OnGetCellHint := @sgGetCellHint;
  125.   sgeditor.OnGetEditText := @sgGetCellHint;
  126.   sgeditor.OnKeyPress := @sgKeyPress;
  127.   sgeditor.OnValidateEntry := @sgValidateEntry;
  128.  
  129.   HideEditor;
  130. end;
  131.  
  132.  
  133. procedure TMyEditor.sgKeyPress(Sender: TObject; var Key: char);
  134. var
  135.   validkeys : set of char;
  136. begin
  137.   case (Sender as TStringGrid).col of
  138.     1 : validkeys := ['0'..'9'];
  139.     2 : validkeys := ['a'..'z'];
  140.     3 : validkeys := ['A'..'Z'];
  141.   else
  142.     validkeys := [#0..#255];
  143.   end;
  144.   if not(key in validkeys) then key := #0;
  145. end;
  146.  
  147.  
  148. procedure TMyEditor.sgValidateEntry(sender: TObject; aCol, aRow: Integer;
  149.   const OldValue: string; var NewValue: String);
  150. begin
  151.   Case aCol of
  152.     1 :  edit1.Text:=sgeditor.Cells[aCol,aRow];
  153.   end;
  154. end;
  155.  
  156.  
  157. {===============================================================================
  158.   shows a hint in statictext1 when cursor moves over cell
  159.  ===============================================================================}
  160. procedure TmyEditor.sgGetCellHint(Sender: TObject; ACol, ARow: Integer;
  161.   var HintText: String);
  162. begin
  163.   statictext1.Caption := '';
  164.   Case acol of
  165.     1 : statictext1.Caption := 'Traverse (T) or Radiation (R)   ... default is Traverse';
  166.     2 : statictext1.Caption := 'Metres (M), Links (L), Feet (F) ... default is metres';
  167.     3 : statictext1.Caption := '+ve includes sector in area, -ve excludes sector from area';
  168.     4 : statictext1.Caption := '"." => repeat previous bearing' + #13#10 + '"R" => reverse bearing';
  169.     5 : statictext1.Caption := '"." => repeat previous distance';
  170.  
  171.   end;
  172. end;
  173.  
  174.  
  175. end.
  176.  
  177.  
  178.  

Thaddy

  • Hero Member
  • *****
  • Posts: 4745
Re: class of graphical objects
« Reply #7 on: August 16, 2017, 01:14:37 pm »
This is really beyond me:
Code: Pascal  [Select]
  1. Type
  2.   TmyEditor = Class(TObject)   //*TControl // TControl is the base class for all graphical objects - defined in controls

So why don't you use:
Code: Pascal  [Select]
  1. Type
  2.   TmyEditor = Class(TControl)
???? 
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

howardpc

  • Hero Member
  • *****
  • Posts: 2421
Re: class of graphical objects
« Reply #8 on: August 16, 2017, 05:41:23 pm »
Perhaps the attached project gives you some hints (with no memory leak).

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus