Recent

Author Topic: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before  (Read 10469 times)

wpflum

  • Sr. Member
  • ****
  • Posts: 287
I working on a project where I want the object to define it's own form instead of using a stored one.  I've done this before so I just copied what I did before but this time I'm getting an 'External: SIGSEGV' error on the TForm.Create(nil) line.  The program I used this in before was compiled with an older version of Lazarus, from last year I think, so I'm not sure what I'm missing.  Below is the code for the Class object it's not finished but testable.

Any ideas?

Code: [Select]

unit InvoiceHeaderClass;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils,forms;

var
   NextInvNum:integer; {Global invoice number that can be set from the outside but will be incremented by the object}

type
     Tinvheader = class
       Private
       InvNum: integer;
       SalesNum: integer;
       CustCode: string;
       CustName: string;
       CustAddr1: string;
       CustAddr2: string;
       CustCity: string;
       CustState: string;
       CustZip:string;
       CustPhone:string;
       InvDate:TDateTime;
       HeadScreen:TForm;

       procedure SetNumData(Index:integer ; targetdata : integer);
       procedure SetStrData(Index : integer ;targetdata : string);
       function GetStrData(Index:integer):string;
       function GetNumData(Index:integer):integer;

       Public
       Constructor Create();
       property InvoiceNumber :integer index 1 read GetNumData write SetNumData;
       property SalespersonNumber :integer index 2 read GetNumData write SetNumData;
       property CustomerCode:string index 1 read GetStrData write SetStrData;
       property CustomerName: string index 2 read GetStrData write SetStrData;
       property CustomerAddr1: string index 3 read GetStrData write SetStrData;
       property CustomerAddr2: string index 4 read GetStrData write SetStrData;
       property CustomerCity: string index 5 read GetStrData write SetStrData;
       property CustomerState: string index 6 read GetStrData write SetStrData;
       property CustomerZip:string index 7 read GetStrData write SetStrData;
       property CustomerPhone:string index 8 read GetStrData write SetStrData;
       function DisplayHeader:boolean;
  end;

implementation

Constructor Tinvheader.Create();
begin
  InvNum:= NextInvNum;
  inc(NextInvNum);   {Increment global invoice number variable so the next time a header is created it has a new number}
  SalesNum:= 0;
  CustCode:= '';
  CustName:= '';
  CustAddr1:= '';
  CustAddr2:= '';
  CustCity:= '';
  CustState:= '';
  CustZip:= '';
  CustPhone:= '';
  InvDate:=now();
end;

procedure Tinvheader.SetNumData(Index:integer;targetdata : integer);
{ Set integer based data in object}
begin
  case Index of
       1:InvNum := targetdata;
       2:SalesNum:= targetdata;
       end;
end;

procedure Tinvheader.SetStrData(Index : integer ;targetdata : string);
{ Set string based data in object}
begin
  case Index of
       1:CustCode := targetdata;
       2:CustName:= targetdata;
       3:CustAddr1:= targetdata;
       4:CustAddr2:= targetdata;
       5:CustCity:= targetdata;
       6:CustState:= targetdata;
       7:CustZip:= targetdata;
       8:CustPhone:= targetdata;
       end;
end;

function Tinvheader.GetNumData(Index:integer):integer;
{Get integer based data in object}
begin
  case Index of
      1:GetNumData := InvNum;
      2:GetNumData:= SalesNum;
      end;
end;

function Tinvheader.GetStrData(Index:integer):string;
{Get string based data in object}
begin
  case Index of
       1:GetStrData:=CustCode;
       2:GetStrData:=CustName;
       3:GetStrData:=CustAddr1;
       4:GetStrData:=CustAddr2;
       5:GetStrData:=CustCity;
       6:GetStrData:=CustState;
       7:GetStrData:=CustZip;
       8:GetStrData:=CustPhone;
       end;
end;

function Tinvheader.DisplayHeader:boolean;
{var
ttypelab,saleslab,ccodelab,namel,addlab,phonelab,plevlab,termslab,translab,jobnamlab,storelab,trandtlab,classlab,authchrglab,taxlab,jobnamelab,custpolab:TLabel;}

begin
HeadScreen := TForm.Create(nil);
HeadScreen.Height := 200;
HeadScreen.Width := 400;
DisplayHeader:=True;
end;



end.


« Last Edit: September 09, 2015, 08:38:45 pm by wpflum »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #1 on: September 09, 2015, 05:03:06 pm »
constructor create is not declared correctly and on top of that you do not call the inherited constructor to allow proper initialization. Address those two problems and my guess is that you problem will go away.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #2 on: September 09, 2015, 05:19:09 pm »
Resourceless forms cannot be instantiated with Create. You have to use CreateNew.
A basic template would be something like this:

Code: [Select]
unit InvoiceHeaderClass;

{$mode objfpc}{$H+}

interface

uses
  Forms;

type

   { Tinvheader }

   Tinvheader = class(TObject)
   private
     HeadScreen:TForm;
   public
     function DisplayHeader: boolean;
   end;

