XPManでListViewの項目が表示されなくなる

解決


Syake  2007-08-28 18:22:36  No: 27546

お世話になります。
また、お力添えをいただければと思います。

ListViewを使用したプログラムで、XPManを有効にした途端にListViewの
項目が表示されなくなりました。
XPManを無効(削除)すると正常に表示します。
簡単なテストプログラムでテストしてみました。

{ ListView  ・・・ OwnerData := True;  OwnerDraw := True}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListView.Items.Clear;
  FSL.Clear;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i :Integer;
begin
  for i := 0 to 10 do
  begin
    FSL.Add(IntToStr(i));
    ListView.Items.Add;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FSL := TStringList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FSL.Free;
end;

procedure TForm1.ListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := FSL.Strings[Item.index];
end;

XPManが無効なら項目名は表示されますが、有効な場合は項目が
表示されません。
何か足りないのか?
私の環境だけなのか?
何か解決策なりご存知の方がおられましたらご教授いただければ
幸いです。

D2006  XP SP2


風来坊  2007-08-28 22:13:23  No: 27547

試してみたところ OwnerDraw := False なら表示されるっぽい。
何が原因なのかはわかりませんが…


そもそも  2007-08-28 22:38:39  No: 27548

ViewStyle := vsIconではオーナードローできなくないですか?
なので、カスタムドローすれば宜しいかと。
XPManで項目が見えたり見えなかったりするのは、コモンコントロールの仕様なのか、Delphiの仕様orバグなのかは分かりませんが。


Syake  2007-08-29 01:38:08  No: 27549

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

>OwnerDraw := False なら表示されるっぽい。
テストでは確かに表示されました。  ありがとうございます。

しかし、本プログラムでは思わぬところでエラーになりました。
OwnerDrawがTrueはエラーにならないですが項目は表示されず
OwnerDrawがFalseではエラーになる。
XPManが無効なら上記はどっち向いてても表示されるしエラーも
でない。
しかし、XPManの有効・無効で内部処理が違うのか?何なのか?

OwnerDrawがFalseでエラーになるようですから、記述を見直して
見ます。  <m(__)m>


Syake  2007-08-29 02:36:26  No: 27550

どうもお手上げ状態です。

テストプログラムにブレイクダウンしてテストしました。
記述を大幅に省いてますので、数値文字はゴミ表示になります。
本プログラムではサムネイルを表示させるプログラムなので・・・

{ ListView OwnerData := True;  OwnerDraw := False}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListView.Items.Clear;
  FSL.Clear;
end;

{データ設定}
procedure TForm1.Button2Click(Sender: TObject);
var
  i :Integer;
begin
  for i := 0 to 1 do
  begin
    FSL.Add(IntToStr(i));
    ListView.Items.Add;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FSL := TStringList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FSL.Free;
end;

