Есть ли ошибка в управлении представлением списка Delphi при использовании пользовательского чертежа?
QC # 101189
Я пытаюсь TListView
в Delphi TListView
как было предложено ответом NGLN на другой вопрос SO . Это отлично работает, кроме взаимодействия с горячим отслеживанием, когда вы рисуете, используя новую тему проводника, представленную в Vista.
Горячая картинка слежения и события пользовательского рисования Delphi, похоже, мешают друг другу. Например, вид вывода, который я вижу, выглядит следующим образом:
- Разбивается ли COM в XE2 и как я могу его обойти?
- Учебник стилей Delphi VCL - как изменить стиль во время выполнения
- Как динамически создавать элементы управления, совпадающие с вершиной, но после других выровненных элементов управления?
- Delphi XE2: Возможно ли создать экземпляр формы FireMonkey в приложении VCL?
- Каковы причины использования TArray вместо массива T?
Текст в колонке 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
- TThreadedQueue не способен к нескольким потребителям?
- Delphi: Нарушение доступа в конце конструктора Create ()
- Как проверить URL с помощью IdHTTP?
- Как определить версию приложения в одном месте для нескольких приложений?
- Библиотека Delphi JSON для XE2, доступная для сериализации объектов
- Как разбирать вложенный объект JSON в Delphi XE2?
Это временное решение для дефектного поведения, а не ответ на вопрос, есть ли ошибка в 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
.