Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing a TListBox Tutorial #3

Open
gasensorX opened this issue May 3, 2022 · 18 comments
Open

Missing a TListBox Tutorial #3

gasensorX opened this issue May 3, 2022 · 18 comments

Comments

@gasensorX
Copy link

There is missing a TListBox Tutorial. It is useful.

I tried to use TListBox, but a memory leak always occurred.

Can you add a simple example for TListBox?

TKS

@sechshelme
Copy link
Owner

sechshelme commented May 18, 2022

I took a look at the ListBox, unfortunately this seems to be quite complicated.
I can't even manage to fill the ListBox with items.
I've also tried using PCollection with no success.

The way you write, you've already managed to do something, which unfortunately caused a crash.
If you could post this snippet of code, maybe we can work something out together.

Here is my attempt:

constructor TMyDialog.Init;
var
  Rect: TRect;
  sb: PScrollBar;
  ListBox: PListBox;
  pc: PCollection;
  ps: PString;
begin
  Rect.Assign(0, 0, 42, 21);
  Rect.Move(23, 3);
  inherited Init(Rect, 'Mein Dialog');

  // ListBox
  Rect.Assign(5, 5, 7, 15);
  sb := new(PScrollBar, Init(Rect));

  pc := new(PCollection, Init(4, 4));
  pc^.Insert(NewStr('abc'));
  pc^.Insert(NewStr('abc'));
  pc^.Insert(NewStr('abc'));
  pc^.Insert(NewStr('abc'));

  Rect.Assign(5, 2, 31, 15);
  ListBox := new(PListBox, Init(Rect, 3, nil));
  //  ListBox^.NewList(pc);
  //  ps:=new(PString);
  //  ps^:='abcd';

  //  ListBox^.Insert(ps);
  //  ListBox^.Insert(ps);
  ps := newstr('dsfdsfdsf');
  //  ListBox^.List^.Insert(ps);
  ListBox^.Insert(pc);
  //ListBox^.Insert(PString, Init('hallo'));
  //ListBox^.Insert(PString, Init('hallo'));

  Insert(ListBox);

  // Button, bei den der Titel geändert wird.
  Rect.Assign(19, 18, 32, 20);
  CounterButton := new(PButton, Init(Rect, '    ', cmCounter, bfNormal));
  CounterButton^.Title^ := '1';

  Insert(CounterButton);

  // Ok-Button
  Rect.Assign(7, 18, 17, 20);
  Insert(new(PButton, Init(Rect, '~O~K', cmOK, bfDefault)));
end;

@gasensorX
Copy link
Author

@gasensorX
Copy link
Author

testfortlist.zip

@sechshelme
Copy link
Owner

sechshelme commented May 19, 2022

thanks for the code All I had to do was {H-} and it compiled and ran with Fehlerfrau. This was because of the string, as FV requires ShortString. I haven't looked yet because of MemoryLeaks, but at least there is an entry in the ListBox.

With the following code even 4.

  pstr := NewStr(s);
  PPortStrList^.Insert(pstr);
  PPortStrList^.Insert(NewStr('abc'));
  PPortStrList^.Insert(NewStr('def'));
  PPortStrList^.Insert(NewStr('1234'));

I didn't think of PStringCollection, as you can see it's been a few lines since I wrote the tutorial.

Not only PListBox and PSortedList Box are worth a tutorial, but also PStringCollection.

I wrote my tutorial based on an old Turbo Pascal book, and therefore almost exclusively used components that I found there.

Another tip that will make your code more readable, please do not use "P" in front of the variable names:

Poorly:

    PSpeedStrList: PStringCollection;
    PPortStrList: PStringCollection;
    PEditPort: PInputLine;
    PEditSpeed: PInputLine;
    PRadioButtonBytes: PRadioButtons;
    PRadioButtonPairty: PRadioButtons;

Good:

    SpeedStrList: PStringCollection;
    PortStrList: PStringCollection;
    EditPort: PInputLine;
    EditSpeed: PInputLine;
    RadioButtonBytes: PRadioButtons;
    RadioButtonPairty: PRadioButtons;

@sechshelme
Copy link
Owner

Another question, what are you developing with?
Your code doesn't look like Lazarus komfom.
Are you using the FPC IDE running in the console.

And one more thing, what OS are you using?

@sechshelme
Copy link
Owner

Ein erster Versuch, scheint zu klappen.

https://github.com/sechshelme/Lazarus-FreeVision/tree/master/99_Test/10_ListBox

@gasensorX
Copy link
Author

Define pointer variable names using "P" as the prefix in order to avoid misuse.

I use fp and Lazarus at the same time. And I work under Linux OS.

@gasensorX
Copy link
Author

I edit the "10_ListBox" to adding Heap display. I find it is still memory leaking.

Strings created by NewStr() can not automatic free/dispose.

10_ListBox_Heap.zip

@sechshelme
Copy link
Owner

sechshelme commented May 20, 2022

I took a closer look at the sources of "PListBox".
In my opinion, a destructor is missing there, which "list" cleans up.

TListBox = OBJECT (TListViewer)
         List: PCollection;                           { List of strings }
      CONSTRUCTOR Init (Var Bounds: TRect; ANumCols: Sw_Word;
        AScrollBar: PScrollBar);
      CONSTRUCTOR Load (Var S: TStream);
// Failure Destructor
      FUNCTION DataSize: Sw_Word; Virtual;     

@sechshelme
Copy link
Owner

sechshelme commented May 20, 2022

I tried the following, but then the whole program crashes.

type
  PNewListBox = ^TNewListBox;
  TNewListBox = object(TListBox)
    destructor Done; virtual;
  end;
.....

destructor TNewListBox.Done;
begin
  FreeAll;
  inherited Done;
end;

