Есть ли ошибка в элементе управления списком Delphi при использовании пользовательского рисунка? - PullRequest
14 голосов
/ 19 ноября 2011

QC # 101189

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

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

enter image description here

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

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

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

Файл Pascal

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

Ответы [ 2 ]

13 голосов
/ 24 ноября 2011

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

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

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

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

0 голосов
/ 19 ноября 2011

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

...