implementation

function Tinvheader.DisplayHeader: boolean;

begin
  HeadScreen:=TForm.CreateNew(Application);
  try
    with HeadScreen do
      begin
        SetInitialBounds(0, 0, 400, 200);
        Position:=poScreenCenter;
        Caption:='Invoice Header';
        Visible:=True;
      end;
    Result:=True;
  except
    Result:=False;
  end;
end;

end.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #3 on: September 09, 2015, 05:22:57 pm »
Resourceless forms cannot be instantiated with Create. You have to use CreateNew.
Yes and no. Yes by default an exception is raised, no you don't have to use the CreateNew (although a valid solution) you simple change the line
Code: [Select]
RequireDerivedFormResource := True; in the project source to false and you are good to go.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #4 on: September 09, 2015, 05:34:46 pm »
constructor create is not declared correctly and on top of that you do not call the inherited constructor to allow proper initialization. Address those two problems and my guess is that you problem will go away.

Pretend I'm an idiot, my wife often does, do you mean the object I'm programming or the TForm object?  If you meant the TForm can you point me to an example because what I used is something that worked before so I'm confused as to why it wont work now.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #5 on: September 09, 2015, 06:55:23 pm »
Let me remind you that I said "Pretend I'm an idiot"  because it's true  :-[

The problem wasn't in the object it was in the code calling it.  I had tried the code that howardpc had posted and got the same error so I figured that I'd clean up the little calling form I was using and post it to make sure I wasn't screwing the pooch with that and low and behold after careful review, actually I saw right away, I realized that instead of creating the new class object with the Tinvheader I was using the actual variable that I had created to create itself.  I'm just using the form to test and I had successfully done it with the sets and gets test but I guess when I deleted that code and added the code to call the DisplayHeader I managed to screw it up royally but kept thinking that the calling code had worked.  I fixed that and my original code worked.

I do have some follow up questions though, in howardpc's code the class is used as class(TObject) is this how you're supposed to create a class because I've been just using class and if I should be using it the other way I'd like to know.

The other is what taazz said about "constructor create is not declared correctly and on top of that you do not call the inherited constructor to allow proper initialization."  is this what the TObject does or am I missing something else that I really should fix so my programs are more correct or function better.

Thanks.




derek.john.evans

  • Guest
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #6 on: September 09, 2015, 07:12:56 pm »
RE:  in howardpc's code the class is used as class(TObject) is this how you're supposed to create a class?

TObject is base class by default, so, you dont have to include (TObject), but IMHO, you should be inheriting from TComponent.

RE: The other is what taazz said about "constructor create is not declared correctly

taazz is right, in that you are not calling the inherited Create constructor, but in the case of TObject, this doesn't matter, since, TObject.Create does nothing.

But, for other base objects like TComponent, if you dont include a "inherited" call, then the class wont be properly created.

derek.john.evans

  • Guest
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #7 on: September 09, 2015, 07:15:44 pm »
BTW, my questions are, why are you creating your own TForm?

I see a bunch of TLabel's, and I dont understand why you are accessing fields via SetNumData/GetNumData etc.

You may need to consider why you want todo all this first, because I think I know what you are trying todo, and there are a number of other better solutions.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #8 on: September 09, 2015, 07:32:08 pm »
BTW, my questions are, why are you creating your own TForm?

I see a bunch of TLabel's, and I dont understand why you are accessing fields via SetNumData/GetNumData etc.

You may need to consider why you want todo all this first, because I think I know what you are trying todo, and there are a number of other better solutions.

I'm planning on three objects, Header, Lines and Total and instead of having separate forms for each object I wanted to have the object itself manage it's own form so updating the object could automatically update the form.  This way if I need the any of those objects in another project I can just drop in the class file itself and not need an additional form. 

I did this with another project where I needed to access a database for customers and items where I wanted the popup search windows and logic to stay with the object so that like now when I need customers or items along with standardized search windows I can drop them in.

As to the set and get I was under the impression that it was the preferred way to access data in an object.  I could have just put the variables in the public side and access them directly but at this point I'm not sure if I'll need to do any checking or modifying of the objects data before returning it so a dedicated set/get lets me do this up front and then modify the routines if I need to later on.  I tried something different this time in that I was able to use the Index of the read/write on a property to access a single set of routines to return the data instead of a pair or set/gets per property, well dual set of functions as I tried to use an overload on the functions so that depending on what the calling property was, string or integer, it would use the correct function but while the overload worked normally I couldn't get it to work in the property line of the object.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #9 on: September 09, 2015, 07:37:24 pm »
RE:  in howardpc's code the class is used as class(TObject) is this how you're supposed to create a class?

TObject is base class by default, so, you dont have to include (TObject), but IMHO, you should be inheriting from TComponent.

RE: The other is what taazz said about "constructor create is not declared correctly

taazz is right, in that you are not calling the inherited Create constructor, but in the case of TObject, this doesn't matter, since, TObject.Create does nothing.