@sechshelme
Copy link
Owner

sechshelme commented May 20, 2022

I also find that a bit strange, if the ListBox is empty, why is an insert simply ignored and no new ones are created.

procedure TListBox.Insert (Item : Pointer);
begin
  if (List <> nil) then
  begin
    List^.Insert(Item);
    SetRange(List^.Count);
  end;
end;   

@sechshelme
Copy link
Owner

sechshelme commented May 20, 2022

This is weird too, you can't even remove an entry without it popping.

  StringCollection := new(PCollection, Init(2, 1));
  StringCollection^.Insert(NewStr('Montag'));
  StringCollection^.Insert(NewStr('Dienstag'));
  StringCollection^.Insert(NewStr('Mittwoch'));
  StringCollection^.Insert(NewStr('Donnerstag'));
  StringCollection^.Insert(NewStr('Freitag'));
  StringCollection^.Insert(NewStr('Samstag'));
  StringCollection^.Insert(NewStr('Sonntag'));

  Rect.Assign(5, 2, 31, 7);
  ListBox := new(PListBox, Init(Rect, 1, ScrollBar));
  ListBox^.NewList(StringCollection);

  Insert(ListBox);

  ListBox^.Insert(NewStr('aaaaaaaaa'));
  ListBox^.FreeItem(1); // Knall !!

@sechshelme
Copy link
Owner

Anything that has anything to do with deleting an entry in the ListBox causes the program to crash.

All of the following variants make a bang.

// ListBox^.FreeItem(2);
// StringCollection^.AtFree(ListBox^.Focused);
// ListBox^.List^.AtFree(ListBox^.Focused);

@sechshelme
Copy link
Owner

sechshelme commented May 22, 2022

The problem must definitely be with the TListBox. The only thing I do in the dialog now is fill a StringCollection and then release it with Dispose. There are no storage corpses here.

constructor TMyDialog.Init;
var
  Rect: TRect;
  i: Sw_Integer;
const
  Tage: array [0..6] of shortstring = (
    'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag');

begin
  Rect.Assign(10, 5, 67, 17);
  inherited Init(Rect, 'ListBox Demo');

  // StringCollection
  StringCollection := new(PStringCollection, Init(2, 1));
  for i := 0 to Length(Tage) - 1 do begin
    StringCollection^.Insert(NewStr(Tage[i]));
  end;
  Dispose(StringCollection, Done);
  exit;

@sechshelme
Copy link
Owner

sechshelme commented May 22, 2022

If I do the following, I get a memory corpse.
Although I didn't even fill the list with dates.

begin
  Rect.Assign(10, 5, 67, 17);
  inherited Init(Rect, 'ListBox Demo');

  ListBox := new(PListBox, Init(Rect, 1, nil));
  Dispose(ListBox, Done);
  exit;

If I do the same with a PButton, the memory is cleaned up cleanly. I even tried it with a filled PRadioButtons, all clean.

I soon suspect that there is a bug in PListBox.

  bt := new(PButton, Init(Rect, '~T~ag', cmTag, bfNormal));
  Dispose(bt, Done);
  exit;
  rad := New(PRadioButtons, Init(Rect, NewSItem('~G~ross', NewSItem('~M~ittel', NewSItem('~K~lein', nil)))));
  Dispose(rad, Done);
  exit;

@sechshelme
Copy link
Owner

sechshelme commented May 23, 2022

I took a closer look at the TFileListBox used by the TFileDialog. Then I came across the following:

destructor TFileList.Done;
begin
  if List <> nil then Dispose(List, Done);
  TListBox.Done;
end;

They added their own destructor there.

Now I also built a new ListBox and added a destructor and used this ListBox in my dialog.
As it seems, this works. the memory leak is gone.

I'll make a few more tries.
In my opinion, this is a bug in TListBox, which lacks the destructor.

type
  PNewListBox = ^TNewListBox;
  TNewListBox = object(TListBox)
    destructor Done; virtual;
  end;
...
destructor TNewListBox.Done;
begin
  if List <> nil then begin
    Dispose(List, Done);
  end;
  TListBox.Done;
end;
constructor TMyDialog.Init;
var
  Rect: TRect;
  ScrollBar: PScrollBar;
  i: Sw_Integer;
const
  Tage: array [0..6] of shortstring = (
    'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag');

begin
  Rect.Assign(10, 5, 67, 17);
  inherited Init(Rect, 'ListBox Demo');

  // StringCollection
  StringCollection := new(PStringCollection, Init(5, 5));
  for i := 0 to Length(Tage) - 1 do begin
    StringCollection^.Insert(NewStr(Tage[i]));
  end;

  // ScrollBar für ListBox
  Rect.Assign(31, 2, 32, 7);
  ScrollBar := new(PScrollBar, Init(Rect));
  Insert(ScrollBar);

  // ListBox
  Rect.Assign(5, 2, 31, 7);
  ListBox := new(PNewListBox, Init(Rect, 1, ScrollBar));
  ListBox^.NewList(StringCollection);
  Insert(ListBox);

  // Cancel-Button
  Rect.Assign(19, 9, 32, 10);
  Insert(new(PButton, Init(Rect, '~T~ag', cmTag, bfNormal)));

  // Ok-Button
  Rect.Assign(7, 9, 17, 10);
  Insert(new(PButton, Init(Rect, '~O~K', cmOK, bfDefault)));
end;

@gasensorX
Copy link
Author

https://forum.lazarus.freepascal.org/index.php/topic,59237.0/topicseen.html

updated

lazarus/freepascal offical reply

@sechshelme
Copy link
Owner

sechshelme commented May 30, 2022

So, now a tutorial for ListBoxes has been added.
With the ListBoxes, you can manually remove the loaded list from memory. This is described in the tutorial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants