Recent

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

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Help with on the fly form giving SIGSEGV error when it worked before
« Reply #15 on: September 09, 2015, 09:24:24 pm »
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.

There is no "supposed to". Like so much in programming it is a matter of personal style.
Code: [Select]
TMyClass = class
 ...
end;
is perfectly OK, and what you see most commonly.
I prefer always to explicitly write the type of the ancestor class (even when it is TObject) because it helps to make code slightly more self-documenting, and here on the forum where there are many beginners, it might be more helpful. But the abbreviated form omitting TObject is obviously quicker to write, and for an experienced Pascaller no less clearly descending from TObject even though that is not explicitly stated.
As Geepster already pointed out, you might in future find you want to descend from TPersistent or TComponent anyway.
Explicitly writing the ancestor class in the declaration makes it very obvious that your class is not presently either a component or a persistent.

derek.john.evans

  • Guest
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #16 on: September 09, 2015, 09:33:49 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.

Size as in executable size? I doubt it.
Size as in the amount of code written (and  debugged), yes.

Btw, I'm not saying, "dont create TForm's at runtime". I'm just thinking ahead.

There are neater/cleaner/faster ways to implement custom forms designed for record editing. Especially if you need to support alot of record types.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #17 on: September 09, 2015, 09:43:01 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.

Size as in executable size? I doubt it.
Size as in the amount of code written (and  debugged), yes.

Btw, I'm not saying, "dont create TForm's at runtime". I'm just thinking ahead.

There are neater/cleaner/faster ways to implement custom forms designed for record editing. Especially if you need to support alot of record types.

Thinking ahead never killed anyone, it's the "Hold my beer and watch this" that gets you every time  :D

My biggest concern is that the amount of programming I do is not much, I might not come back to a project or start another similar project for months or years so having to deal with only the object instead of object form, etc is simpler on my failing memory.  That being said learning something new is always helpful so I'll take a look into the few ideas you gave me.

derek.john.evans

  • Guest
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #18 on: September 09, 2015, 09:49:35 pm »
Give me a minute or two and I'll code up how I think it should be done. I'll post the code in a hour or so.

derek.john.evans

  • Guest
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #19 on: September 09, 2015, 11:11:31 pm »
My biggest concern is that the amount of programming I do is not much, I might not come back to a project or start another similar project for months or years so having to deal with only the object instead of object form, etc is simpler on my failing memory.  That being said learning something new is always helpful so I'll take a look into the few ideas you gave me.

I understand. Yea, coding is somewhat of a constant head strain. Well. mm. Here is a way to write briefcase databases with automatically generated TForm's.
http://www.wascal.net/bin/BriefCase.zip

It uses an idea that I've used in the past for client and server side app's. It allows a lot to be done with minimal coding. But eventually you end up having to write the "special cases". Ie: custom buttons, etc.

See what you think. Good luck with your coding.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #20 on: September 10, 2015, 01:22:39 am »
Based on your code
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;

  Public
       Constructor Create();
  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;
end.
what do you expect that happens with the above code? take your time and think about then read what happens below.

What happens is, as always, dependent  heavily on the compiler mode you are using, in objfpc mode the above code declares a new overloaded constructor named Create with no parameters and thats because the overload keyword is not mandatory in that mode. In delphi mode a warning should be raised that the new constructor is hiding the old one since no overloading is defined and no override is given and the constructor declaration is different from the old one the compiler does what it can to compile the program and that is to create a second one with the same that is to be used for this class only and since there is a naming conflict it informs you that the newer constructor will be used in all cases.

In both cases the old constructor that has code to internally initialize the various private fields is not called from your new constructor at all.

You are lucky because in most cases the internal fields are lazy created but there are fields initialized in the constructors and those initialization are never executed IF you call the new constructor correctly.

And then you ask about calling the 
Quote
TForm.Create(nil)
which in objfpc mode should never be your constructor but always the old constructor declared in the TForm class(overloaded takes care of this). In the case of delphi mode since you are using the tform class instead of TInvHeader class it will have no idea about the new constructor, because no override is ever declared and the last known virtual constructor will be executed. In the case that you have correctly used the new class (TinvHeader) if you pass the nil parameter I think the correct behavior is to call the old constructor although an exception that it can't find the method would be acceptable as well in this case and I can't remember for sure which one is the correct behavior.

The solution is to properly override the old constructor and in there call the old one. Although there are cases where calling inherited might not be very smart you should never, ever avoid calling the inherited constructor, think of it as a mandatory obligation of the override. To sum things up the correct way to write your form's constructor is the following.
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;

  Public
       Constructor Create(aOwner:TComponent);override;
  end;

implementation

Constructor Tinvheader.Create(aOwner:TComponent);
begin
  inherited Create(aOwner); // or inherited; both should have the same effect but the second requires the parameter name to be the same with the old constructor as well If I remember correctly.
end;
At this point you might observe that the name of the parameter I use is different from the the one used in the TForm class, that is not a problem as long as the type of the parameter is the same.
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: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #21 on: September 10, 2015, 10:33:09 am »
...
The solution is to properly override the old constructor and in there call the old one. Although there are cases where calling inherited might not be very smart you should never, ever avoid calling the inherited constructor, think of it as a mandatory obligation of the override. To sum things up the correct way to write your form's constructor is the following.
Code: [Select]
unit InvoiceHeaderClass;

{$mode objfpc}{$H+}

interface

type
  Tinvheader = class
  Private
       ...
  Public
       Constructor Create(aOwner:TComponent);override;
  end;

@taazz: I don't follow you here. TObject has no virtual Create constructor (though it does have a virtual Destroy destructor). So declaring an overridden Create() constructor in a TObject descendant makes no sense.
I presume the compiler just ignores the "override;" specifier. What would it mean to "override" a non-virtual constructor?
I would expect that re-declaring Create() as a constructor in a TObject descendant simply replaces the compiler-provided constructor implementation (with whatever initialization that compiler-generated code does) with the code you put in your implementation to replace it.
Or am I more confused than usual?
« Last Edit: September 10, 2015, 10:34:40 am by howardpc »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #22 on: September 10, 2015, 11:27:16 am »
...
The solution is to properly override the old constructor and in there call the old one. Although there are cases where calling inherited might not be very smart you should never, ever avoid calling the inherited constructor, think of it as a mandatory obligation of the override. To sum things up the correct way to write your form's constructor is the following.
Code: [Select]
unit InvoiceHeaderClass;

{$mode objfpc}{$H+}

interface

type
  Tinvheader = class
  Private
       ...
  Public
       Constructor Create(aOwner:TComponent);override;
  end;

@taazz: I don't follow you here. TObject has no virtual Create constructor (though it does have a virtual Destroy destructor). So declaring an overridden Create() constructor in a TObject descendant makes no sense.
I presume the compiler just ignores the "override;" specifier. What would it mean to "override" a non-virtual constructor?
I would expect that re-declaring Create() as a constructor in a TObject descendant simply replaces the compiler-provided constructor implementation (with whatever initialization that compiler-generated code does) with the code you put in your implementation to replace it.
Or am I more confused than usual?
You can ignore most of my posts, although they are technically accurate I'm writing under the assumption of
Code: [Select]
TinvHeader = class(Tform).... Never registered in my brain that the form discussed here isn't the header but something else.
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: [SOLVED] Help with on the fly form giving SIGSEGV error when it worked before
« Reply #23 on: September 10, 2015, 11:39:12 am »
Perhaps I should have replied to wpflum earlier (see #16 above)

"Explicitly writing the ancestor class in the declaration makes it very obvious that your class is not presently either a component or a persistent or a form."

 

TinyPortal © 2005-2018