Неверный намек, отображаемый на TListView с OwnerData и OwnerDraw, установлен в True

я использую Delphi 2007. У меня есть TListView С OwnerData и OwnerDraw установить значение True. ViewStyle установлено значение vsReport.

у меня есть 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 подсказка не отображается вообще. В Windows Vista и Windows 7, когда моя мышь находится над элементом, он показывает подсказку, которая полностью выключена.

у меня нет специального кода для обработки намеки. Должен ли он быть в OwnerData и OwnerDraw режимы?

вот изображения того, что я получаю:

ListviewListview with hint

EDIT: Давид спросил почему!--3--> был установлен до True. Есть две причины:--15-->

  1. таким образом, я могу "запретить" выбор пользователя.
  2. если я поставил OwnerDraw to False, у меня другая проблема. См.почему я получаю белые разделители столбцов в моем настраиваемом listview?

EDIT 2: Если Я управляю OnInfoTip событие, как предложил Тлама, я получаю подсказку unthemed balloon и неправильный намек из Windows Vista & 7.

1 ответов


1. Среды

поведение, описанное здесь, я испытал и протестировал только на Windows 7 SP1 64-bit Home Premium с последними обновлениями, установленными с приложением, встроенным в 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 ?

задание OwnerDraw свойство False фактически решает проблему (подсказки затем отображаются с правильными текстами элементов фактическим зависшим элементом), но вы сказали, что вам нужно использовать чертеж владельца, поэтому это также не решение для вас.

3.3. Удалить стиль LVS_EX_INFOTIP ?

удаление LVS_EX_INFOTIP стиль из стиля представления списка, наконец, перестал показывать подсказки элемента системой, но также вызвал, что управление остановлено для отправки родительской подсказке уведомлений. Как следствие этого является OnInfoTip событие с отключенной функциональностью. В этом случае вам необходимо полностью реализовать обработку подсказок самостоятельно. И это то, что я пробовал в следующем коде.

4. Решение

я решил отключить все системные подсказки представления списка, исключив LVS_EX_INFOTIP стиль и реализация собственной обработки всплывающих подсказок. Так насколько я знаю, по крайней мере, о следующих проблемах:

  • когда вы используете обычный Hint собственность и Ховер из элемента с сокращенной подписи к пустой область представления списка,Hint отображается, но не скрывается, если вы не выходите из прямоугольника клиента управления или подсказка показывает интервал времени (даже если вы снова наведете курсор на элемент с сокращенным заголовком). Проблема в том, что я не знаю как указать the CursorRect на THintInfo структура, так что вы покров весь прямоугольник клиента, кроме прямоугольника области элементов.

  • вы должны использовать те же экстенты прямоугольника элемента, что и в методе событий рисования владельца, поскольку система не знает, где вы рендеринг текста ваших элементов. Еще один недостаток-это синхронизация.

вот код основного блока из демо-проекта, который вы можете скачать 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.