いつもお力添えありがとうございます。
Delphi6Proを使っています。
List.Sortを実装したいと思い、Helpを参照しました。
-----
Sort 例
-----
以下の例は、リスト内の各オブジェクトをそれぞれの名前のアルファベット順にソートします。これは、リストがコンポーネント参照のみを格納していることを前提としています。
CompareNames 関数は、リスト内のオブジェクトの比較を行います。ユーザーがボタンをクリックすると、リストがソートされます。
function CompareNames(Item1, Item2: Pointer): Integer;
begin
Result := CompareText((Item1 as TComponent).Name, (Item2 as TComponent).Name);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
List1.Sort(@CompareText);
end;
-----
呼び出し方の部分は次のようになっています。
List1.Sort(@CompareText);
これは、CompareText関数を引数として渡しているように思います。
たぶんSortメソッドの中でCompareTextを呼び出していると推察しました。
CompareTextはDelphiが準備した関数ですよね?
そうすると、ユーザが定義している
function CompareNames
関数はなぜ存在しているのか?とわからなくなってしまいました。
私がSortについて把握しているイメージを説明させていただきます。
a)List1はItemにTComponent型を保持している
b)List1.Sort(MyFunc関数のポインタ); でソートを実行できる
c)実際はふたつのItemを比較する際にMyFunc(Item1,Item2)が実行される
d)引数は、Sortメソッドの中で自動的にセットされる(?)、
e)MyFuncの戻り値でふたつのItemの大小を判断し、
f)List1の中で並べ替えが行われる
このように考えたので、b)では、自作関数(MyFunc)を引数にする気がしています。
たぶん、何か、根本的に誤解または理解できていない点があるように思います。
また、ご指導いただけると幸いです。
Delphi7でも直ってないです。
×List1.Sort(@CompareText);
○List1.Sort(@CompareNames);
ママんさん、ありがとうございます。
ヘルプの誤りだったんですね。おかげさまで、
List.Sort(@TForm1.CompareNames);
の形で自作関数を呼び出すことができました。
※CompareNamesをTForm1のメンバ関数として実装したので、頭にTForm1が必要みたいですね。
これでソートを実装できるととても便利だと思います。ありがとうございます。
-----
ところが、今度は自作関数の中でエラーが発生しています。
もう少しお力添えくださいませ。
ヘルプの例で言うと、Itemの型指定部分を次のように変更して実装しました。
function CompareNames(Item1, Item2: Pointer): Integer;
begin
Result := CompareText(TMyClass(Item1).Name, TMyClass(Item2).Name);・・(A)
end;
このコードが呼び出された段階で、次の状況になってしまいます。
・Item1.Nameは取得できる
・Item1.Nameが取得できない ←読み込み違反のエラーになる
値を調べると
・Item1=$ED77E0
・Item2=$9
とふたつの引数で値に違いが見つかりました。
この読込違反が起きるのは、Sortの使い方が間違っているからなのでしょうか?
Item1とItem2は、自動的に渡されているので原因が想像できず困っています。
また、もうひとつわからない点が出ています。
上記(A)で、
TMyClass(Item1).Name
の形で型を指定しています。
ヘルプの例と異なっている理由は、
(Item1 as TComponent).Name
の場合に次のメッセージが出てコンパイルできないためです。
・この型には演算子は使えません
何かこの辺が原因を示唆しているのでしょうか・・?
もしかするとTList(実際はTObjectList)でのコンポーネントの持ち方に問題があるのかも?と気づきました。
そこで、ヘルプの記述に従った形で、典型的なコードを実行したところ期待通りソートされました。
TObjectListのItemにnilを代入したら、上記と同様のエラーが発生します。
TList.Sortと比較関数の問題ではないと言えそうですね。
この質問は解決として、自分でコードを追求してみます。
ママんさん、みなさん、ありがとうございました。
以下のコードはフォームに
・Button1
・Memo1
を貼り付けて実行しました。
TObjectListを使うため、UsesにContnrsを追加しました。
-----
function CompareNames(Item1, Item2: Pointer): Integer;
begin
Result := CompareText(TComponent(Item1).Name, TComponent(Item2).Name);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
AObjList: TObjectList;
AComponent: TComponent;
i: Integer;
begin
AObjList := TObjectList.Create;
AComponent := TComponent.Create(Self);
AComponent.Name := 'aaaaa';
AObjList.Add(AComponent);
AComponent := TComponent.Create(Self);
AComponent.Name := 'ccccc';
AObjList.Add(AComponent);
AComponent := TComponent.Create(Self);
AComponent.Name := 'bbbbb';
AObjList.Add(AComponent);
for i := 0 to AObjList.Count -1 do
begin
Memo1.Lines.Add(TComponent(AObjList.Items[i]).Name);
end;
//AObjList.Items[1] := nil;
AObjList.Sort(@CompareNames);
for i := 0 to AObjList.Count -1 do
begin
Memo1.Lines.Add(TComponent(AObjList.Items[i]).Name); //ソートされて追加される
end;
AObjList.Clear;
end;
寝る前にサンプルを投下
これで基本概念を理解してください。
明日は深夜までここへは来れません
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Contnrs;
type
PMyItem = ^TMyItem;
TMyItem = record
myName:String; //自分で定義(本来被りそうな名前は使用するべきでない)
end;
TMyObject = class(TObject)
private
public
myName:String; //自分で定義(本来被りそうな名前は使用するべきでない)
end;
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Button2: TButton;
Button3: TButton;
Memo1: TMemo;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private 宣言 }
AObjList: TObjectList;
AList : TList;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function CompareMyItemName(Item1, Item2: Pointer): Integer;
begin
Result := CompareText(PMyItem(Item1).myName, PMyItem(Item2).myName);
end;
function CompareMyObjectName(Item1, Item2: Pointer): Integer;
begin
Result := CompareText(TMyObject(Item1).myName, TMyObject(Item2).myName);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
myObj1:TMyObject;
myItem:PMyItem;
begin
//追加の例
new(myItem);
myItem.myName:=Edit1.Text;
AList.Add(myItem);
myObj1:=TMyObject.Create;
myObj1.myName:=Edit1.Text;
AObjList.Add(myObj1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
AObjList:= TObjectList.Create;
AList := TList.Create;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
//ソートの例
AObjList.Sort(@CompareMyObjectName);
AList.Sort(@CompareMyItemName);
end;
procedure TForm1.Button3Click(Sender: TObject);
var i:integer;
begin
//列挙の例
Memo1.Clear;
Memo1.Lines.Add('--AList--');
for i:=0 to AList.Count-1 do
Memo1.Lines.Add(PMyItem(AList.Items[i]).myName);
Memo1.Lines.Add('');
Memo1.Lines.Add('--AObjList--');
for i:=0 to AObjList.Count-1 do
Memo1.Lines.Add(TMyObject(AObjList.Items[i]).myName);
end;
procedure TForm1.Button4Click(Sender: TObject);
var i:integer;
begin
//削除の例
for i:=AList.Count-1 downto 0 do
Dispose(PMyItem(AList.Items[i]));
AList.Clear;
for i:=AObjList.Count-1 downto 0 do
TMyObject(AObjList.Items[i]).Free;
AObjList.Clear;
end;
end.
> TObjectListのItemにnilを代入したら、上記と同様のエラーが発生します。
> TList.Sortと比較関数の問題ではないと言えそうですね。
CompareTextの仕様を忘れましたが
単にnilチェックする必要があるだけでは?
function CompareNames(Item1, Item2: Pointer): Integer;
begin
if (not Assinged(Item1)) and (not Assinged(Item2)) then
begin
Result := 0;
end else
if (not Assinged(Item1)) and (Assinged(Item2)) then
begin
Result := -1;
end else
if (Assinged(Item1)) and (not Assinged(Item2)) then
begin
Result := +1;
end else
begin
Result := CompareText(TComponent(Item1).Name, TComponent(Item2).Name);
end;
end;
こんなんでしたっけ?
比較関数は、リストに
ItemA
ItemB
ItemC
ItemD
ItemE
が入っている場合に、List.Sortが呼び出されると
CompareNames(ItemA, ItemB)が呼び出されて
結果が正か負か同じかでItemAとItemBの場所を入れ替えるかどうか決める
同様に、
CompareNames(ItemB, ItemC)
CompareNames(ItemC, ItemD)
を呼び出していくという比較が行われて、その結果で順番がそろう
という概念ですよ。
(概念だけで、実際は上から順番に比較するのではないと思いますけど。)
TComponent(Item1).Name と書いているのですから
Item1にnilが入ってきたら、nilの対応しないと誤動作するでしょう。
ツイート | ![]() |