おはようございます。
現在D7でTObjectを使いlistboxに文字列を代入してみました。
そこで2質問があるのですが
1,下記で言う年齢の場所でソートするのはどのようにすればいいでしょうか?
2,年齢の他にも血液型など文字列を追加するにはどのようにすればいいでしょうか?
すいませんが宜しくおねがいいたします
//----------------------------------------------------------
function NewStr(s:string):PString;
begin
New(result);
result^ := s;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
with ListBox1.Items do begin
AddObject('あ',TObject(NewStr('18さい')));
AddObject('う',TObject(NewStr('16さい')));
AddObject('い',TObject(NewStr('26さい')));
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
i:integer;
begin
for i := 0 to ListBox1.Items.Count-1 do
Dispose(PString(ListBox1.Items.Objects[i]));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
SL:TStringList;
i:integer;
birthday:string;
begin
SL := TStringList.Create;
try
for i := 0 to listbox1.Items.count-1 do
SL.AddObject(listbox1.Items[i],ListBox1.Items.Objects[i]);
SL.Sort;
for i := 0 to listbox1.Items.count-1 do
memo1.lines.add(PString(sl.Objects[i])^);
Cascade;
finally
SL.Free;
end;
end;
// ---------------------------------------------------------
・入力したデータは全て配列なりStringGridなり構造体で一括管理
・それらをソートする関数を作成
・入力→ソート→ListBoxに追加
というように、管理用のオブジェクトを利用するのがいいんじゃないでしょうか。
ソート結果を目でみて分かる表示するためにも、ListboxよりもListViewにした方がいいんじゃないのかな。
>2,年齢の他にも血液型など文字列を追加する
ということなら、複数要素を一目で見渡せるStringGridを使うのが便利だと思います。
StringGridを使うのならこれでどうでしょうか。
FormにStringGridを貼り付けて、RowCount:=21に、次にButtonを2個貼り付けてください。20個の要素を1列目または2列目を基準に並び替えるデモです。
procedure GridSort(Grid : TStringGrid; SortCol : Integer);
var
TempStList1, TempStList2 : TStringList;
k : Integer;
begin
TempStList1 := TStringList.Create;
try
TempStList1.Assign(Grid.Cols[SortCol]);
for k := 1 to Grid.FixedRows do TempStList1.Delete(0);
//年齢を一桁と二桁の混在と仮定//************************************
for k:=0 to TempStList1.Count-1 do begin
if Length(TempStList1[k])=1 then TempStList1[k]:='0'+TempStList1[k]
end;
for k := Grid.FixedRows to Grid.RowCount - 1 do begin
TempStList2 := TStringList.Create;
TempStList2.Assign(Grid.Rows[k]);
TempStList1.Objects[k - Grid.FixedRows] := TempStList2
end;
TempStList1.Sort;
for k := Grid.FixedRows to Grid.RowCount - 1 do begin
Grid.Rows[k].Assign(TStringList(TempStList1.Objects[k - Grid.FixedRows]));
TStringList(TempStList1.Objects[k - Grid.FixedRows]).Free
end;
finally
TempStList1.Free
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var k: integer;
begin
Stringgrid1.Cells[1,0]:='条件1';
Stringgrid1.Cells[2,0]:='条件2';
for k:=1 to 20 do begin
Stringgrid1.Cells[1, k]:=InttoStr(21-k);
Stringgrid1.Cells[2, k]:=InttoStr(k);
end
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
GridSort(StringGrid1, 1) //第二引数で並び替え基準列をCol値で指定
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
GridSort(StringGrid1, 2)
end;
ListBoxのitemsはTStringsなのでソートは難しいです。
データは別に管理してListBoxは表示に専念させた方が簡単す。
こんな感じ、
今回は、ソースをコピペするだけで動きます。
オブジェクトの貼付け不要す。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TBlood = (UnKnown,A,B,AB,O);
function BloodToString(aBlood:TBlood):string;
type
TValues = class(TObject)
public
Name : string;
Age : Byte;
Blood : TBlood;
procedure SetValue(aName:string; aAge:Byte; aBlood:TBlood);
function GetString:string;
end;
TForm1 = class(TForm)
Button1: TButton;
private
{ Private 宣言 }
fList : TList;
fListBox : TListBox;
fButton : TButton;
procedure AddValue;
public
{ Public 宣言 }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure fButtonClick(Sender: TObject);
procedure SortByAge;
procedure ListUp;
procedure ListClear;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function BloodToString(aBlood:TBlood):string;
begin
case aBlood of
UnKnown: Result:= '-';
A : Result:= 'A';
B : Result:= 'B';
AB : Result:= 'AB';
O : Result:= 'O';
end;
end;
function SortAge(Item1, Item2: Pointer): Integer;
begin
result := TValues(Item1).Age - TValues(Item2).Age;
end;
{ TValues }
function TValues.GetString: string;
begin
Result := Name + ' ' + IntToStr(Age) + '歳 ' + BloodToString(Blood) + '型';
end;
procedure TValues.SetValue(aName: string; aAge: Byte; aBlood: TBlood);
begin
Name := aName;
Age := aAge;
Blood := aBlood;
end;
{ TForm1 }
procedure TForm1.AddValue;
var
aValue : TValues;
begin
aValue := TValues.Create;
aValue.SetValue('山田',30,A);
fList.Add(aValue);
aValue := TValues.Create;
aValue.SetValue('田中',50,B);
fList.Add(aValue);
aValue := TValues.Create;
aValue.SetValue('斉藤',11,AB);
fList.Add(aValue);
aValue := TValues.Create;
aValue.SetValue('鈴木',25,UnKnown);
fList.Add(aValue);
aValue := TValues.Create;
aValue.SetValue('山口',80,AB);
fList.Add(aValue);
aValue := TValues.Create;
aValue.SetValue('千葉',31,A);
fList.Add(aValue);
ListUp;
end;
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
fList := TList.Create;
fListBox := TListBox.Create(self);
fListBox.Align := alClient;
fListBox.Parent:= self;
fListBox.Show;
fButton := TButton.Create(self);
fButton.Caption := '年齢順';
fButton.Parent := fListBox;
fButton.Left := fListBox.Width - fButton.Width;
fButton.Anchors := [akTop,akRight];
fButton.OnClick := fButtonClick;
AddValue;
end;
destructor TForm1.Destroy;
begin
ListClear;
fButton.Free;
fListBox.Free;
fList.Free;
inherited;
end;
procedure TForm1.fButtonClick(Sender: TObject);
begin
SortByAge;
end;
procedure TForm1.ListClear;
var
i:Integer;
aValue : TValues;
begin
for i := fList.Count-1 downto 0 do
begin
aValue := fList.Items[i];
aValue.Free;
end;
fList.Clear;
end;
procedure TForm1.ListUp;
var
i:Integer;
aValue : TValues;
begin
fListBox.Clear;
for i := 0 to fList.Count - 1 do
begin
aValue := fList.Items[i];
fListBox.AddItem(aValue.GetString,nil);
end;
end;
procedure TForm1.SortByAge;
begin
fList.Sort(SortAge);
ListUp;
end;
end.
ぎょへ、いらぬお世話でしたね。
先にページ更新するんだった…
訂正、最後のprocedureがButton2ではなくButton3になっていますね。
Button2に変えてください。
こうかな
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TBlood = (blA,blB,blAB,blO);
PItem = ^TItem;
TItem = record
Age : Integer;
Blood: TBlood;
end;
TForm3 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
ListBox2: TListBox;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
procedure QuickSort(L, R: Integer);
end;
var
Form3: TForm3;
A: TList;
implementation
{$R *.dfm}
function NewData(Age: Integer; Blood: TBlood): PItem;
begin
New (Result);
Result.Age := Age;
Result.Blood := Blood;
end;
procedure TForm3.QuickSort(L, R: Integer);
var
I, J,K,H: Integer;
P, T: Pointer;
S1,S2: String;
Item1,Item2: PItem;
begin
repeat
I := L;
J := R;
H := PItem(ListBox1.Items.Objects[(L+R) shr 1])^.Age;
repeat
K := 0;
while K = 0 do
begin
if I < ListBox1.Items.Count then
begin
if PItem(ListBox1.Items.Objects[I]).Age < H then
begin
Inc(I);
end
else
begin
K := 1;
end;
end
else
begin
K := 1;
end;
end;
K := 0;
while K = 0 do
begin
if I < ListBox1.Items.Count then
begin
if PItem(ListBox1.Items.Objects[J]).Age > H then
begin
Dec(J);
end
else
begin
K := 1;
end;
end
else
begin
K := 1;
end;
end;
//データ入れ替え
if I <= J then
begin
S1 := ListBox1.Items[I];
S2 := ListBox1.Items[J];
Item1 := PItem(ListBox1.Items.Objects[I]);
Item2 := PItem(ListBox1.Items.Objects[J]);
ListBox1.Items[I] := S2;
ListBox1.Items[J] := S1;
ListBox1.Items.Objects[I] := TObject(Item2);
ListBox1.Items.Objects[J] := TObject(Item1);
Inc(I);
Dec(J);
end;
until I > J;
if L < J then
QuickSort(L, J);
L := I;
until I >= R;
end;
procedure TForm3.Button1Click(Sender: TObject);
var
I: Integer;
begin
//データ作成 年齢データは random(99999)
for I:=0 to 1023 do
begin
ListBox1.Items.AddObject(IntToStr(I),TObject( NewData(Random(99999),blA) ));
end;
//ソート
QuickSort(0,ListBox1.Items.Count-1);
//年齢データを ListBox2 に表示
for I:=0 to 1023 do
begin
ListBox2.Items.Add(IntToStr(PItem(ListBox1.Items.Objects[I]).Age));
end;
//消す
for I:=0 to 1023 do
begin
Dispose(PItem(ListBox1.Items.Objects[I]));
end;
end;
end.
皆様どうもありがとうございます。
TObjectというのを最近知って夢中になってしまい
たとえば様やkenny様のいう、stringgridを使うという方法を
忘れていました(>_<)
無事解決しました。
TObjectも興味ありますのでmonaa様のも少し勉強してみたいと
おもいます。
どうもありがとうございました。
ツイート | ![]() |