procedure TForm1.ListViewCustomDrawItem(Sender: TCustomListView; Item: TListItem; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  ARect: TRect;
begin
  ARect := Item.DisplayRect(drIcon);
  ListView.Canvas.FillRect(ARect);
end;

procedure TForm1.ListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := FSL.Strings[Item.index];
end;

OnCustomDrawItemイベントを記述すると、XPMan有効かつOnDrawをFalseに
するとIndexのエラーになるようです。

更にXPManの有効・無効では処理の流れが違うようです。
XPManの無効では{データ設定}を一通り処理した後に、OnCustomDrawItemと
OnDataイベントで相互に処理しているのに対し、XPManが有効では{データ設
定}のItems.addから其の都度OnCustomDrawItemとOnDataイベントで相互に処
理しているようです。
最終的にOnCustomDrawItemとOnDataイベントで相互に処理しているようです
が、最後のOnDataイベント内でItem.Index値が途方も無い数値をもってきて
いるようで、この時点でIndexのエラーが表示されているようでした。

と、まあ判ったのですが何で?と、言うよりどうすりゃいいいの?  (;_;)


Syake  2007-08-29 03:33:26  No: 27551

・・・で、苦し紛れにOnCustomDrawItemとOnDataに
if (ListView.Items.Count -1 >= Item.Index) and (0 <= Item.Index) then
begin
 ・・・・
end;
を記述。
XPMan有効でもエラーは無くなったけど、今度はマウスポインターが項目の上
を移動する度にひどくちらつく事が判明。
何か疲れた、根本的に何か違うような・・・


Mr.XRAY  URL  2007-08-29 05:23:35  No: 27552

Syakeさん、こんにちは。
ちょっと手抜きですがテストしてみました。
{ ListView OwnerData := True;  OwnerDraw := False}の設定です。
OSはWindowXP(SP2)です。
推測ですが、おそらくTListViewのOnDataHintがミソなのではないかと。

(1) BDS2006を起動、Win32開発環境にする
(2) [ファイル][プロジェクトを開く...]で以下のプロジェクトを開く
     http://homepage2.nifty.com/Mr_XRAY/Delphi/plSamples/T_ListView.htm#03
(3) [ツールパレット]の[Win32]から[TXPManifest]を選択しフォームに配置
(4) [F9]でコンパイル実行
(5) ボタンをクリックして適当なフォルダを選択して表示。

アイコンと共に項目名(ファイル名等)が表示されました。
もちろん、各列のタイトルも表示されています。
次に、

(6) ViewStyleをVsIconに
(7) FormのOnCreatのイメージリスト関係のコードを以下の様に修正
     //システムのイメージリストのハンドルを取得
     ImgListHandle := SHGetFileInfo('C:\',
                      0,
                      SHFileInfo,
                      SizeOf(SHFileInfo),
                      SHGFI_ICON or
                      SHGFI_LARGEICON or   //ここをLARGEICONに変更
                      SHGFI_OPENICON or
                      SHGFI_SYSICONINDEX);
     ListView_SetImageList(ListView1.Handle,ImgListHandle,LVSIL_NORMAL);
     //LVSIL_SMALLをLVSI_NORMALに変更
(9) [F9]でコンパイル実行

アイコンとそのファイル名等が表示されました。

EXE終了後、
OwnerDrawをTrueにして実行すると、何も表示されません。
OwnerDrawがTrueで該当するコードがないので当然ですが。

また、ViewStyleをVsReportに戻し、FormのOnCreateの部分も元に戻し、
OwnerDrawをTrueにして実行すると
アイコンとサイズ、更新日時が非表示となります。

参考になるでしょうか。
OnCustomDrawItemとOnDataの同時使用は避けた方がいいのではないかと思われ
ます。どちらもItemの描画を行うからです(一方は全て、一方は表示範囲のみ)。
Syakeさんとの違いはOnDataHintイベントを使用していることです。

本来は新規プロジェクトでテストすべきでしょうが手抜きということで。

なお、メモリマネージャーは以下のサイトのをものを使用しました。
http://sourceforge.net/projects/fastmm/


そもそも  2007-08-29 07:05:36  No: 27553

確かにエラーが出ますね、vsReport or vsListだと問題ないようですが。
なんなんだろう、バグなんだろうか・・・
それと、Mr.XRAYさんも言われていますが、OnCustomDrawItemとOnDataを同時使用するのはエラー云々以前に無駄です。
自前で描画するならOnCustomDrawItemのみで、しないならOnDataのみを使えば宜しいかと思います。
必ずしも正しい使い方なのかは分かりませんが、私はそうしています。


Mr.XRAY  URL  2007-08-29 09:09:14  No: 27554

あまり良いレスではありませんでしたので、追記します。

ListViewのOnDateイベントを使用するのは、いわゆる仮想リストビューを構成する
場合です。
仮想リストビューというのはListViewの全てのItemを描画するのではなく、実際に
見える部分のみを表示していかにも高速に表示するようにする方式です。

ここで、OwnerDrawをTrueにして、CustomDrawItem等を使用すると、このイベント内
では全てのItemに対して発生します。しかし、OnDateイベントでは全てのItemが準備
されているわけではありせん。そこでIndexのエラーが発生するものと思われます。
ただ、XPManとの関連は不明です。

その実際に表示する範囲のItemはOnDateHintイベントの引数で知ることができます。
StartIndex,EndIndex がそれです(正確にはちょっと違うが)。
したがって、今回の場合、、CustomDrawItemイベント内で処理したい内容を
OnDateHintイベントで行うようにしてみてはいかがでしょうか。


Syake  2007-08-29 17:15:04  No: 27555

皆様、引き続きありがとうございます。
ご意見を参考にちょっとやってみます。

結果は後程・・・・


Syake  2007-08-29 21:14:30  No: 27556

OwnerDataをTrueに
OwnerDrawをFalseに
CustomDrawItemイベントからOnDateHintに変更で、XPMan有効で
ちらつき無く表示する事ができました。
ただ、OnDataとOnDataHintにはItem.Indexの判定記述が、XPMan
が有効の場合には必要なようです。

皆様方、ありがとうございました。


そもそも  2007-08-31 09:19:00  No: 27557

解決されたようであれなんですが、そもそも自前で描画したいからオーナードローしようとしてたのではないんでしょうか?
となると、カスタムドローを使わずにどのように描画するのか疑問です。
自前で描画するつもりがないなら問題ありませんが。

それと、Mr.XRAYさんのレスについてちょっと気になったので。
>ここで、OwnerDrawをTrueにして、CustomDrawItem等を使用すると、
OwnerDrawをTrueにする事と、CustomDrawItemイベントとは何の関係もありません。

>このイベント内では全てのItemに対して発生します。
CustomDrawItemイベントは実際の描画の時しか呼ばれません。

>しかし、OnDateイベントでは全てのItemが準備されているわけではありせん。そこでIndexのエラーが発生するものと思われます。
実際試してみると分かりますが、ListView.Items.Count=2でもOnDataイベントのItem.Indexが22とかになります・・・

>CustomDrawItemイベント内で処理したい内容をOnDateHintイベントで行うようにしてみてはいかがでしょうか。
OnCustomDrawItemイベントはあくまで描画処理をするイベントなのでその処理をOnDataHintに置き換えたりすることはできません、OnDataHintイベントはOnDataイベントで必要なデータを予めキャッシュする為のイベントです。(OnDataは実際の描画以外でも頻繁に呼ばれるので)

一応、これはSyakeさんへのレスです。Mr.XRAYさんへ言いがかりを付けたい訳ではありませんので、あしからず。

因みに、前のレスで自前で描画する時はCustomDrawItemイベントのみでいいと書きましたが、これをやると速度は通常の仮想リストビューより早くなりますが、コモンコントロールとしてのリストビューとしては機能しなくなります。


Syake  2007-08-31 21:12:24  No: 27558

ありがとうございます。

実のところ、上手くいったように思えたのですが、スクロール時に
ひどくちらつくし、DoubleBufferedを使ったら表示されなくなるし
いかがしたもんかと悩んでおりました。
つまるところ、OnDataイベントが邪魔してたのですね。

ご教授頂いた内容で再度見直しました。
OwnerDrawをFalse  OwnerDataをFalse
OnDataイベントの内容は削除し、Item.Captionはデータ取得時に設定
OnDataHintの記述を削除しOnCustomDrawItemイベントに戻す。

以上で正常にXpMan有効、無効も表示されるようになりました。
ListViewのプロパティーを初期のままOnCustomDrawItemで処理すれば
良かったのですね。

ちなみに、OwnerDrawがTrueだと設定したItem.Captionは表示されませ
んでした。

お蔭様で、今度こ解決です。
大変助かりました。  <m(__)m>


Mr.XRAY  URL  2007-09-01 03:50:23  No: 27559

>Mr.XRAYさんへ言いがかりを付けたい訳ではありませんので、あしからず。

と書いてありますが、読んで納得。
ちょっといい加減なレスをしてしまったようです(苦笑)。
このBBSを読んでいる方のためにも。

一部はヘルプを読み返すと理解可能です。また、Indexのエラーの解釈は私の方の
BBSでのやりとりで原因がわかりました。
OnCustomDrawItemとOnDataHintについても理解できました。ご指摘感謝致します。

Syakeさん、

どうもXPManがらみのようですね。サムネイルを作成する際には、該当フォルダ内
の全て作成することになると思われますので、その方法でというこになりそうです
ね。当面は。
当方も、過去に挫折した経験があるので大きなことは言えません。
機会があれば再度挑戦したいと思っています。
コンポーネントを提供されている方もいますが、当時はWindows98でも動作する必要
がありました。今なら利用できるかも知れません。
ただし、XPManとの兼ね合いについては不明です (^_^;)


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

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






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