2007. június 13., szerda

Display custom hint messages in a TOpenDialog


Problem/Question/Abstract:

I would like to modify the behavior of the standard OpenDialog component in Delphi 6 to show my custom hints when the mouse pointer is over particular file shown on the OpenDialog screen. By default the screen shows a hint with the file extension and size. I tried to access the (supposedly) integrated component on the dialog screen in a similar way I have done with the QuickReport standard preview screen (not the Preview component from the palette) - using client.parent. I realize that the implementation of the OpenDialog may directly reference Windows DLLs.Is there a way I could implement custom hint messages?

Answer:

Well, it should be possible, but it will be awkward. The TOpenDialog is not a component wrapper around a control you could easily subclass, it is a wrapper around an API function that shows a dialog. The dialog contains a number of Windows controls, among which is the listview that shows the files. The listviews parent will get WM_NOTIFY messages from the listview (heaps of them, in fact), among which is the notification asking for the tooltip text. You need to subclass the parent the API way to get hold of this message. A place to do this is the TOpenDialogs OnShow event. The parent handle is not the components Handle property, by the way, you need to go one level up via Windows.GetParent to get the dialog boxes true handle. Do a recursive EnumChildWindow on this handle to investigate the control hierarchy on the dialog. I dimly remember that the listview and its container gets created after OnShow, so you may have to delay the enumeration via PostMessage.

The following gets the listview's handle, the listview is recreated by the dialog as needed so you have to retrieve the handle each time you want to access it.

{ ... }
type
  pWndSt r = ^hWndStr;
  hWndStr = record
    lpStr: string;
    hWnd: HWND;
  end;

function ClassProc(hWnd: HWND; p: pWndStr): Boolean; stdcall;
var
  strBuf: array[0..20] of Char;
begin
  FillChar(strBuf, SizeOf(strBuf), #0);
  GetClassName(hWnd, @strBuf[0], 20);
  if StrPas(strBuf) = p^.lpStr then
  begin
    Result := False;
    p^.hWnd := hWnd;
  end
  else
    Result := True;
end;

function ChildByClass(hWnd: HWND; lpzClass: string): HWND;
var
  p: pWndStr;
begin
  New(p);
  p^.lpStr := lpzClass;
  p^.hWnd := 0;
  EnumChildWindows(hWnd, @ClassProc, Longint(p));
  Result := p^.hWnd;
  Dispose(p);
end;

function TOpenPictureDialogEx.SystemLVHWND: HWND;
begin
  {Handle here is the TOpenPictureDialogEx's Handle as this is
  a decendant of TOpenPictureDialog.}
  result := ChildByClass(GetParent(Handle), 'SysListView32');
end;

Nincsenek megjegyzések:

Megjegyzés küldése