Recent

Author Topic: [SOLVED] Graph returns a SIGSEVG after calling custom 'Draw' function  (Read 346 times)

mug33n

  • Newbie
  • Posts: 3
Hello, i have the problem with this code (it raises a SIGSEVG (see problem.png) in Lazarus):

Code: Pascal  [Select][+][-]
  1. {$MODE objfpc} {$H+} {$J-} {$R+} {$UNITPATH src}
  2. program Main;
  3.  
  4. uses cthreads, ptcGraph, ptcCrt, UMenu;
  5.  
  6. var Menu: TMenu;
  7.    Mode, Driver: SmallInt;
  8.  
  9. begin
  10.    Mode := M800x600; Driver := D16Bit;
  11.    InitGraph(Driver, Mode, '');
  12.  
  13.    Menu := TMenu.Init(3, 1, 'TEST');
  14.  
  15.    Menu.Draw(16, 16, 16, White, ['WEE', 'WEE', 'WEE']);
  16.  
  17.    CloseGraph;
  18. end.
  19.  

It says that the problem is a call for Menu.Draw from UMenu unit (see reason.png).

The code of UMenu unit:
Code: Pascal  [Select][+][-]
  1. {$MODE objfpc} {$H+} {$J-} {$R+}
  2. unit UMenu;
  3.  
  4. interface
  5.    uses cthreads, ptcGraph;
  6.  
  7.    type TMenu = class
  8.          EntryCount, Font: SmallInt;
  9.          Title: String;
  10.          Texts: Array of String;
  11.          PosX, PosY: Array of SmallInt;
  12.          
  13.          constructor Init(EC, F: SmallInt; T: String = 'TEST');
  14.  
  15.          procedure Draw(SX, SY, Step, Color: SmallInt: ColorType; T: Array of String);
  16.    end;
  17.  
  18. implementation
  19.    constructor TMenu.Init(EC, F: SmallInt; T: String = 'TEST');
  20.    begin
  21.       if EC = 0 then EC := 1;
  22.       if F = 0 then F := 0;
  23.    
  24.       EntryCount := EC; Font := F; Title := T;
  25.  
  26.       SetLength(Texts, EntryCount);
  27.       SetLength(PosX, EntryCount); SetLength(PosY, EntryCount);
  28.    end;
  29.  
  30.    procedure TMenu.Draw(SX, SY, Step, Color: SmallInt; T: Array of String);
  31.    var I: Integer;
  32.             Temp: OutTextXYProc;
  33.  
  34.    begin
  35.                 if Length(T) = 0 then RunError(10);
  36.       if (Length(T) > EntryCount) or (Length(T) < EntryCount) then RunError(11);
  37.  
  38.       { Set text color and font }
  39.       SetColor(Color); SetTextStyle(Font, 0, 0);
  40.  
  41.       { Display menu title }
  42.                 OutTextXY(SX, SY, Title);
  43.  
  44.                 Inc(SY, Step);
  45.  
  46.       { Display menu entries }
  47.       for I := 1 to EntryCount do
  48.       begin
  49.          PosX[I] := SX; PosY[I] := SY;
  50.          Texts[I] := T[I];
  51.          
  52.          OutTextXY(PosX[I], PosY[I], Texts[I]);
  53.  
  54.          Inc(SY, Step);
  55.       end;
  56.    end;
  57. end.
  58.  

I use the following versions of software to build the project:
FPC version - 3.2.2 from Gentoo GNU/Linux official repository;
Lazarus version - 3.6, built from source code.

P.S. - Thanks to rvk for help.
« Last Edit: November 12, 2024, 04:56:36 pm by mug33n »

TRon

  • Hero Member
  • *****
  • Posts: 3619
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #1 on: November 12, 2024, 03:20:40 pm »
Hi mug33n,

You seem to be mixing old-style objects with a class.

Either tmenu is a class or an old style object.

