Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: Nicola - Agosto 28, 2019, 06:44:17 am

Titolo: Sempre sulle Stringgrid ordinamento
Inserito da: Nicola - Agosto 28, 2019, 06:44:17 am
Problema: in una StringGrid, inserisco fra gli altri valori anche una colonna con numeri; questi vengono
"trasformati" in formato piu' leggibile ad esempio 1936,27 diventa  1.936,27; per fare ciò  trasformo il numero in stringa e lo passo alla cella interessata.
Ora se seleziono la proprietà ColumnClickSorts=True, ordino tutte le colonne, esclusa quella numerica che essendo stringa mi viene ordinata in ordine alfabetico e non numerico; come si può vedere dalle immagini allegate la n.2 non viene ordinata.
Esiste modo di risolvere questo problema?
Grazie
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: bonmario - Agosto 28, 2019, 07:55:55 am
Avevo avuto lo stesso problema qualche anno fa', ed allora mi era stato detto che non c'era niente, e che bisognava farsi l'ordinamento "a mano".
Non so se nel frattempo è cambiato qualcosa.

Ciao, Mario
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: xinyiman - Agosto 28, 2019, 08:27:02 am
Se non ricordo male devi gestirti l'ordinamento attraverso l'uso dell'evento OnCompareCells
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: nomorelogic - Agosto 28, 2019, 09:46:21 am
guarda qua per un esempio

https://wiki.lazarus.freepascal.org/Grids_Reference_Page#Sorting_Columns_or_Rows (https://wiki.lazarus.freepascal.org/Grids_Reference_Page#Sorting_Columns_or_Rows)
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: Nicola - Agosto 30, 2019, 07:58:31 am
Ho inserito al funzione OncompareCells, ma l'ordinamento peggiora, nel senso che non mi ordina nemmeno le colonne alfabetiche.
Codice: [Seleziona]
procedure TForm1.SgDaOrdinareCompareCells(Sender: TObject; ACol, ARow, BCol,
  BRow: Integer; var Result: integer);
begin
  if Acol<>5 then exit;
  // Result will be either <0, =0, or >0 for normal order.
  result := StrToIntDef(SgDaOrdinare.Cells[ACol,ARow],0)-StrToIntDef(SgDaOrdinare.Cells[BCol,BRow],0);
  // For inverse order, just negate the result (eg. based on grid's SortOrder).
  if SgDaOrdinare.SortOrder = soDescending then
   result := -result;
end;

procedure TForm1.popolagriglia;
var cl,rg:integer;
  begin
   SgDaOrdinare.rowcount:=6;
   for rg:=1 to 5 do with SgDaOrdinare
    do begin
      cl:=0;
      Cells[cl,rg]:=ArrElementi[rg].primo;inc(cl);
      Cells[cl,rg]:=CreaNumeroCurrency(ArrElementi[rg].secondo);inc(cl);
      Cells[cl,rg]:=ArrElementi[rg].terzo;inc(cl);
      Cells[cl,rg]:=ArrElementi[rg].quarto;inc(cl);
      Cells[cl,rg]:=CreaNumeroCurrency(ArrElementi[rg].quinto);inc(cl);
    end;
  end;

procedure TForm1.FormShow(Sender: TObject);
begin
 ArrElementi[1].primo:='il';
 ArrElementi[1].secondo:=1;
 ArrElementi[1].terzo:='elemento1';
 ArrElementi[1].quarto:='primo';
 ArrElementi[1].quinto:=1010.05;
 ArrElementi[2].primo:='il';
 ArrElementi[2].secondo:=2;
 ArrElementi[2].terzo:='elemento2';
 ArrElementi[2].quarto:='secondo';
 ArrElementi[2].quinto:=220.22;
 ArrElementi[3].primo:='il';
 ArrElementi[3].secondo:=3;
 ArrElementi[3].terzo:='elemento3';
 ArrElementi[3].quarto:='terzo';
 ArrElementi[3].quinto:=3000.17;
 ArrElementi[4].primo:='il';
 ArrElementi[4].secondo:=4;
 ArrElementi[4].terzo:='elemento4';
 ArrElementi[4].quarto:='quarto';
 ArrElementi[4].quinto:=40;
 ArrElementi[5].primo:='il';
 ArrElementi[5].secondo:=5;
 ArrElementi[5].terzo:='elemento5';
 ArrElementi[5].quarto:='quinto';
 ArrElementi[5].quinto:=5000;
 popolagriglia;

