Recent

Author Topic: trying to create an own component but getting SIGSEGV  (Read 1620 times)

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #15 on: August 18, 2022, 04:22:13 pm »
What I need are the components TLabel, TButton themselves but I need them to be "glued" and aligned to some background (TPanel in our example) but I need the background to be custom drawn and semi-transparent and TPanel makes it difficult to achieve. TImage would be better option but I can't do Title.Parent:=bkg; (bkg: TImage), I'm getting some error when I try to make TImage a parent.
For now I solved it making TPanel a parent to all other components, I set it borderless and put a TImage on top of it to draw the needed background.

Check on the picture I attached. The background is TImage, TLabel and TButton are anchored to TImage. There is a TPanel underneath but it doesn't do anything beside holding all these 3 components in tact. I don't need tab stopping, scrolling, nor other fireworks, I just need a custom drawn, transparent background. It's be cool to get rid of TPanel since it's useless but I don't know how to use TImage as a parent for the other components.

Thank you very much for the example code, it's very useful.

rvk

  • Hero Member
  • *****
  • Posts: 4949
Re: trying to create an own component but getting SIGSEGV
« Reply #16 on: August 18, 2022, 04:37:17 pm »
It's be cool to get rid of TPanel since it's useless but I don't know how to use TImage as a parent for the other components.
It doesn't have to be a TPanel from which you inherit from.
You can also use a basic TWinControl.

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #17 on: August 18, 2022, 04:48:46 pm »
ohh true... I just reminded your example code and I replaced TPanel with TCustomControl. Is TWinControl a better option in this case?

rvk

  • Hero Member
  • *****
  • Posts: 4949
Re: trying to create an own component but getting SIGSEGV
« Reply #18 on: August 18, 2022, 05:01:55 pm »
TCustomControl is a direct descendant of TWinControl.
So you can use TCustomControl.

https://lazarus-ccr.sourceforge.io/docs/lcl/controls/tcustomcontrol.html
Quote
In contrast to TGraphicControl, a TCustomControl can accept keyboard input (get the Focus) and can have child controls.

And because you have components on it that need focus (TButton) you can't go with the TGraphicControl route.

