Подтвердить что ты не робот

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

QС# 101189

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

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

enter image description here

Текст в столбце 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 = <
      item
        Caption = 'Column 1'
        Width = 250
      end
      item
        Caption = 'Column 2'
        Width = 250
      end>
    ViewStyle = vsReport
    OnCustomDrawSubItem = ListViewCustomDrawSubItem
  end
end
4b9b3361

Ответ 1

Это обходной путь для дефектного поведения, а не ответ на вопрос, есть ли ошибка в 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 отличаются от пользовательских чертежей другими элементами управления и несколько сложными (см.: Пользовательский чертеж с элементами управления List-View и Tree-View). Но вы полностью контролируете весь процесс. Код в NM_CUSTOMDRAW случае TCustomListView.CNNotify в 'comctrls.pas' VCL одинаково сложный. Но, несмотря на то, что вам предоставлена ​​куча пользовательских обработчиков чертежей (половина из них продвинута), вы не можете контролировать, что делает VCL. Например, вы не можете вернуть CDRF_xxx, который хотите, или вы не можете установить clrTextBk, который вы хотите. Мое предубежденное мнение состоит в том, что в элементе управления представлением списка Delphi есть проблема с ошибкой/дизайном, но у меня нет ничего более конкретного, чем интуиция, как в поиске обходного пути.

Ответ 2

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