try
Code: Pascal  [Select][+][-]
  1.  type TMenu = object // not class
  2.          EntryCount, Font: SmallInt;
  3.          Title: String;
  4.          Texts: Array of String;
  5.          PosX, PosY: Array of SmallInt;
  6.          
  7.          constructor Init(EC, F: SmallInt; T: String = 'TEST');
  8.  
  9.          procedure Draw(SX, SY, Step, Color: SmallInt: ColorType; T: Array of String);
  10.    end;
  11.  
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

rvk

  • Hero Member
  • *****
  • Posts: 6572
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #2 on: November 12, 2024, 03:31:17 pm »
Although I do have questions about the old-style object... why are you using those????

The problem lies somewhere else.
You have several  Array of xx;

You do a SetLength on that Array.
After that you do a for loop with 1 to count.
But... array of x is always from index 0 !!!

So you need to do 0 to count - 1 (or access object[I - 1] instead of object[ I ] )

TRon

  • Hero Member
  • *****
  • Posts: 3619
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #3 on: November 12, 2024, 03:37:13 pm »
Ah yes rvk you are right.

As a quick dirty fix from
Code: Pascal  [Select][+][-]
  1. EntryCount := EC; Font := F; Title := T;
  2. ...
  3. for I := 1 to EntryCount do
  4.  
to
Code: Pascal  [Select][+][-]
  1. EntryCount := EC+1; Font := F; Title := T;
  2. ...
  3. for I := 1 to EntryCount-1 do
  4.  

Only for quick testing of course  :)

Better:
Code: Pascal  [Select][+][-]
  1. for i := low(your_array) to high(your_array)
  2.  
« Last Edit: November 12, 2024, 03:40:39 pm by TRon »
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

mug33n

  • Newbie
  • Posts: 3
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #4 on: November 12, 2024, 04:04:23 pm »
Quote from: rvk

why are you using those????
Are You about usage of ptcGraph instead of other tools?

Quote from: rvk
You do a SetLength on that Array.
After that you do a for loop with 1 to count.
But... array of x is always from index 0 !!!