Found this once (https://stackoverflow.com/a/36804442/1037511 answer from Remy):

Quote
Is it visual?
  • If no, use TComponent.
  • if yes, does it need its own HWND (input focus, window messages, etc)?
    • If no, use TGraphicControl.
    • If yes, does it need to custom paint itself?
      • if yes, use TCustomControl.
      • if no, use TWinControl.
But... the question is... do you need to paint your component? Because you already have a TImage, TLabel and TButtonm, which paint themselves, you don't actually need to paint anything else, do you??? So TWinControl would be sufficient in that case, I think  :D
« Last Edit: August 18, 2022, 05:03:47 pm by rvk »

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #19 on: August 18, 2022, 05:05:53 pm »
ohh I see.... so I'm switching back to TWinControl.

No, I don't need to draw anything else. I just need some kind of holder/container that determines the size, position etc and keeps other components in tact.

Thanks!
« Last Edit: August 18, 2022, 05:08:21 pm by r.lukasiak »

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #20 on: August 21, 2022, 10:05:03 pm »
now I faced another issue, not really related to the topic but maybe someone can help?

I have a class like:
Code: Pascal  [Select][+][-]
  1.   Tchip = class(TImage)
  2.     private
  3.       procedure Paint; override;
  4.     public
  5.       letter: string;
  6.       value:  byte;
  7.       blank:  boolean;
  8.       constructor Create(AOwner: TComponent);
  9.   end;        

and OnPaint:
Code: Pascal  [Select][+][-]
  1. procedure TChip.Paint;
  2. var
  3.   ts: TTextStyle;
  4. begin
  5.   inherited;
  6.   Self.Stretch:=true;
  7.   Self.Picture.LoadFromFile('gfx/bkg.png');
  8.  
  9.   Self.Canvas.Brush.Style:=bsClear;
  10.   if Blank then Self.Canvas.Font.Color:=clGray
  11.            else Self.Canvas.Font.Color:=clBlack;
  12.   //letter
  13.   Self.Canvas.Font.Style:=[fsBold];
  14.   Self.Canvas.Font.Size:=Round(ChipWH/2);
  15.   ts:=Self.Canvas.TextStyle;
  16.   ts.Alignment:=taCenter;
  17.   ts.Layout:=tlCenter;
  18.   Self.Canvas.TextStyle:=ts;
  19.   Self.Canvas.TextRect(Rect(0,0,ChipWH-Round(ChipWH/5),ChipWH-Round(ChipWH/5)),0,0,Letter,Self.Canvas.TextStyle);
  20.   //value
  21.   Self.Canvas.Font.Size:=Round(ChipWH/5);
  22.   Self.Canvas.Font.Style:=[];
  23.   Self.Canvas.Font.Quality:=fqAntialiased;
  24.   ts:=Self.Canvas.TextStyle;
  25.   ts.Alignment:=taRightJustify;
  26.   ts.Layout:=tlBottom;
  27.   Self.Canvas.TextStyle:=ts;
  28.  
  29.   if Value>0 then
  30.      Self.Canvas.TextRect(Rect(Round(ChipWH/3),Round(ChipWH/3),ChipWH-Round(ChipWH/10),ChipWH-Round(ChipWH/6)),0,0,intToStr(Value));
  31.  
  32. end;    

and after creating
Code: Pascal  [Select][+][-]
  1. Game.sack[Length(Game.sack)-1]:=TChip.Create(sq);
  2. Game.sack[Length(Game.sack)-1].Parent:=sq;    
  3.  
I get 100% CPU use.
I load the Picture from a file but it doesn't seem to be the culprit, I tried with TImageList but with the same effect.

any clue what I am doing wrong?


rvk

  • Hero Member
  • *****
  • Posts: 4949
Re: trying to create an own component but getting SIGSEGV
« Reply #21 on: August 21, 2022, 10:12:14 pm »
Why are you calling inherited in Paint?
You inherit from TImage so inherit already paints everything.
And afterwards you are going to do self.stretch and some other changes to self.
This will trigger another Paint in which case you get a loop.

Either don't use inherit and paint everything yourself or use something else (TWinControl) and attach a TImage in which case you can change these things without a loop.

You can also just use TCanvas as base and paint everything on that.
(Or do you really jeed TImage?)

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #22 on: August 21, 2022, 10:25:20 pm »
Quote
And afterwards you are going to do self.stretch and some other changes to self.
This will trigger another Paint in which case you get a loop.
good point. I took .Stretch out of the procedure. I set this property after .Create, but it's still 100% CPU.

Quote
Why are you calling inherited in Paint?
That's a good question. I removed it but now, for some reason, the background image doesn't load, I only have the text painted.

Quote
You can also just use TCanvas as base and paint everything on that.
(Or do you really jeed TImage?)
I don't really need TImage. I will give TCanvas a try.

Thanks for you quick answer.

rvk

  • Hero Member
  • *****
  • Posts: 4949
Re: trying to create an own component but getting SIGSEGV
« Reply #23 on: August 21, 2022, 11:01:12 pm »
Quote
And afterwards you are going to do self.stretch and some other changes to self.
This will trigger another Paint in which case you get a loop.
good point. I took .Stretch out of the procedure. I set this property after .Create, but it's still 100% CPU.
It's not only the stretch line.
Also the Self.Picture.LoadFromFile()
You are loading a 'new' image.
That's definitely going to trigger a (re)paint which causes a loop.

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #24 on: August 26, 2022, 05:35:57 pm »
I see, LoadFromFile indeed caused a loop but loading from TImageList seems to do the same.

Removing inherit for some reason casues .TextOut to not draw any text (?!), any idea what it might be so?
Anyway I created a public procedure PaintMe so I call it whenever I need the item to repaint, so far it seems to work as expected.

Thanks a lot!

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #25 on: August 31, 2022, 05:02:55 am »
and how can I assign my own procedure to TImage on-events? I'm trying to follow Handoko's example code but I'm getting some errors.

Code: Pascal  [Select][+][-]
  1. Tchip = class(TImage)
  2.     private
  3.       //procedure Paint; override;
  4.       procedure Click; override;
  5.       procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
  6.  
  7.     public
  8.       letter: string;
  9.       value:  byte;
  10.       blank:  boolean;
  11.       constructor Create(AOwner: TComponent);
  12.       procedure PaintMe;
  13.       //procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
  14.   end;      
  15. .
  16. .
  17. .
  18. procedure TChip.MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
  19. begin
  20.   (Sender as TImage).BringToFront;
  21.   if ssLeft in Shift then
  22.      begin
  23.        (Sender as TImage).Left:=(Sender as TImage).Left+x-Round(ChipWH/2);
  24.        (Sender as TImage).Top:=(Sender as TImage).Top+y-Round(ChipWH/2);
  25.      end;
  26. end;    
  27.  
  28. .
  29. .
  30. .
  31.  
  32. MyChip:=TChip.Create(sq);
  33. MyChip..Parent:=sq;
  34.  
  35. MyChip.OnMouseMove:=@TChip.MouseMove;  //I'm getting the error here
  36.  

gives me:
Quote
sq_pas.pas(555,56) Error: Incompatible types: got "<address of procedure(TObject;TShiftState;LongInt;LongInt) of object;Register>" expected "<procedure variable type of procedure(TObject;TShiftState;LongInt;LongInt) of object;Register>"

I thought I got the Handoko's example (FTimer.OnTimer  := @OnTimer;) but it looks like I didn't :/

Any hint?

rvk

  • Hero Member
  • *****
  • Posts: 4949
Re: trying to create an own component but getting SIGSEGV
« Reply #26 on: August 31, 2022, 11:32:25 am »
Code: Pascal  [Select][+][-]
  1. MyChip.OnMouseMove:=@TChip.MouseMove;  //I'm getting the error here
You are using a direct class (TChip) event.
You can only do that if you have a class procedure (so the procedure isn't dependent on any variable in the object).

You probably meant to do this:
Code: Pascal  [Select][+][-]
  1. MyChip.OnMouseMove:=@MyChip.MouseMove; // <== note the MyChip instance

Otherwise you need to do this in the class and implementation.
Code: Pascal  [Select][+][-]
  1. class procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer); // <== note the class keyword
Because I don't see any access to local variables (but only to the Sender properties) you might be able to do it like that.


r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #27 on: September 02, 2022, 09:52:19 pm »
Quote
You probably meant to do this:
MyChip.OnMouseMove:=@MyChip.MouseMove; // <== note the MyChip instance
yes, of course... silly me  :o

thank you very much!

r.lukasiak

  • Jr. Member
  • **
  • Posts: 82
Re: trying to create an own component but getting SIGSEGV
« Reply #28 on: September 06, 2022, 10:13:32 pm »
and I've faced a SIGSEGV again...

I moved the class definition to a separate unit (it's a Data Module) so other forms (modal windows) can access it.
But now, when I try to
Code: Pascal  [Select][+][-]
  1. Game.sack[Length(Game.sack)-1].OnMouseMove:=@Game.sack[Length(Game.sack)-1].MouseMove;
it's giving me sq_pas.pas(444,88) Error: identifier idents no member "MouseMove"

The unit name is added to uses;

Then, improvising,  I got an idea to assign the procedure on .Create, right in the Constructor.
Code: Pascal  [Select][+][-]
  1. constructor TChip.Create(AOwner: TComponent);
  2. begin
  3.   inherited;
  4.   Self.Width:=ChipWH;
  5.   Self.Height:=ChipWH;
  6.   Self.OnMouseMove:=@Self.MouseMove;
  7. end;

Surprisingly, it built with no problems but when kicked off, it gives me:
Quote
Project sq raised exception class 'External: SIGSEGV'.
 At address 465960

Any idea what I screwed up this time?

thanks in advance.
« Last Edit: September 06, 2022, 10:40:13 pm by r.lukasiak »

rvk

  • Hero Member
  • *****
  • Posts: 4949
Re: trying to create an own component but getting SIGSEGV
« Reply #29 on: September 06, 2022, 10:51:17 pm »
it's giving me sq_pas.pas(444,88) Error: identifier idents no member "MouseMove"
Maybe MouseMove is not defined as public function.
Then it's only accessible inside it's own functions (like you do in create).

As for the sigsegv, it's hard to say without seeing any code.
Are you sure it's triggered in the TChip.Create.
How do you use that (show the code where you call create).

BTW. If you are always going to use Self.OnMouseMove with that internal function you can also just override the MouseMove event itself. Then your TChip doesn't even need to expose OnMouseMove.
« Last Edit: September 07, 2022, 12:09:58 am by rvk »

 

TinyPortal © 2005-2018