2014-04-29 64 views
3

我有2列StringGrid:PlayerScores。我必須根據玩家的分數來排序這張桌子。按行排序TStringGrid及其整數值

enter image description here

情況是這樣的。我嘗試過使用StringGrid3.SortColRow(true, 1);,但它僅對字符串值進行排序。如果我有[1,4,12,3]這樣的數字,則排序後的StringGrid將變成[a,12,3,4]。我不得不排序整數值,而不是字符串之一。另外,我的問題是我必須用數字來移動玩家的名字(如上圖所示)。

我該怎麼辦?

回答

5

如果兩個比較值都是數字,您可能會編寫一個比較器,試圖按數字進行排序。通過將Stringgrid投射到其祖先TCustomgrid,您可以使用MoveRow過程來交換行。顯示在排序的列一個例子可能是這樣的:

unit StringGridSortEnh; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, Grids, StdCtrls; 

type 
    TForm1 = class(TForm) 
    StringGrid1: TStringGrid; 
    Button1: TButton; 
    Button2: TButton; 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    private 
    { Private-Deklarationen } 
    public 
    { Public-Deklarationen } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 
type 
    TMoveSG = class(TCustomGrid); 
    TSortInfo=Record 
    col:Integer; 
    asc:Boolean; 
    End; 


function CompareNumber(i1, i2: Double): Integer; 
// Result: -1 if i1 < i2, 1 if i1 > i2, 0 if i1 = i2 
begin 
    if i1 < i2 then 
    Result := -1 
    else if i1 > i2 then 
    Result := 1 
    else 
    Result := 0; 
end; 

// Compare Strings if possible try to interpret as numbers 
function CompareValues(const S1, S2 : String;asc:Boolean): Integer; 
var 
    V1, V2 : Double; 
    C1, C2 : Integer; 
begin 
    Val(S1, V1, C1); 
    Val(S2, V2, C2); 
    if (C1 = 0) and (C2 = 0) then // both as numbers 
    Result := CompareNumber(V1, V2) 
    else // not both as nubers 
    Result := AnsiCompareStr(S1, S2); 
    if not Asc then Result := Result * -1; 

end; 

procedure SortGridByCols(Grid: TStringGrid; ColOrder: array of TSortInfo; Fixed: Boolean); 
var 
    I, J, FirstRow: Integer; 
    Sorted: Boolean; 

    function Sort(Row1, Row2: Integer): Integer; 
    var 
    C: Integer; 
    begin 
    C := 0; 
    Result := CompareValues(Grid.Cols[ColOrder[C].col][Row1], Grid.Cols[ColOrder[C].col][Row2],ColOrder[C].asc); 
    if Result = 0 then 
    begin 
     Inc(C); 
     while (C <= High(ColOrder)) and (Result = 0) do 
     begin 
     Result := CompareValues(Grid.Cols[ColOrder[C].col][Row1], Grid.Cols[ColOrder[C].col][Row2],ColOrder[C].asc); 
     Inc(C); 
     end; 
    end; 
    end; 

begin 
    for I := 0 to High(ColOrder) do 
    if (ColOrder[I].col < 0) or (ColOrder[I].col >= Grid.ColCount) then 
     Exit; 

    if Fixed then 
    FirstRow := 0 
    else 
    FirstRow := Grid.FixedRows; 

    J := FirstRow; 
    Sorted := True; 
    repeat 
    Inc(J); 
    for I := FirstRow to Grid.RowCount - 2 do 
     if Sort(I, I + 1) > 0 then 
     begin 
     TMoveSG(Grid).MoveRow(i + 1, i); 
     Sorted := False; 
     end; 
    until Sorted or (J >= Grid.RowCount + 1000); 
    Grid.Repaint; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
const // we want to use only 4 columns 
    MyArray: array[0..3] of TSortInfo = 
    ((col: 1; asc: true), 
    (col: 2; asc: true), 
    (col: 3; asc: true), 
    (col: 4; asc: false) 
    ); 
begin 
    SortGridByCols(StringGrid1,MyArray,true); 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
const // we want to use only one column 
    MyArray: array[0..0] of TSortInfo = 
    ((col: 1; asc: true) 
    ); 
