Есть ли ошибка в управлении представлением списка Delphi при использовании пользовательского чертежа?

QC # 101189

Я пытаюсь TListView в Delphi TListView как было предложено ответом NGLN на другой вопрос SO . Это отлично работает, кроме взаимодействия с горячим отслеживанием, когда вы рисуете, используя новую тему проводника, представленную в Vista.

Горячая картинка слежения и события пользовательского рисования Delphi, похоже, мешают друг другу. Например, вид вывода, который я вижу, выглядит следующим образом:

введите описание изображения здесь

Текст в колонке 1 должен читать пункт 3, но уничтожается. Это похоже на ошибку в оболочке Delphi на элемент управления списком, но в равной степени я могу сделать что-то неправильно!

Хотя я развиваю это в XE2, такое же поведение происходит в 2010 году и, предположительно, XE.

Вот код для воспроизведения этого поведения:

Паскаль

 unit Unit1; interface uses Windows, Classes, Controls, Forms, CommCtrl, ComCtrls; type TForm1 = class(TForm) ListView: TListView; procedure FormCreate(Sender: TObject); procedure ListViewCustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin ListView.RowSelect := True; ListView.Items.Add.Caption := 'Item 1'; ListView.Items.Add.Caption := 'Item 2'; ListView.Items.Add.Caption := 'Item 3'; end; procedure TForm1.ListViewCustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); var R: TRect; begin DefaultDraw := False; ListView_GetSubItemRect(Sender.Handle, Item.Index, SubItem, LVIR_BOUNDS, @R); Sender.Canvas.MoveTo(R.Left, R.Top); Sender.Canvas.LineTo(R.Right-1, R.Bottom-1); end; end. 

Файл формы

 object Form1: TForm1 Caption = 'Custom Draw List View Bug' ClientHeight = 290 ClientWidth = 554 OnCreate = FormCreate object ListView: TListView Align = alClient Columns =  ViewStyle = vsReport OnCustomDrawSubItem = ListViewCustomDrawSubItem end end 

Это временное решение для дефектного поведения, а не ответ на вопрос, есть ли ошибка в VCL и несколько мыслей.

Обходной путь заключается в том, чтобы установить фоновый режим контекста устройства, назначенный общим элементом управления, для рисования элемента cyle до прозрачного после выполнения пользовательского чертежа:

 procedure TForm1.ListViewCustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); var R: TRect; begin if not [CustomDrawing] then // <- If we're not gonna do anything do not Exit; // fiddle with the DC in any way DefaultDraw := False; ListView_GetSubItemRect(Sender.Handle, Item.Index, SubItem, LVIR_BOUNDS, @R); Sender.Canvas.MoveTo(R.Left, R.Top); Sender.Canvas.LineTo(R.Right-1, R.Bottom-1); SetBkMode(Sender.Canvas.Handle, TRANSPARENT); // <- will effect the next [sub]item end; 

В цикле краски [sub] item картина всегда выполняется сверху вниз, элементы с более низким индексом отправляются извещения NM_CUSTOMDRAW до тех, у кого более высокие индексы. Когда мышь перемещается из одной строки в другую, нужно перерисовывать две строки - одну, которая теряет горячее состояние, и тот, кто ее набирает. Казалось бы, когда пользовательский чертеж не действует, рисование строки, которая теряет горячее состояние, оставляет DC в нежелательном состоянии. Это не проблема при перемещении мыши вверх, потому что этот элемент набирается последним.

Пользовательский чертеж Элементы управления ListView и TreeView отличаются от пользовательского рисования других элементов управления и несколько сложны (см. Custom Draw With List-View и Tree-View Controls ). Но вы полностью контролируете весь процесс. Код в случае NM_CUSTOMDRAW для TCustomListView.CNNotify в comctrls.pas VCL одинаково сложный. Но, несмотря на то, что вам предоставлена ​​куча пользовательских обработчиков чертежей (половина из них продвинута ), вы не можете контролировать, что делает VCL. Например, вы не можете вернуть CDRF_xxx вам нужен, или вы не можете установить clrTextBk . Мое предубежденное мнение состоит в том, что в элементе управления представлением списка Delphi есть проблема с ошибкой / дизайном , но у меня нет ничего более конкретного, чем интуиция, как при поиске обходного пути.

У меня нет подсказки для черного прямоугольника в текстовой позиции, но недостающее горячее отслеживание связано с DefaultDraw := False; в вашем коде. OnCustomDrawSubItem вызывается только для subitem <> 0 , поэтому первый столбец рисуется по умолчанию, а второй использует ваш код. Пользовательский чертеж первого столбца можно сделать с помощью OnCustomDrawItem .

Давайте будем гением компьютера.