2005. szeptember 14., szerda

Creating an equivalent to the missing TListView.OnColumnDblClick


Problem/Question/Abstract:

How to subclass your header-control (using a TListView), to receive a OnColumnDblClick- equivalent notification?

Answer:

This requires a bit of work. MS did not see fit to send a notification to the TListView when the user double-clicks on the header. But the header control class does have the CS_DBLCLKS style, so it does get WM_LBUTTONDBLCLK messages, it just does not do anything with them.
To get at these messages requires API-style subclassing of the header control. How? See below.


uses..., Commctrl;
...
const
  UM_LISTVIEW_COLUMN_DBLCLICK = WM_USER + 1982;
  ....
    { the HeaderProc function should look something like this: }

function
  HeaderProc(wnd: HWND; msg: Cardinal; wparam: WPARAM; lparam: LPARAM): Longint;
    stdcall;
var
  hti: THDHitTestInfo;
begin
  Result := CallWindowProc(Pointer(GetWindowLong(wnd, GWL_USERDATA)),
    wnd, msg, wparam, lparam);
  if msg = WM_LBUTTONDBLCLK then
  begin
    FillChar(hti, sizeof(hti), 0);
    hti.Point := SmallPointToPoint(TSmallPoint(lparam));
    if SendMessage(wnd, HDM_HITTEST, 0, Longint(@hti)) >= 0 then
      if hti.Flags = HHT_ONHEADER then
        PostMessage(MainForm.Handle, UM_LISTVIEW_COLUMN_DBLCLICK, hti.Item, 0);
    { Change MainForm to whatever you need }
  end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
var
  wnd: HWND;
  oldProc: Integer;
begin
  {beginning of workaround for missing TListView.OnColumnDblClick}
  wnd := GetWindow(aListView.handle, GW_CHILD); { <-- your TListView's name here }
  if wnd <> 0 then
  begin
    if (GetClassLong(wnd, GCL_STYLE) and CS_DBLCLKS) <> 0 then
    begin
      oldproc := GetWIndowLong(wnd, GWL_WNDPROC);
      if GetWindowLong(wnd, GWL_USERDATA) <> 0 then
        raise
          Exception.Create('Cannot sublcass ListView header, USERDATA already in use');
      SetWIndowLong(wnd, GWL_USERDATA, oldproc);
      SetWindowLong(wnd, GWL_WNDPROC, integer(@HeaderProc));
    end;
  end
  else
    ShowMessage('ListView component in vsReport state is missing !!!');
  {...}
  {Do some more wonderful things}
end;

and then don't forget to declare a custom message handler for UM_LISTVIEW_COLUMN_DBLCLICK (this will be your OnColumnDblClick equivalent).

Nincsenek megjegyzések:

Megjegyzés küldése