11

私はDelphi2007を使用しています。withがあり、TListViewTrueに設定されていますOwnerData。に設定されます。OwnerDrawViewStylevsReport

私は持っていrecordます。

type TAList=record
  Item:Integer;
  SubItem1:String;
  SubItem2:String;
end;

var
 ModuleData: array of TAList;

procedure TForm1.ListView3Data(Sender: TObject; Item: TListItem);
begin
 Item.Caption := IntToStr(ModuleData[Item.Index].Item);
 Item.SubItems.Add(ModuleData[Item.Index].SubItem1);
 Item.SubItems.Add(ModuleData[Item.Index].SubItem2);
end;

procedure TForm1.ListView3DrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
 LIndex : integer;
 LRect: TRect;
 LText: string;
 TTListView: TListView;
begin
 TTListView := TListView(Sender);

 if (Item.SubItems[0] = '...') then
 begin
  TTListView.Canvas.Brush.Color := clHighlight;
  TTListView.Canvas.Font.Color  := clHighlightText;
 end else
 begin
  TTListView.Canvas.Brush.Color := TTListView.Color;
  TTListView.Canvas.Font.Color  := TTListView.Font.Color;
 end;

 for LIndex := 0 to TTListView.Columns.Count - 1 do
 begin
  if (not(ListView_GetSubItemRect(TTListView.Handle, Item.Index, LIndex, LVIR_BOUNDS, @LRect))) then Continue;
  TTListView.Canvas.FillRect(LRect);
  if (LIndex = 0) then LText := Item.Caption else LText := Item.SubItems[LIndex - 1];
  LRect.Left := LRect.Left + 6;
  DrawText(TTListView.Canvas.Handle, PChar(LText), Length(LText), LRect, DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX or DT_END_ELLIPSIS);
 end;
end;

SubItem2が切り捨てられたときにヒントを表示したいと思います。Windows XPでは、ヒントはまったく表示されません。WindowsVistaおよびWindows7では、マウスをアイテムの上に置くと、完全にオフになっているヒントが表示されます。

ヒントを処理するための特別なコードはありません。OwnerDataOwnerDrawモードに1つあるべきですか?

これが私が得たものの画像です:

