看看老外写的。Extended GetItemAtThis method (GetItemAt) only provides the information about which ListItem (if any) is located at the specified coordinates passed as parameters, but only works with the first column of the TListView. The rest are ignored. If we needed to know if the user clicked on an element in another column, we can declare a new method in a derived class:uses ComCtrls;type TListViewX = class(TListView) public function GetItemAtX(X, Y: integer; var Col: integer): TListItem; end;implementationfunction TListViewX.GetItemAtX(X, Y: integer; var Col: integer): TListItem; var i, n, RelativeX, ColStartX: Integer; ListItem: TlistItem; begin Result := GetItemAt(X, Y); if Result <> nil then begin Col := 0; // First column end else if (ViewStyle = vsReport) and (TopItem <> nil) then begin // First, let's try to find the row ListItem := GetItemAt(TopItem.Position.X, Y); if ListItem <> nil then begin // Now let's try to find the Column RelativeX := X-ListItem.Position.X-BorderWidth; ColStartX := Columns[0].Width; n := Columns.Count - 1; for i := 1 to n do begin if RelativeX < ColStartX then break; if RelativeX <= ColStartX + StringWidth(ListItem.SubItems[i-1]) then begin Result := ListItem; Col := i; break; end;//if Inc(ColStartX, Columns[i].Width); end;//for end;//if end;//if end;Casting to the new classWe don't need to intall this new component and register it in the components palette as we explained in another article. Instead, any time we want to access this method, we can just cast the object (for example ListView1) to our new class. For example in a MouseDown event:procedure TForm1.ListView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var col: integer; li: TListItem; begin li := TListViewX(ListView1).GetItemAtX(x, y, col); if li <> nil then ShowMessage('Column #' + IntToStr(col)); end;
修改了一下function TListViewX.GetItemAtX(X, Y: integer; var Col: integer): TListItem; var i, n, RelativeX, ColStartX: Integer; ListItem: TlistItem; OldRowSelect:Boolean; Found:Boolean; begin Result := GetItemAt(X, Y); if (not RowSelect) and (Result <> nil) then begin Col := 0; // First column end else if (ViewStyle = vsReport) and (TopItem <> nil) then begin // First, let's try to find the row //ListItem := GetItemAt(TopItem.Position.X, Y); //save rowselect setting OldRowSelect := RowSelect; RowSelect := True; ListItem := GetItemAt(X, Y); //Restore rowselect setting; RowSelect := OldRowSelect; if ListItem <> nil then begin // Now let's try to find the Column RelativeX := X - ListItem.Position.X - BorderWidth; // ColStartX := Columns[0].Width; ColStartX:=0; n := Columns.Count - 1; for i := 0 to n do begin if RelativeX < ColStartX + Columns[i].Width then begin Result:=ListItem; Col:=i; break; end; { if RelativeX <= ColStartX + StringWidth(ListItem.SubItems[i - 1]) then begin Result := ListItem; Col := i; break; end; //if} Inc(ColStartX, Columns[i].Width); end; //for // Col:=i; end; //if end; //if end;
修改了一下: function TListViewX.GetItemAtX(X, Y: integer; var Col: integer): TListItem; var i, n, RelativeX, ColStartX: Integer; ListItem: TlistItem; OldRowSelect:Boolean; Found:Boolean; begin Result := GetItemAt(X, Y); if (not RowSelect) and (Result <> nil) then begin Col := 0; // First column end else if (ViewStyle = vsReport) and (TopItem <> nil) then begin // First, let's try to find the row //ListItem := GetItemAt(TopItem.Position.X, Y); //save rowselect setting OldRowSelect := RowSelect; RowSelect := True; ListItem := GetItemAt(X, Y); //Restore rowselect setting; RowSelect := OldRowSelect; if ListItem <> nil then begin // Now let's try to find the Column RelativeX := X - ListItem.Position.X - BorderWidth; // ColStartX := Columns[0].Width; ColStartX:=0; n := Columns.Count - 1; for i := 0 to n do begin if RelativeX < ColStartX + Columns[i].Width then begin Result:=ListItem; Col:=i; break; end; { if RelativeX <= ColStartX + StringWidth(ListItem.SubItems[i - 1]) then begin Result := ListItem; Col := i; break; end; //if} Inc(ColStartX, Columns[i].Width); end; //for // Col:=i; end; //if end; //if end;
改了一下function TListViewX.GetItemAtX(X, Y: integer; var Col: integer): TListItem; var i, n, RelativeX, ColStartX: Integer; ListItem: TlistItem; OldRowSelect:Boolean; Found:Boolean; begin Result := GetItemAt(X, Y); if (not RowSelect) and (Result <> nil) then begin Col := 0; // First column end else if (ViewStyle = vsReport) and (TopItem <> nil) then begin // First, let's try to find the row //ListItem := GetItemAt(TopItem.Position.X, Y); //save rowselect setting OldRowSelect := RowSelect; RowSelect := True; ListItem := GetItemAt(X, Y); //Restore rowselect setting; RowSelect := OldRowSelect; if ListItem <> nil then begin // Now let's try to find the Column RelativeX := X - ListItem.Position.X - BorderWidth; // ColStartX := Columns[0].Width; ColStartX:=0; n := Columns.Count - 1; for i := 0 to n do begin if RelativeX < ColStartX + Columns[i].Width then begin Result:=ListItem; Col:=i; break; end; { if RelativeX <= ColStartX + StringWidth(ListItem.SubItems[i - 1]) then begin Result := ListItem; Col := i; break; end; //if} Inc(ColStartX, Columns[i].Width); end; //for // Col:=i; end; //if end; //if end;
TListViewX = class(TListView)
public
function GetItemAtX(X, Y: integer; var Col: integer): TListItem;
end;implementationfunction TListViewX.GetItemAtX(X, Y: integer;
var Col: integer): TListItem;
var
i, n, RelativeX, ColStartX: Integer;
ListItem: TlistItem;
begin
Result := GetItemAt(X, Y);
if Result <> nil then begin
Col := 0; // First column
end else if (ViewStyle = vsReport)
and (TopItem <> nil) then begin
// First, let's try to find the row
ListItem := GetItemAt(TopItem.Position.X, Y);
if ListItem <> nil then begin
// Now let's try to find the Column
RelativeX := X-ListItem.Position.X-BorderWidth;
ColStartX := Columns[0].Width;
n := Columns.Count - 1;
for i := 1 to n do begin
if RelativeX < ColStartX then break;
if RelativeX <= ColStartX +
StringWidth(ListItem.SubItems[i-1]) then
begin
Result := ListItem;
Col := i;
break;
end;//if
Inc(ColStartX, Columns[i].Width);
end;//for
end;//if
end;//if
end;Casting to the new classWe don't need to intall this new component and register it in the components palette as we explained in another article. Instead, any time we want to access this method, we can just cast the object (for example ListView1) to our new class. For example in a MouseDown event:procedure TForm1.ListView1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
col: integer;
li: TListItem;
begin
li := TListViewX(ListView1).GetItemAtX(x, y, col);
if li <> nil then
ShowMessage('Column #' + IntToStr(col));
end;
var Col: integer): TListItem;
var
i, n, RelativeX, ColStartX: Integer;
ListItem: TlistItem;
OldRowSelect:Boolean;
Found:Boolean;
begin
Result := GetItemAt(X, Y);
if (not RowSelect) and (Result <> nil) then
begin
Col := 0; // First column
end
else if (ViewStyle = vsReport)
and (TopItem <> nil) then
begin
// First, let's try to find the row
//ListItem := GetItemAt(TopItem.Position.X, Y); //save rowselect setting
OldRowSelect := RowSelect;
RowSelect := True;
ListItem := GetItemAt(X, Y);
//Restore rowselect setting;
RowSelect := OldRowSelect; if ListItem <> nil then
begin
// Now let's try to find the Column
RelativeX := X - ListItem.Position.X - BorderWidth;
// ColStartX := Columns[0].Width;
ColStartX:=0;
n := Columns.Count - 1;
for i := 0 to n do
begin
if RelativeX < ColStartX + Columns[i].Width then
begin
Result:=ListItem;
Col:=i;
break;
end;
{ if RelativeX <= ColStartX +
StringWidth(ListItem.SubItems[i - 1]) then
begin
Result := ListItem;
Col := i;
break;
end; //if}
Inc(ColStartX, Columns[i].Width);
end; //for
// Col:=i;
end; //if
end; //if
end;
function TListViewX.GetItemAtX(X, Y: integer;
var Col: integer): TListItem;
var
i, n, RelativeX, ColStartX: Integer;
ListItem: TlistItem;
OldRowSelect:Boolean;
Found:Boolean;
begin
Result := GetItemAt(X, Y);
if (not RowSelect) and (Result <> nil) then
begin
Col := 0; // First column
end
else if (ViewStyle = vsReport)
and (TopItem <> nil) then
begin
// First, let's try to find the row
//ListItem := GetItemAt(TopItem.Position.X, Y); //save rowselect setting
OldRowSelect := RowSelect;
RowSelect := True;
ListItem := GetItemAt(X, Y);
//Restore rowselect setting;
RowSelect := OldRowSelect; if ListItem <> nil then
begin
// Now let's try to find the Column
RelativeX := X - ListItem.Position.X - BorderWidth;
// ColStartX := Columns[0].Width;
ColStartX:=0;
n := Columns.Count - 1;
for i := 0 to n do
begin
if RelativeX < ColStartX + Columns[i].Width then
begin
Result:=ListItem;
Col:=i;
break;
end;
{ if RelativeX <= ColStartX +
StringWidth(ListItem.SubItems[i - 1]) then
begin
Result := ListItem;
Col := i;
break;
end; //if}
Inc(ColStartX, Columns[i].Width);
end; //for
// Col:=i;
end; //if
end; //if
end;
var Col: integer): TListItem;
var
i, n, RelativeX, ColStartX: Integer;
ListItem: TlistItem;
OldRowSelect:Boolean;
Found:Boolean;
begin
Result := GetItemAt(X, Y);
if (not RowSelect) and (Result <> nil) then
begin
Col := 0; // First column
end
else if (ViewStyle = vsReport)
and (TopItem <> nil) then
begin
// First, let's try to find the row
//ListItem := GetItemAt(TopItem.Position.X, Y); //save rowselect setting
OldRowSelect := RowSelect;
RowSelect := True;
ListItem := GetItemAt(X, Y);
//Restore rowselect setting;
RowSelect := OldRowSelect; if ListItem <> nil then
begin
// Now let's try to find the Column
RelativeX := X - ListItem.Position.X - BorderWidth;
// ColStartX := Columns[0].Width;
ColStartX:=0;
n := Columns.Count - 1;
for i := 0 to n do
begin
if RelativeX < ColStartX + Columns[i].Width then
begin
Result:=ListItem;
Col:=i;
break;
end;
{ if RelativeX <= ColStartX +
StringWidth(ListItem.SubItems[i - 1]) then
begin
Result := ListItem;
Col := i;
break;
end; //if}
Inc(ColStartX, Columns[i].Width);
end; //for
// Col:=i;
end; //if
end; //if
end;