Неверный намек, отображаемый на 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
режимы?
вот изображения того, что я получаю:
EDIT:
Давид спросил почему!--3--> был установлен до True
. Есть две причины:--15-->
- таким образом, я могу "запретить" выбор пользователя.
- если я поставил
OwnerDraw
toFalse
, у меня другая проблема. См.почему я получаю белые разделители столбцов в моем настраиваемом 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
отображается, но не скрывается, если вы не выходите из прямоугольника клиента управления или подсказка показывает интервал времени (даже если вы снова наведете курсор на элемент с сокращенным заголовком). Проблема в том, что я не знаю как указать theCursorRect
на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.