Recent

Author Topic: [SOLVED] Sorting chartlistbox?  (Read 587 times)

barsoom

  • New Member
  • *
  • Posts: 28
[SOLVED] Sorting chartlistbox?
« on: January 29, 2021, 12:47:21 am »
AFAIK, Chartlistbox is filled from top to bottom in the same sequence that the series are added, i.e., by Zposition. is there a way to sort in other way?

I mean, the serie on top of the others in the chart, is at the bottom in the chartlistbox, is it possible to fill in the opposite way to have a more intuitive sequence of series?

And is it possible to sort the series by name or by tag, in some way? I used chartlistbox.sorted, but it seems does nothing with the series names.

Thanks.
« Last Edit: February 01, 2021, 12:52:01 am by barsoom »

wp

  • Hero Member
  • *****
  • Posts: 8392
Re: Sorting chartlistbox?
« Reply #1 on: January 29, 2021, 02:32:28 pm »
AFAIK, Chartlistbox is filled from top to bottom in the same sequence that the series are added, i.e., by Zposition. is there a way to sort in other way?
The ChartListbox is ordered in the same way as the series in the Chart's Series list. That this happens to look like the ZPositions is just by incidence. Every series has an Index property which describes its index in the Chart.Series list and thus in the ChartListbox. So, if you want to rearrange the series in the CheckListbox you simply change their Index. As I noticed, however, it is recommended to disconnect the ChartListbox temporarily from the chart while the series is reindexed.

Here is a short code ordering the Checklistbox series by their title:
Code: Pascal  [Select][+][-]
  1. uses
  2.   TACustomSeries, TAEnumerators;
  3.  
  4. function FindSeriesByTitle(AChart: TChart; ASeriesTitle: String): TCustomChartSeries;
  5. var
  6.   ser: TCustomChartSeries;
  7. begin
  8.   Result := nil;
  9.   for ser in CustomSeries(AChart) do
  10.     if ser.Title = ASeriesTitle then
  11.       exit(ser);
  12. end;
  13.  
  14. procedure TForm1.Button1Click(Sender: TObject);
  15. var
  16.   L: TStringList;
  17.   i: Integer;
  18. begin
  19.   L := TStringList.Create;
  20.   try
  21.     for i := 0 to ChartListbox1.SeriesCount-1 do
  22.       L.Add(ChartListbox1.Series[i].Title);
  23.     L.Sort;
  24.  
  25.     ChartListbox1.Chart := nil;
  26.     for i := 0 to L.Count-1 do
  27.       FindSeriesByTitle(Chart1, L[i]).Index := i;
  28.     ChartListbox1.Chart := Chart1;
  29.   finally
  30.     L.Free;
  31.   end;
  32. end;

[EDIT]
I added similar code to the "listbox" demo in folder components/tachart/demo/listbox of the trunk Lazarus installation.
« Last Edit: January 29, 2021, 04:20:47 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

barsoom

  • New Member
  • *
  • Posts: 28
Re: Sorting chartlistbox?
« Reply #2 on: January 29, 2021, 07:52:33 pm »
Thanks a lot! It works nice.
Thanks @wp for the nice piece of code!

I made a small add to your code to control, at the same time the zposition, in order to have the series on top on the ChartListBox, on top in the chart:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.ToolButton1Click(Sender: TObject);
  2. var
  3.   L: TStringList;
  4.   i: Integer;
  5. begin
  6.   L := TStringList.Create;
  7.   try
  8.     for i := 0 to ChartListbox1.SeriesCount-1 do
  9.       L.Add(ChartListbox1.Series[i].Title);
  10.     L.Sort;
  11.  
  12.     ChartListbox1.Chart := nil;
  13.     for i := 0 to L.Count-1 do
  14.       begin
  15.         FindSeriesByTitle(Chart1, L[i]).Index := i;
  16.         FindSeriesByTitle(Chart1, L[i]).zPosition := L.Count-1-i;
  17.       end;
  18.     ChartListbox1.Chart := Chart1;
  19.   finally
  20.     L.Free;
  21.   end;
  22. end;

In the same way, i added the reverse sequence, by this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ToolButton2Click(Sender: TObject);
  2. var
  3.   L: TStringList;
  4.   i: Integer;
  5. begin
  6.   L := TStringList.Create;
  7.   try
  8.     for i := 0 to ChartListbox1.SeriesCount-1  do
  9.       L.Add(ChartListbox1.Series[i].Title);
  10.     L.Sort;
  11.  
  12.     ChartListbox1.Chart := nil;
  13.     for i := 0 to L.Count-1  do
  14.       begin
  15.         FindSeriesByTitle(Chart1, L[i]).Index := L.Count-1-i;
  16.         FindSeriesByTitle(Chart1, L[i]).zposition := i;
  17.       end;
  18.     ChartListbox1.Chart := Chart1;
  19.   finally
  20.     L.Free;
  21.   end;
  22. end;

