皆さん暑中お見舞い申し上げます。
環境はWindows7 Delphi6Personalです。
http://mrxray.on.coocan.jp/Delphi/plSamples/790_ListView.htm
を参考に790_仮想リストビューの勉強をしています。
08_仮想リストビューにチェックボックス でつまずいています。
どうしても項目を削除するとメモリーリークします。
場所はFormShowのFItem := TDataListItem.Create;
だと表示しているようなのですが、解決できません。
マスターに変わりどなたか教えてくださいませんか。
イメージ不器用なので○●で代用しています。
コードはコピペしただけですが念のため。(長くなりますがm(_ _)m)
type
TplDataListItem = class;
TplDataList = class(TList)
protected
function Get(Index: Integer): TplDataListItem;
procedure Put(Index: Integer; Item: TplDataListItem);
public
destructor Destroy; override;
procedure Clear; virtual;
function Add(Item: TplDataListItem): Integer;
function IndexOf(Item: TplDataListItem): Integer;
function Remove(Item: TplDataListItem): Integer;
property Items[Index: Integer]: TplDataListItem read Get write Put; default;
end;
//プロパティはCaptionとChecedのみとした
TplDataListItem =class(TObject)
private
FCaption : String;
FChecked : Boolean;
public
property Caption : String read FCaption write FCaption;
property Checked : Boolean read FChecked write FChecked;
end;
TDataListItem = class(TplDataListItem);
TForm1 = class(TForm)
ListView1: TListView;
Panel1: TPanel;
Button2: TButton;
ImageList1: TImageList;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure ListView1MouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
DataList : TplDataList;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses CommCtrl;
{ TplDataList }
// 仮想リストビュー用のデータを格納するTplDataListの関数とメソッド類
destructor TplDataList.Destroy;
var
i : Integer;
begin
for i := 0 to Count - 1 do begin
Items[i].Free;
end;
inherited;
end;
//-----------------------------------------------------------------------------
procedure TplDataList.Clear;
var
i : Integer;
begin
for i := 0 to Count - 1 do begin
Items[i].Free;
end;
inherited;
end;
//-----------------------------------------------------------------------------
procedure TplDataList.Put(Index: Integer; Item: TplDataListItem);
begin
inherited Items[Index] := Item;
end;
//-----------------------------------------------------------------------------
function TplDataList.Get(Index: Integer): TplDataListItem;
begin
Result := TplDataListItem(inherited Items[Index]);
end;
//-----------------------------------------------------------------------------
function TplDataList.Add(Item: TplDataListItem): Integer;
begin
Result := inherited Add(Item);
end;
//-----------------------------------------------------------------------------
function TplDataList.IndexOf(Item: TplDataListItem): Integer;
begin
Result := inherited IndexOf(Item);
end;
//-----------------------------------------------------------------------------
function TplDataList.Remove(Item: TplDataListItem): Integer;
begin
Result := inherited Remove(Item);
end;
{$R *.dfm}
// 開始時にDataListを生成
procedure TForm1.FormCreate(Sender: TObject);
var
ACol : TListColumn;
begin
Form1.Caption:=FormCaption;
DataList := TplDataList.Create;
//ListViewの設定
ListView1.ViewStyle := vsReport;
ListView1.MultiSelect := True;
ListView1.OwnerData := True; //OwnerDataプロパティをTrueにしておく
ACol := ListView1.Columns.Add;
ACol.Width := 150;
ACol.Caption := '名前';
end;
//=============================================================================
// フォームを表示したらテスト用データを作成
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
i : Integer;
FItem : TDataListItem;
begin
ListView1.Items.Clear;
for i := 0 to 80 do begin // テスト用データの生成
FItem := TDataListItem.Create;
FItem.Caption := Format('Item%.3d', [i]);
FItem.Checked := False;
DataList.Add(FItem);
end;
//ListViewにItems数を通知してListViewの表示を更新
//OnDataHint,OnDataイベントが発生して必要なItemの描画が行われる
ListView1.Items.Count := DataList.Count;
end;
//=============================================================================
// 終了時はDataListを解放
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(DataList);
end;
//=============================================================================
// ListView1のOnDataイベント
// ListViewのItem.Captionの設定
// このOnDataイベントで設定しないと無効.OnDataHintでは設定しても無効
// チェックボックスも同様
// [備考]ListViewのOnDataHintイベントはスクロールすれば発生する
//=============================================================================
procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := DataList[Item.Index].Caption;
//StateIconを設定
//1,0はImageList1のアイテム番号(0はチェックなし画像)
if DataList[Item.Index].Checked then begin
Item.StateIndex := 1;
end else begin
Item.StateIndex := 0;
end;
end;
//=============================================================================
// チェックボックス上のマウスダウン(クリック)でチェックボックスのOn,Off切換
// データリストのCheckedプロパティを変更
// 実際の描画はListViewのRefreshメソッドを実行することで行う
//=============================================================================
procedure TForm1.ListView1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
AItem : TListItem;
AHitTests : THitTests;
begin
AItem := ListView1.GetItemAt(X, Y);
if AItem = nil then exit;
//マウス左ボタンの時のみ
if Button = mbLeft then begin
//座標(X,Y)がStateIcon(状態アイコンまたはビットマップ)上の場合のみ処理
AHitTests := ListView1.GetHitTestInfoAt(X, Y);
if htOnStateIcon in AHitTests then begin
DataList[AItem.Index].Checked := not DataList[AItem.Index].Checked;
//ListViewの表示更新(OnDataイベントが発生する)
ListView1.Refresh;
end;
end;
end;
//=============================================================================
// チェックしてあるアイテムを削除する
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
i : Integer;
begin
for i := DataList.Count - 1 downto 0 do begin
if DataList[i].Checked then DataList.Delete(i);
end;
ListView1.Items.Count := DataList.Count;
//ListViewの表示更新(OnDataまたはOnDataHintイベントが発生する)
ListView1.Refresh;
end;
|