リストビュー
(出典:noelshack.com

ヒント付きリストビュー
(出典:noelshack.com

編集: デビッドはなぜOwnerDrawに設定されたのか尋ねましたTrue。2つの理由があります:

  1. このようにして、ユーザーの選択を「禁止」することができます。
  2. に設定OwnerDrawするとFalse、別の問題が発生します。カスタム描画リストビューに白い列区切り文字が表示されるのはなぜですか?を参照してください。

編集2:OnInfoTip TLamaによって提案されたようにイベント を処理すると、テーマのないバルーンヒントWindows Vista&7からの間違ったヒントが表示されます。

4

1 に答える 1

8

1.環境

ここで説明する動作私はWindows7SP164ビットHomePremiumでのみ経験し、テストしました。最新の更新プログラムは、Delphi 2009で構築されたアプリケーションでインストールされ、最新の更新プログラムも適用されています。他のシステムでは、これを試したことはありません。

2.問題について

スクリーンショットに表示されるデフォルトのアイテムヒントは、VCLからのものではありません。ヒットしたばかりの特定の状況では、システムによって間違った、おそらく何らかの形でキャッシュされた方法で表示されるヒントがあります。最後にホバーしたアイテムのテキストは、ホバーしたばかりのアイテムのヒントとして表示されます。プロパティの構成は次のとおりです(重要な部分だけです。残りはデフォルトのコンポーネント値のままです)。

ListView1.ShowHint := False;
ListView1.OwnerData := True;
ListView1.OwnerDraw := True;
ListView1.ViewStyle := vsReport;

次のイベントが処理されます。

OnData
OnDrawItem

OnDrawItem実際には、問題をシミュレートするためにを処理する必要はありません。OnDataヒントは、イベントのアイテムに与えられたテキストによって示されます。VCLに表示されるヒントに関連する可能性のある通知ハンドラー(またはシステム通知)がないように思われるため、これ以上詳しく追跡することはできません。これが、システムを疑っている理由です。

3.解決する方法

私が試したことは、現在のプロパティ構成を維持する問題を修正しませんでした。これが私が試したことのリストです:

3.1。LVS_EX_LABELTIPスタイルを削除しますか?

一番のお気に入りで、実際に最初にチェックしたのは、アイテムのヒントの表示が停止し、イベントLVS_EX_LABELTIPを通じて独自のカスタムヒントを実装できるようになることを期待して、リストビューのスタイルからを除外することでした。OnInfoTip問題は、このスタイルがリストビューコントロールのどこにも実装されていないため、リストビュースタイルに含まれていないことです。

3.2。OwnerDrawプロパティを無効にしますか?

プロパティをFalseに設定すると、OwnerDraw実際には問題が解決されます(ヒントは、実際のホバーされたアイテムによって正しいアイテムテキストで表示されます)が、所有者の描画を使用する必要があると言っているので、これも解決策ではありません。

3.3。LVS_EX_INFOTIPスタイルを削除しますか?

LVS_EX_INFOTIPリストビューのスタイルからスタイルを削除すると、最終的にシステムによるアイテムヒントの表示が停止しましたが、コントロールが親にツールチップ通知を送信するのを停止しました。この結果として、OnInfoTipその機能が遮断されたイベントが発生します。この場合、ヒント処理を完全に自分で実装する必要があります。そして、それは私が次のコードで試したことです。

4.回避策

LVS_EX_INFOTIPスタイルを除外し、独自のツールチップ処理を実装することにより、リストビューのすべてのシステムヒントを無効にすることにしました。これまでのところ、少なくとも次の問題について知っています。

  • 通常のHintプロパティを使用して、キャプションが短縮されたアイテムからリストビューのHintの領域にカーソルを合わせると、が表示されますが、コントロールクライアントの長方形を終了するか、ヒント表示の時間間隔が経過しない限り、非表示にはなりません(キャプションが短縮されたアイテムにもう一度カーソルを合わせます)。CursorRect問題は、THintInfo構造のを指定する方法がわからないため、アイテム領域の長方形を除くクライアントの長方形全体をカバーすることです。

  • システムはアイテムのテキストをどこにレンダリングしているかを認識しないため、所有者の描画イベントメソッドで使用するのと同じアイテムの長方形の範囲を使用する必要があります。したがって、もう1つの欠点は、これを同期させることです。

デモプロジェクトのメインユニットのコードは次のとおりです。必要に応じてダウンロードできますfrom here

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, CommCtrl, StdCtrls;

type
  TRecord = record
    Item: Integer;
    SubItem1: string;
    SubItem2: string;
  end;

type
  TListView = class(ComCtrls.TListView)
  private
    procedure CMHintShow(var AMessage: TCMHintShow); message CM_HINTSHOW;
  end;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    procedure FormCreate(Sender: TObject);
    procedure ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
      Rect: TRect; State: TOwnerDrawState);
    procedure ListView1Data(Sender: TObject; Item: TListItem);
  private
    ModuleData: array of TRecord;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  ListColumn: TListColumn;
begin
  SetLength(ModuleData, 3);
  ModuleData[0].Item := 0;
  ModuleData[0].SubItem1 := '[0;0] Subitem caption';
  ModuleData[0].SubItem2 := '[1;0] Subitem caption';
  ModuleData[1].Item := 1;
  ModuleData[1].SubItem1 := '[0;1] Subitem caption';
  ModuleData[1].SubItem2 := '[1;1] Subitem caption';
  ModuleData[2].Item := 2;
  ModuleData[2].SubItem1 := '[0;2] This is a long subitem caption';
  ModuleData[2].SubItem2 := '[0;2] This is even longer subitem caption';

  ListView1.OwnerData := True;
  ListView1.OwnerDraw := True;
  ListView1.ViewStyle := vsReport;

  ListView_SetExtendedListViewStyle(
    ListView1.Handle,
    ListView_GetExtendedListViewStyle(ListView1.Handle) and not LVS_EX_INFOTIP);

  ListColumn := ListView1.Columns.Add;
  ListColumn.Caption := 'Col. 1';
  ListColumn.Width := 50;
  ListColumn := ListView1.Columns.Add;
  ListColumn.Caption := 'Col. 2';
  ListColumn.Width := 50;
  ListColumn := ListView1.Columns.Add;
  ListColumn.Caption := 'Col. 3';
  ListColumn.Width := 50;

  ListView1.Items.Add;
  ListView1.Items.Add;
  ListView1.Items.Add;
end;

procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := IntToStr(ModuleData[Item.Index].Item);
  Item.SubItems.Add(ModuleData[Item.Index].SubItem1);
  Item.SubItems.Add(ModuleData[Item.Index].SubItem2);
end;

procedure TForm1.ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
  Rect: TRect; State: TOwnerDrawState);