begin 
    SortGridByCols(StringGrid1,MyArray,true); 


end; 

end. 

enter image description here enter image description here

+0

等待,但你沒有decalre TMoveSG(網格).MoveRow();任何地方 –

+0

@AlbertoRossi無需聲明它,因爲您可以從同一個單元訪問受保護的過程。 TMoveSG = class(TCustomGrid);在同一個單元中使用具有受保護的MoveRow()的技巧。 – bummi

+0

謝謝!但我仍然有錯誤(我使用拉撒路)。它說'標識符沒有成員「MoveRow」 ' –

1

你在使用Lazarus而不是Delphi嗎?我不知道標準Delphi StringGrid實現中的排序功能。

問題在於StringGrid就是這樣一個字符串的網格。它不知道字符串實際上是數字,所以它只能按字母順序排序。

如果您正在尋找比網格自然提供更復雜的排序功能,您有幾個選擇。要麼覆蓋TStringGrid類,並生成你自己的專門版本,以便如何分配它(恐怕我沒有Lazarus源代碼來給你更具體的指示),或者你可以簡單地對記錄進行排序你把它們放到網格中。

例如,如果您有一個TPlayer類代表您的玩家和他們的分數,那麼您可以使用TList.Sort(..)對您進行排序,然後再循環並填充網格。

// 
// Sort the player scores by their *numeric* value, not by the string representation 
// 
function SortByPlayerScore(A, B: Pointer) : integer 
begin 
    Result := TPlayer(A).Score - TPlayer(B).Score; 
end; 

// .... 

list.Sort(SortByPlayerScore); 

grid.RowCount := list.Count + 1; 
for i := 0 to list.Count - 1 do begin 
    grid.Cells[0, i + 1] := list[i].Name; 
    grid.Cells[1, i + 1] := IntToStr(list[i].Score); 
end; 
2

在拉撒路您可以定義排序使用OnCompareCells事件的一個TStringGrid細胞如何,看如何用數字和詳細信息做了以下鏈接和榜樣。

http://wiki.lazarus.freepascal.org/Grids_Reference_Page#Sorting_Columns_or_Rows


如果你想在Delphi中你需要重新實現從拉撒路SortColRow方法對行進行排序。

你可以用類幫手做

請注意,這並沒有得到充分的測試!

下面的程序中的AnsiCompareStr然後可以被淹沒以比較整數。

type 
    TStringGridHelper = class helper for TStringGrid 
    public 
    procedure SortColRow(IsColumn: Boolean; Index: Integer); overload; 
    procedure SortColRow(IsColumn: Boolean; Index: Integer; FromIndex: Integer; ToIndex: Integer); overload; 
end; 


implementation 


procedure TStringGridHelper.SortColRow(IsColumn: Boolean; Index: Integer); 
begin 
    if (IsColumn) then SortColRow(IsColumn, Index, FixedCols, ColCount - 1) 
    else SortColRow(IsColumn, Index, FixedRows, RowCount - 1) 
end; 

procedure TStringGridHelper.SortColRow(IsColumn: Boolean; Index: Integer; FromIndex: Integer; ToIndex: Integer); 
    var i, p, x, c : Integer; 
    s1, s2 : String; 
begin 

    if (IsColumn) then 
    begin 
     for x := ToIndex downto FromIndex do 
      for I := FromIndex to ToIndex - 1 do 
      begin 
       s1 := Cells[i, index]; 
       s2 := Cells[i + 1, index]; 

       c := AnsiCompareStr(s1, s2); 
       if (c > 0) then 
       begin 
        p := i + 1; 
        p := Max(p, FromIndex); 
        p := Min(p, ToIndex); 

        MoveColumn(i, p); 
       end; 
      end; 
    end 
    else 
    begin 
     for x := ToIndex downto FromIndex do 
      for I := FromIndex to ToIndex - 1 do 
      begin 
       s1 := Cells[index, i]; 
       s2 := Cells[index, i + 1]; 
       c := AnsiCompareStr(s1, s2); 
       if (c > 0) then 
       begin 
        p := i + 1; 
        p := Max(p, FromIndex); 
        p := Min(p, ToIndex); 

        MoveRow(i, p); 
       end; 
      end; 
    end; 
end;