我有2列StringGrid:Player
和Scores
。我必須根據玩家的分數來排序這張桌子。按行排序TStringGrid及其整數值
情況是這樣的。我嘗試過使用StringGrid3.SortColRow(true, 1);
,但它僅對字符串值進行排序。如果我有[1,4,12,3]這樣的數字,則排序後的StringGrid將變成[a,12,3,4]。我不得不排序整數值,而不是字符串之一。另外,我的問題是我必須用數字來移動玩家的名字(如上圖所示)。
我該怎麼辦?
我有2列StringGrid:Player
和Scores
。我必須根據玩家的分數來排序這張桌子。按行排序TStringGrid及其整數值
情況是這樣的。我嘗試過使用StringGrid3.SortColRow(true, 1);
,但它僅對字符串值進行排序。如果我有[1,4,12,3]這樣的數字,則排序後的StringGrid將變成[a,12,3,4]。我不得不排序整數值,而不是字符串之一。另外,我的問題是我必須用數字來移動玩家的名字(如上圖所示)。
我該怎麼辦?
如果兩個比較值都是數字,您可能會編寫一個比較器,試圖按數字進行排序。通過將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.
你在使用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;
在拉撒路您可以定義排序使用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;
等待,但你沒有decalre TMoveSG(網格).MoveRow();任何地方 –
@AlbertoRossi無需聲明它,因爲您可以從同一個單元訪問受保護的過程。 TMoveSG = class(TCustomGrid);在同一個單元中使用具有受保護的MoveRow()的技巧。 – bummi
謝謝!但我仍然有錯誤(我使用拉撒路)。它說'標識符沒有成員「MoveRow」 ' –