So you need to do 0 to count - 1 (or access object[I - 1] instead of object[ I ] )
I tried to do that by replacing 47th line in UMenu on this one (i'm not sure what i understand this part of Your answer correctly), but it still fails with SIGSEGV:
Code: Pascal  [Select][+][-]
  1. for I := 0 to EntryCount do

rvk

  • Hero Member
  • *****
  • Posts: 6572
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #5 on: November 12, 2024, 04:13:37 pm »
Quote from: rvk

why are you using those????
Are You about usage of ptcGraph instead of other tools?
No, I'm talking about the contructor Init(). I haven't seen that since my good ol' Borland Pascal years.

Quote from: rvk
You do a SetLength on that Array.
After that you do a for loop with 1 to count.
But... array of x is always from index 0 !!!

So you need to do 0 to count - 1 (or access object[I - 1] instead of object[ I ] )
I tried to do that by replacing 47th line in UMenu on this one (i'm not sure what i understand this part of Your answer correctly), but it still fails with SIGSEGV:
Code: Pascal  [Select][+][-]
  1. for I := 0 to EntryCount do
You can't go to EntryCount. If you use Array of X you end up with an array [0..EntryCount - 1] !!
So you can't loop to EntryCount but you need to loop to EntryCount - 1.

But you then also need to make sure you fill those correctly.

You could go the 'dirty' way TRon already mentioned and do SetLength ( EntryCount + 1).
But that will give you Array[ 0 .. EntryCount ] and then you have a 0 entry which you don't use.
For testing this is fine but it's best you learn how to use dynamic arrays and you need to know they start on 0 up to (and NOT including) the count you gave.

SetLength(Count) reserves Count elements.
That's [0 .. Count - 1] (you see that?)

Doing SetLength(Count + 1) will reserve Count + 1 elements.
And then you have [0 .. Count ] (and you can use that [ Count ] but have a  [ 0 ] which you don't use.

That's how dynamic arrays work  ;)


TRon

  • Hero Member
  • *****
  • Posts: 3619
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #6 on: November 12, 2024, 04:15:27 pm »
A slightly other approach (I tried to stay in line with your original as much as possible) as there were many other small things not exactly right.

Code: Pascal  [Select][+][-]
  1. program Main;
  2.  
  3. {$MODE objfpc} {$H+} {$J-} {$R+}
  4.  
  5. uses
  6.   {$ifdef linux}
  7.   cthreads,
  8.   {$endif}
  9.   ptcgraph, ptccrt, umenu;
  10.  
  11. var
  12.   Menu   : TMenu;
  13.   Mode   : SmallInt;
  14.   Driver : SmallInt;
  15.  
  16. begin
  17.    Mode   := M800x600;
  18.    Driver := D16Bit;
  19.    InitGraph(Driver, Mode, '');
  20.  
  21.    Menu.Init(3, 1, 'TEST');
  22.  
  23.    Menu.Draw(16, 16, 16, White, ['WEE', 'WEE', 'WEE']);
  24.    repeat
  25.    until keypressed;
  26.  
  27.    CloseGraph;
  28. end.
  29.  

Code: Pascal  [Select][+][-]
  1. unit UMenu;
  2.  
  3. {$MODE objfpc} {$H+} {$J-} {$R+}
  4.  
  5. interface
  6.  
  7. uses
  8.   {$ifdef linux}
  9.   cthreads,
  10.   {$endif}
  11.   ptcGraph;
  12.  
  13. type
  14.   TMenuItem = record
  15.     // if wanted/required add fields xpos and ypos here as well.
  16.     FTitle : string;
  17.   end;
  18.  
  19.   TMenu = object // class
  20.     FFont : SmallInt;
  21.     FTitle: String;
  22.     FMenuItems : array of TMenuItem;
  23.     constructor Init(EC, F: SmallInt; const T: String = 'TEST');
  24.     procedure Draw(SX, SY, Step, Color: SmallInt; T: Array of String);
  25.   end;
  26.  
  27. implementation
  28.  
  29. constructor TMenu.Init(EC, F: SmallInt; const T: String = 'TEST');
  30. begin
  31.   SetLength(FMenuItems, EC);
  32.   FFont  := F;
  33.   FTitle := T;
  34. end;
  35.  
  36.  
  37. procedure TMenu.Draw(SX, SY, Step, Color: SmallInt; T: Array of String);
  38. var
  39.   i : integer;
  40.   Title: string;
  41. begin
  42.   // copy title
  43.   i := low(FMenuItems);
  44.   for Title in T do
  45.   begin
  46.     if i < length(FMenuItems)
  47.       then FMenuItems[i].FTitle := Title
  48.       else break;
  49.     inc(i);
  50.   end;
  51.  
  52.  
  53.   { Set text color and font }
  54.   SetColor(Color);
  55.   SetTextStyle(FFont, 0, 0);
  56.  
  57.   { Display menu title }
  58.   OutTextXY(SX, SY, FTitle);
  59.  
  60.  
  61.   { Display menu entries }
  62.   for I := low(FMenuItems) to high(FMenuItems) do
  63.   begin
  64.     Inc(SY, step);
  65.     OutTextXY(SX, SY, FMenuItems[I].FTitle);
  66.   end;
  67. end;
  68.  
  69. end.
  70.  
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

mug33n

  • Newbie
  • Posts: 3
Re: Graph returns a SIGSEVG after calling custom 'Draw' function
« Reply #7 on: November 12, 2024, 04:53:57 pm »
No, I'm talking about the contructor Init().

I use because it seems more familiar (?) for me then Create.

So you can't loop to EntryCount but you need to loop to EntryCount - 1.
Thank You!

 

TinyPortal © 2005-2018