var
  R: TRect;
  S: string;
  SubItem: Integer;
  ListView: TListView;
begin
  ListView := TListView(Sender);

  if (Item.SubItems[0] = '...') then
  begin
    ListView.Canvas.Brush.Color := clHighlight;
    ListView.Canvas.Font.Color  := clHighlightText;
  end
  else
  begin
    ListView.Canvas.Brush.Color := ListView.Color;
    ListView.Canvas.Font.Color  := ListView.Font.Color;
  end;

  for SubItem := 0 to ListView.Columns.Count - 1 do
  begin
    if ListView_GetSubItemRect(ListView.Handle, Item.Index, SubItem,
      LVIR_LABEL, @R) then
    begin
      ListView.Canvas.FillRect(R);
      if (SubItem = 0) then
        S := Item.Caption
      else
      begin
        R.Left := R.Left + 6;
        S := Item.SubItems[SubItem - 1];
      end;
      DrawText(ListView.Canvas.Handle, PChar(S), Length(S), R, DT_SINGLELINE or
        DT_VCENTER or DT_NOPREFIX or DT_END_ELLIPSIS);
    end;
  end;
end;

{ TListView }

procedure TListView.CMHintShow(var AMessage: TCMHintShow);
var
  R: TRect;
  S: string;
  Item: Integer;
  SubItem: Integer;
  HitTestInfo: TLVHitTestInfo;
begin
  with AMessage do
  begin
    HitTestInfo.pt := Point(HintInfo.CursorPos.X, HintInfo.CursorPos.Y);
    if ListView_SubItemHitTest(Handle, @HitTestInfo) <> -1 then
    begin
      Item := HitTestInfo.iItem;
      SubItem := HitTestInfo.iSubItem;

      if (Item <> -1) and (SubItem <> -1) and
        ListView_GetSubItemRect(Handle, Item, SubItem, LVIR_LABEL, @R) then
      begin
        if (SubItem = 0) then
          S := Items[Item].Caption
        else
        begin
          R.Left := R.Left + 6;
          S := Items[Item].SubItems[SubItem - 1];
        end;

        if ListView_GetStringWidth(Handle, PChar(S)) > R.Right - R.Left then
        begin
          MapWindowPoints(Handle, 0, R.TopLeft, 1);
          MapWindowPoints(Handle, 0, R.BottomRight, 1);

          HintInfo^.CursorRect := R;
          HintInfo^.HintPos.X := R.Left;
          HintInfo^.HintPos.Y := R.Top;
          HintInfo^.HintMaxWidth := ClientWidth;
          HintInfo^.HintStr := S;

          AMessage.Result := 0;
        end
        else
          AMessage.Result := 1;
      end
      else
        AMessage.Result := 1;
    end
    else
      inherited;
  end;
end;

end.
于 2012-12-15T13:32:02.673 に答える