我在 Delphi 中同时使用所有者绘图和数据列表视图,如果我在第一次以编程方式更改所选行后立即使用 shift 箭头选择,我注意到一个奇怪的问题。
考虑以下窗口,我尝试用最少的代码显示问题:
这是复制问题的最小 Delphi 代码:
unit Main;
//--------------------------------------------------------------------------------------------------
// I N T E R F A C E
//--------------------------------------------------------------------------------------------------
interface uses Classes,
ComCtrls,
Controls,
Dialogs,
ExtCtrls,
Forms,
Graphics,
Messages,
StdCtrls,
SysUtils,
Variants,
Windows;
//--------------------------------------------------------------------------------------------------
// T Y P E D E F I N I T I O N S
//--------------------------------------------------------------------------------------------------
type TMainForm = class(TForm)
listView : TListView;
bottomPanel : TPanel;
position10Button : TButton;
procedure FormCreate(
sender : TObject);
//----------------------------------------------------------------------------------------------
// LIST VIEW EVENT HANDLERS
//----------------------------------------------------------------------------------------------
procedure ListViewData(
sender : TObject;
item : TListItem);
procedure ListViewDrawItem(
sender : TCustomListView;
item : TListItem;
rect : TRect;
state : TOwnerDrawState);
//----------------------------------------------------------------------------------------------
// POSITION BUTTON HANDLER
//----------------------------------------------------------------------------------------------
procedure Position10ButtonClick(
sender : TObject);
private
//----------------------------------------------------------------------------------------------
// WINDOWS MESSAGE HANDLERS
//----------------------------------------------------------------------------------------------
procedure WMMeasureItem(
var msg : TWMMeasureItem); message WM_MEASUREITEM;
private
//----------------------------------------------------------------------------------------------
// DRAWING
//----------------------------------------------------------------------------------------------
procedure DrawHighlightRect(
canvas : TCanvas;
rect : TRect;
color : TColor);
end;
//--------------------------------------------------------------------------------------------------
// G L O B A L V A R I A B L E S
//--------------------------------------------------------------------------------------------------
var MainForm : TMainForm;
//--------------------------------------------------------------------------------------------------
// I M P L E M E N T A T I O N
//--------------------------------------------------------------------------------------------------
implementation uses CommCtrl;
{$R *.dfm}
//--------------------------------------------------------------------------------------------------
// F O R M C R E A T E
//--------------------------------------------------------------------------------------------------
procedure TMainForm.FormCreate(
sender : TObject);
begin
// Set double buffering for listview.
listView.doubleBuffered := TRUE;
// Set listview count: 20 lines.
listView.items.count := 20;
// Set focus on listview.
WINDOWS.SetFocus(
listView.handle);
end;
//--------------------------------------------------------------------------------------------------
// FORM CONTROLS EVENT HANDLERS
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// LIST VIEW EVENT HANDLERS
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// L I S T V I E W D A T A
//--------------------------------------------------------------------------------------------------
procedure TMainForm.ListViewData(
sender : TObject;
item : TListItem);
begin
if item = NIL then EXIT;
item.caption := SYSUTILS.IntToStr(item.index);
end;
//--------------------------------------------------------------------------------------------------
// L I S T V I E W D R A W I T E M
//--------------------------------------------------------------------------------------------------
procedure TMainForm.ListViewDrawItem(
sender : TCustomListView;
item : TListItem;
rect : TRect;
state : TOwnerDrawState);
const TEXT_MARGIN = 7;
var drawRect : TRect;
begin
// Draw focus rectangle for selected item.
if item.selected then
begin
drawRect := rect;
Inc( drawRect.top, 1);
Dec( drawRect.bottom,1);
DrawHighlightRect(
sender.canvas,
drawRect,
clBlack);
end;
// Prepare brush to draw text.
sender.canvas.brush.style := bsClear;
// Draw text.
drawRect := rect;
drawRect.left := TEXT_MARGIN;
WINDOWS.DrawText(
sender.canvas.handle,
PCHAR(item.caption),
Length( item.caption),
drawRect,
DT_SINGLELINE or
DT_LEFT or
DT_VCENTER);
end;
//--------------------------------------------------------------------------------------------------
// P O S I T I O N 1 0 B U T T O N C L I C K
//--------------------------------------------------------------------------------------------------
procedure TMainForm.Position10ButtonClick(
sender : TObject);
begin
WINDOWS.SetFocus(
listView.handle);
// Unselect all.
listView.ClearSelection;
// Select and focus line 10.
listview.items[10].selected := TRUE;
listview.items[10].focused := TRUE;
end;
//--------------------------------------------------------------------------------------------------
// WINDOWS MESSAGE HANDLERS
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// W M M E A S U R E I T E M
//--------------------------------------------------------------------------------------------------
procedure TMainForm.WMMeasureItem(
var msg : TWMMeasureItem);
begin
inherited;
// Set height of list view items.
if msg.IDCtl = listView.handle then msg.measureItemStruct^.itemHeight := 25;
end;
//--------------------------------------------------------------------------------------------------
// D R A W H I G H L I G H T R E C T
//--------------------------------------------------------------------------------------------------
procedure TMainForm.DrawHighlightRect(
canvas : TCanvas;
rect : TRect;
color : TColor);
var topLeft : TPoint;
var topRight : TPoint;
var bottomRight : TPoint;
var bottomLeft : TPoint;
begin
// Prepare pen.
canvas.pen.style := psSolid;
canvas.pen.width := 1;
canvas.pen.mode := pmCopy;
// Compute outer rectangle points.
topLeft.x := rect.left;
topLeft.y := rect.top;
topRight.x := rect.right;
topRight.y := rect.top;
bottomRight.x := rect.right;
bottomRight.y := rect.bottom;
bottomLeft.x := rect.left;
bottomLeft.y := rect.bottom;
// Draw rectangle.
canvas.pen.color := color;
canvas.PolyLine( [ topLeft, topRight, bottomRight, bottomLeft, topLeft]);
// Compute inner rectangle points.
topLeft.x := rect.left + 1;
topLeft.y := rect.top + 1;
topRight.x := rect.right - 1;
topRight.y := rect.top + 1;
bottomRight.x := rect.right - 1;
bottomRight.y := rect.bottom - 1;
bottomLeft.x := rect.left + 1;
bottomLeft.y := rect.bottom - 1;
// Draw rectangle.
canvas.pen.color := color;
canvas.PolyLine( [ topLeft, topRight, bottomRight, bottomLeft, topLeft]);
end;
//--------------------------------------------------------------------------------------------------
end.
[编辑] 正如 Andreas Rejbrand 所指出的,非所有者绘制非所有者数据列表视图也存在问题。
unit Main;
//--------------------------------------------------------------------------------------------------
// I N T E R F A C E
//--------------------------------------------------------------------------------------------------
interface uses Classes,
ComCtrls,
Controls,
Dialogs,
ExtCtrls,
Forms,
Graphics,
Messages,
StdCtrls,
SysUtils,
Variants,
Windows;
//--------------------------------------------------------------------------------------------------
// T Y P E D E F I N I T I O N S
//--------------------------------------------------------------------------------------------------
type TMainForm = class(TForm)
listView : TListView;
bottomPanel : TPanel;
position10Button : TButton;
procedure FormCreate(
sender : TObject);
//----------------------------------------------------------------------------------------------
// POSITION BUTTON HANDLER
//----------------------------------------------------------------------------------------------
procedure Position10ButtonClick(
sender : TObject);
end;
//--------------------------------------------------------------------------------------------------
// G L O B A L V A R I A B L E S
//--------------------------------------------------------------------------------------------------
var MainForm : TMainForm;
//--------------------------------------------------------------------------------------------------
// I M P L E M E N T A T I O N
//--------------------------------------------------------------------------------------------------
implementation uses CommCtrl;
{$R *.dfm}
//--------------------------------------------------------------------------------------------------
// F O R M C R E A T E
//--------------------------------------------------------------------------------------------------
procedure TMainForm.FormCreate(
sender : TObject);
var index : integer;
var newItem : TListItem;
begin
// Set double buffering for listview.
listView.doubleBuffered := TRUE;
for index := 0 to 19 do
begin
newItem := listview.items.Add;
newItem.caption := SYSUTILS.IntToStr( index);
end;
// Set focus on listview.
WINDOWS.SetFocus(
listView.handle);
end;
//--------------------------------------------------------------------------------------------------
// FORM CONTROLS EVENT HANDLERS
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// P O S I T I O N 1 0 B U T T O N C L I C K
//--------------------------------------------------------------------------------------------------
procedure TMainForm.Position10ButtonClick(
sender : TObject);
begin
WINDOWS.SetFocus(
listView.handle);
// Unselect all.
listView.ClearSelection;
// Select and focus line 10.
listview.items[10].selected := TRUE;
listview.items[10].focused := TRUE;
end;
//--------------------------------------------------------------------------------------------------
end.