TObjectでご指導ねがいます。

解決


pipi  2010-01-28 16:44:16  No: 37313

おはようございます。
現在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;
// ---------------------------------------------------------


たとえば  2010-01-28 18:08:46  No: 37314

・入力したデータは全て配列なりStringGridなり構造体で一括管理
・それらをソートする関数を作成
・入力→ソート→ListBoxに追加
というように、管理用のオブジェクトを利用するのがいいんじゃないでしょうか。


ListboxよりListView  2010-01-28 18:48:28  No: 37315

ソート結果を目でみて分かる表示するためにも、ListboxよりもListViewにした方がいいんじゃないのかな。


Kenny  2010-01-28 19:17:31  No: 37316

>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;


monaa  2010-01-28 19:18:08  No: 37317

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.


monaa  2010-01-28 19:19:25  No: 37318

ぎょへ、いらぬお世話でしたね。
先にページ更新するんだった…


Kenny  2010-01-28 19:20:32  No: 37319

訂正、最後のprocedureがButton2ではなくButton3になっていますね。
Button2に変えてください。


KHE00221  2010-01-28 22:30:28  No: 37320

こうかな

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.


pipi  2010-02-08 08:00:42  No: 37321

皆様どうもありがとうございます。

TObjectというのを最近知って夢中になってしまい
たとえば様やkenny様のいう、stringgridを使うという方法を
忘れていました(>_<)

無事解決しました。
TObjectも興味ありますのでmonaa様のも少し勉強してみたいと
おもいます。

どうもありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加