2005. február 22., kedd

Check which column of a TListView in vsReport style has been clicked


How can I know which column was click in a TListView? GetItemAt only works with the first column.


Solve 1:

The 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:

  TListViewX = class(TListView)
    function GetItemAtX(X, Y: integer; var Col: integer): TListItem;


function TListViewX.GetItemAtX(X, Y: integer;
  var Col: integer): TListItem;
  i, n, RelativeX, ColStartX: Integer;
  ListItem: TlistItem;
  Result := GetItemAt(X, Y);
  if Result <> nil then
    Col := 0; // First column
  else if (ViewStyle = vsReport)
    and (TopItem <> nil) then
    // First, let's try to find the row
    ListItem := GetItemAt(TopItem.Position.X, Y);
    if ListItem <> nil then
      // 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
        if RelativeX < ColStartX then
        if RelativeX <= ColStartX +
          StringWidth(ListItem.SubItems[i - 1]) then
          Result := ListItem;
          Col := i;
        end; //if
        Inc(ColStartX, Columns[i].Width);
      end; //for
    end; //if
  end; //if

Casting to the new class

We don't need to intall this new component and register it in the components palette as we explained in another article ("Adding new methods and properties without registering new components"). 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);
  col: integer;
  li: TListItem;
  li := TListViewX.GetItemAtX(x, y, col);
  if li <> nil then
    ShowMessage('Column #' + IntToStr(col));

Solve 2:


procedure TForm1.ListView1Click(Sender: TObject);
  pt: TPoint;
  col: Integer;
  pos: Integer;
  pt := Listview1.ScreenToClient(pt);
  Pos := -GetScrollPos(ListView1.Handle, SB_HORZ);
  Col := -1;
  while Pos < Pt.X do
    Inc(Pos, ListView_GetColumnWidth(ListView1.Handle, Col));
  if Col >= ListView1.Columns.Count then
    Col := -1; {clicked past last column}

Nincsenek megjegyzések:

Megjegyzés küldése