2005. május 22., vasárnap

How to modify dialog boxes


Problem/Question/Abstract:

To define additional controls for a dialog box, I use a custom template as demonstrated by the TOpenPictureDialog source code. My component is a TOpenDialog descendant which needs space for extra controls on the bottom of the dialog. This works fine, except for the dimensions of the dialog.

Answer:

I've found the idea of using a dialog template to be a real pain - you basically have to throw away the Delphi TOpenDialog and do everything through the API functions. Instead, I modify the dialog in the OnShow event. At the time this event occurs, the component's Handle is valid.

I can change the size of the dialog window, or change its caption, using simple messages. I can enumerate its controls by simply stepping through with FindWindowEx. And I can add new controls using CreateWindow(). E.g. in a recent project I added a button to the Font dialog that lets the user take action regarding the selected font. I had calculated the position of the Rightmost control, and the Lowest control, and used those to place the button. It's also necessary to set the font for the new button, and to subclass the dialog, thus:


{ ... }
BtnHandle := CreateWindow('BUTTON', '&Ban', WS_CHILD or WS_CLIPSIBLINGS or
  WS_VISIBLE or WS_TABSTOP or BS_PUSHBUTTON, Rightmost - 72,
  Lowest - 21, 72, 21, DlgH, BanBtn_ID, HInstance, nil);
{Set the new button's font}
TempFont := TFont.Create;
try
  PostMessage(BtnHandle, WM_SETFONT, Longint(TempFont.Handle), MAKELPARAM(1, 0));
finally
  TempFont.Free;
end;
{Subclass the dialog to process the new button}
Integer(@GlobalWas) := SetWindowLong(DlgH, GWL_WNDPROC, Longint(@BanBtnWndProc));
{ ... }


The replacement dialog proc is pretty simple - if any control but our new button is pressed, it passes the processing to the old dlgproc. If it IS our button, it checks to make sure there IS a selection in the font name combobox (whose window handle was obtained during the enumeration of the box's controls) and, if so, calls a routine in the main form.


function BanBtnWndProc(HWindow: HWND; Msg: UINT; wParam: WPARAM;
  lParam: LPARAM): LRESULT; stdcall;
{This wndproc subclasses the font dialog and responds to the added Ban button}
var
  buff: array[0..MAX_PATH] of Char;
  sel: Integer;
begin
  if (Msg = WM_COMMAND) and (Lo(wParam) = BanBtn_ID) then
  begin
    sel := SendMessage(GlobalCBH, CB_GETCURSEL, 0, 0);
    if Sel >= 0 then
      SendMessage(GlobalCBH, WM_GETTEXT, MAX_PATH, Integer(@buff))
    else
      Buff[0] := #0;
    if StrLen(Buff) > 0 then
      MainForm.BanFont(StrPas(Buff))
    else
      MessageBeep(MB_ICONSTOP);
    Result := 0;
  end
  else
    Result := GlobalWas(HWindow, Msg, wParam, lParam);
end;


You can accomplish your modification of the file common dialogs using a similar technique.

Nincsenek megjegyzések:

Megjegyzés küldése