end;
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: xinyiman - Settembre 01, 2019, 10:14:06 am
Nicola allega un piccolo esempio, io poi te lo correggo
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: Nicola - Settembre 01, 2019, 06:24:13 pm
Ecco qua prova con questo.
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: bonmario - Settembre 01, 2019, 07:41:55 pm
Così dovrebbe funzionare:

Codice: [Seleziona]
procedure TForm1.SgDaOrdinareCompareCells(Sender: TObject; ACol, ARow, BCol,
  BRow: Integer; var Result: integer);
var Num1, Num2:Longint;
begin
  //if Acol<>5 then exit;

  Num1:=StrToIntDef(SgDaOrdinare.Cells[ACol,ARow],0);
  Num2:=StrToIntDef(SgDaOrdinare.Cells[BCol,BRow],0);

  // Result will be either <0, =0, or >0 for normal order.
  if (Num1 > Num2) then Result:=1
  else
    if (Num1 = Num2) then Result:=0
  else
    Result := -1;


  // For inverse order, just negate the result (eg. based on grid's SortOrder).
  if SgDaOrdinare.SortOrder = soDescending then
   result := -result;
end;

P.S. Che senso ha questa : "if Acol<>5 then exit;" ???
La prima colonna è la colonna 0, l'ultima è la colonna 4. Con quella istruzione la "SgDaOrdinareCompareCells" non viene mai eseguita !!!

P.P.S. Invece di usare "','", usa "FormatSettings.DecimalSeparator".
Stessa cosa per il "'.'", usa "FormatSettings.ThousandSeparator".
Solo così puoi essere sicuro che le successive conversioni tra numeri e stringhe funzionino correttamente

Dopo queste correzioni, il codice che ho postato sopra, funziona solo per la colonna 1, che è l'unica che contiene numeri validi in tutte le righe.

Ciao, Mario
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: Nicola - Settembre 02, 2019, 10:39:38 pm
Citazione
P.S. Che senso ha questa : "if Acol<>5 then exit;" ???
La prima colonna è la colonna 0, l'ultima è la colonna 4. Con quella istruzione la "SgDaOrdinareCompareCells" non viene mai esegu
In effetti non ha nessun senso stavo facendo delle prove di "comprensione", e mi son dimenticato di cancellare la riga.

Ho inserito la tua modifica però non funziona la seconda colonna no viene ordinata in maniera discendente (allego immagine).
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: bonmario - Settembre 03, 2019, 08:08:38 am
Hai ragione, mi ero dimenticato un pezzo !!!
La colonna contiene numeri con decimali, quindi bisogna usare un'altra istruzione per convertire la stringa in numero.

Allego comunque il programma funzionante, solo sulla colonna 1, che è l'unica con numeri "reali".

Ciao, Mario
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: Nicola - Settembre 05, 2019, 11:49:38 am
Grazie per la colonna 2 funziona, purtroppo per la colonna 5 no, in realtà era quella che piu' mi serviva (numeri "Currency")
Titolo: Re:Sempre sulle Stringgrid ordinamento
Inserito da: bonmario - Settembre 05, 2019, 11:59:48 am
Grazie per la colonna 2 funziona, purtroppo per la colonna 5 no, in realtà era quella che piu' mi serviva (numeri "Currency")

Occhio che le colonne vanno da 0 a 4, quindi funziona per colonna 1 e non per colonna 4 .....

Per farla funzionare anche per colonna 4, devi togliere i punti di separazione delle migliaia prima di fare il confronto:

Codice: [Seleziona]
procedure TForm1.SgDaOrdinareCompareCells(Sender: TObject; ACol, ARow, BCol,
  BRow: Integer; var Result: integer);
var Num1, Num2:Extended;
    Str1, Str2:String;
begin
  Str1:=StringReplace(SgDaOrdinare.Cells[ACol,ARow], FormatSettings.ThousandSeparator, '', []);
  Str2:=StringReplace(SgDaOrdinare.Cells[BCol,BRow], FormatSettings.ThousandSeparator, '', []);

  if (not TryStrToFloat(Str1, Num1)) then Num1:=0;
  if (not TryStrToFloat(Str2, Num2)) then Num2:=0;

  // Result will be either <0, =0, or >0 for normal order.
  if (Num1 > Num2) then Result:=1
  else
    if (Num1 = Num2) then Result:=0
  else
    Result := -1;


  // For inverse order, just negate the result (eg. based on grid's SortOrder).
  if SgDaOrdinare.SortOrder = soDescending then
   result := -result;
end;

Così funziona sia per colonna 1 che per colonna 4.

Ciao, Mario