But, for other base objects like TComponent, if you dont include a "inherited" call, then the class wont be properly created.

I'm foggy on exactly what you are saying, I'm probably not locking on to the concept because I'm either doing it already in other places and don't know what it means but saw it in an example or am completely missing the point.  Could you give me a brief example line of code so I can determine which one it is.

Thanks.

derek.john.evans

  • Guest
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #10 on: September 09, 2015, 08:22:48 pm »
I guess, im just not sure why you really want to create form's at runtime. Why not just have folder of reusable TForms? Its the same as having your own TForm creation code, except the controls are loaded from a lfm file.

Why do you want to sync object fields to a GUI? Why not use data aware controls? and TDataSet's.

Why not just store the data in the form's controls, and use TDateEdit/TSpinEdit to manage data validation?

What about RTTI controls? they can be linked to object properties.


Handoko

  • Hero Member
  • *****
  • Posts: 5513
  • My goal: build my own game engine using Lazarus
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #11 on: September 09, 2015, 08:37:02 pm »
I tested wpflum's code, which I removed unnecessary things (fields, properties, etc). It works correctly on my computer. I think the bug is not on unit InvoiceHeaderClass but hidden somewhere on other unit or main project file.

Code: [Select]
type

  { TMyTest }

  TMyTest = class
  private
    HeadScreen: TForm;
  public
    function DisplayHeader: Boolean;
  end;

..........
..........
..........

var
  Test: TMyTest;
  frmMain: TfrmMain; 

implementation

{$R *.lfm}

{ TMyTest }

function TMyTest.DisplayHeader: Boolean;
begin
  HeadScreen := TForm.Create(nil);
  HeadScreen.Height := 200;
  HeadScreen.Width := 400;
  HeadScreen.Show;
  DisplayHeader := True;
end;                       

procedure TfrmMain.Button1Click(Sender: TObject);
var
  TestResult: Boolean;
begin
  TestResult := Test.DisplayHeader;
end;
Above is my simplified version, which runs without any error message.

Finding bug isn't an easy task. But at least the way wpflum creating form at runtime is working correctly. Runtime error messages sometime can be misleading. It points out the line that has the (memory leaking) issue but actually the cause of the problem could be on the other line.
« Last Edit: September 09, 2015, 08:43:20 pm by Handoko »

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #12 on: September 09, 2015, 08:44:14 pm »
I tested wpflum's code, which I removed unnecessary things (fields, properties, etc). It works correctly on my computer. I think the bug is not on unit InvoiceHeaderClass but hidden somewhere on other unit or main project file.

Code: [Select]
type

  { TMyTest }

  TMyTest = class
  private
    HeadScreen: TForm;
  public
    function DisplayHeader: Boolean;
  end;

..........
..........
..........

var
  Test: TMyTest;
  frmMain: TfrmMain; 

implementation

{$R *.lfm}

{ TMyTest }

function TMyTest.DisplayHeader: Boolean;
begin
  HeadScreen := TForm.Create(nil);
  HeadScreen.Height := 200;
  HeadScreen.Width := 400;
  HeadScreen.Show;
  DisplayHeader := True;
end;                       

procedure TfrmMain.Button1Click(Sender: TObject);
var
  TestResult: Boolean;
begin
  TestResult := Test.DisplayHeader;
end;
Above is my simplified version, which run without any error message.

Finding bug isn't an easy task. But at least the way wpflum creating form at runtime is working correctly. Runtime error messages sometime can be misleading. It point out the line that has the issue but actually causing the problem could be on the other line.

Thanks, I did track it down and it was a brain dead coding error in the calling form I was using to test the object.  I should have looked for it sooner but I was fixated on the error showing as the TForm.Create(nil) line and not from the form calling it where I was trying to create the Tinvheader variable with itself instead of using the Tinvheader object.  I should have known better and looked there first since I've pulled that bone stupid move before.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #13 on: September 09, 2015, 08:52:56 pm »
I guess, im just not sure why you really want to create form's at runtime. Why not just have folder of reusable TForms? Its the same as having your own TForm creation code, except the controls are loaded from a lfm file.

Why do you want to sync object fields to a GUI? Why not use data aware controls? and TDataSet's.

Why not just store the data in the form's controls, and use TDateEdit/TSpinEdit to manage data validation?

What about RTTI controls? they can be linked to object properties.


Basically because...Reasons...

I'm mostly self taught in programming so when I learn to do something on my own and it works I just keep using it.  I also just like the idea that everything is packaged up in one file but the options you suggested sound interesting so I may look into them.  Every once in a while I wished I'd be able to take some classes in programming in whatever language I'm using at the time, perl, C, assembly and so on but the truth of the matter is that without a defined objective like needing to write some code to do something I need to do or want to do I get bored so classroom work is mostly nap time.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #14 on: September 09, 2015, 09:07:13 pm »
I do have one question about using the other methods will they result in smaller code?  I need to generate as small a program as possible so if using pre-built forms would shrink the size it would be worth looking into.

 

TinyPortal © 2005-2018