I also added this code to recover the original sequence, as i saved the z position in the tag propertie of each serie when the series were added:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ToolButton3Click(Sender: TObject);
  2. var
  3.   i: integer;
  4. begin
  5.   ChartListbox1.Chart := nil;
  6.   for i := 0 to ChartListbox1.SeriesCount-1 do
  7.     begin
  8.       ChartListbox1.Series[i].index := ChartListbox1.SeriesCount-1 - ChartListbox1.Series[i].tag;
  9.       ChartListbox1.Series[i].zposition := ChartListbox1.Series[i].tag;
  10.     end;
  11.   ChartListbox1.Chart := chart1;
  12. end;

Next steps to work on: to move a selected serie one position up (index -1; zposition +1) or down (index +1; zposition-1) respect the others, or to the top (index =0; Zposition = X); or the bottom (index = X; zposition= 0).

[Edit]
I found this topic in this forum about ListBox that could inspire the solution for the ChartListBox. I will study it so see if i could adapt it to this component.
https://forum.lazarus.freepascal.org/index.php?topic=45069.0

« Last Edit: January 29, 2021, 09:48:47 pm by barsoom »

wp

  • Hero Member
  • *****
  • Posts: 8392
Re: Sorting chartlistbox?
« Reply #3 on: January 31, 2021, 12:12:57 am »
I must correct myself to some degree: The order of the series in the chartlistbox is not only given by the series' Index but also by the position of the series in the legend. When the chart's Legend.Inverted is set to true the legend items are drawn upside down, and so in the listbox. Moreover every series has a Legend.Order parameter which determines the position of the series in the legend -- and in the ChartListbox. Read the short chapter about the order of legend items in the documentation: https://wiki.lazarus.freepascal.org/TAChart_documentation#Legend

Since I think that there might be a need to rearrange the series in the ChartListbox independently of the legend I added two new methods to TChartListbox:

Code: Pascal  [Select][+][-]
  1.   procedure ExchangeSeries(AIndex1, AIndex2: Integer);
  2.   procedure Sort(Descending: boolean = false);

You can use the ExchangeSeries method to move the selected series in the ChartListbox up and down, e.g. ChartListbox.ExchangeSeries(ChartListbox.ItemIndex, ChartListbox.itemIndex-1).

The Sort method sorts the listbox by the series name. Note however that only series with the default Legend.Order of -1 are affected. This adds a large amount of flexibility. The listbox sort order can be inverted by calling the Sort method with parameter Descending = true, or by setting the Chart.Legend.Inverted to true (if you apply both the sort order will be ascending again...).

The demo project in folder components/tachart/demo/listbox was extended to apply the new methods.
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

barsoom

  • New Member
  • *
  • Posts: 28
Re: Sorting chartlistbox?
« Reply #4 on: January 31, 2021, 02:54:59 pm »
Thanks for the ti about the legend. I never used, so i will explore it.

About the two new procedures:
Quote
procedure ExchangeSeries(AIndex1, AIndex2: Integer);
  procedure Sort(Descending: boolean = false);

I assume that they are only accesible in the trunk version of Lazarus? am i right? Is there not other way to see the code? Thanks

In any case thanks so much. I think these new procedures will help a lot to other users too.

wp

  • Hero Member
  • *****
  • Posts: 8392
Re: Sorting chartlistbox?
« Reply #5 on: January 31, 2021, 03:30:42 pm »
The easiest way to see the laz-trunk code, if you don't use svn, is to look at https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/components/tachart/?root=lazarus&sortby=date#dirlist. Make a backup copy of your TAChartListbox.pas and then download the file from that site and copy it over your version (folder components/tachart of your installation). Start Lazarus and recompile the IDE. Hopefully the downloaded version is compatible with your installed Laz and installation succees (otherwise you have to reactivate your backup copy and rebuild the IDE again).
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

barsoom

  • New Member
  • *
  • Posts: 28
Re: Sorting chartlistbox?
« Reply #6 on: February 01, 2021, 12:51:39 am »
I followed your steps and t worked really nicely after to compile the IDE.
Thanks so much, i really appreciate. It solve the wish i had, and i am sure that many others will be also happy with these sort and exchange tools.

May be, just to be perfect, to add the option, in both of them, to affect the index and/or the z position, to cover all the possible options.

In any case, they great new functions.
Thanks a lot!

[SOLVED]
« Last Edit: February 01, 2021, 01:19:53 am by barsoom »

 

TinyPortal © 2005-2018