1

I want to position a MessageBox in a particular position with respect to the active cell in a string grid and this is no problem using MessageDlgPos() except that I want to prevent the box running off the right or bottom of the screen when the active cell is close to the right or bottom. What I need for this is a way of getting the dimensions of the box but I cannot see a simple way of getting these. Anyone know how without creating my own box?

Olivier
  • 13,283
  • 1
  • 8
  • 24
Ron Jay
  • 13
  • 2

3 Answers3

1

The MessageDlg...() functions do not support what you are asking for. The dimensions of the dialog are not known until the dialog is being displayed, and you have no way to access the dialog window directly to query/re-position it, except maybe with a WH_CBT hook from SetWindowsHookEx().

That being said...

On Windows Vista+ with Vcl.Dialogs.UseLatestCommonDialogs=true and Visual Styles enabled, the MessageDlg...() functions call the Win32 TaskDialogIndirect() API to display a message box. You have no control over that dialog's dimensions, so you would have to wait for that dialog to issue a TDN_DIALOG_CONSTRUCTED notification to then query its actual dimensions before it is displayed, so you can then adjust its position as needed. However, the MessageDlg...() functions do not provide access to any of TaskDialogIndirect()'s notifications (TCustomTaskDialog, which is used internally, does have an OnDialogConstructed event, amongst other events). So, if you wanted to reposition this dialog, you would have to call TaskDialogIndirect() yourself with a custom callback function (or, use the VCL's TTaskDialog wrapper).

On pre-Vista, or with UseLatestCommonDialogs=false or Visual Styles disabled, the MessageDlg...() functions display a custom VCL TForm via Vcl.Dialogs.CreateMessageDialog() instead, which you can call directly, and then pretty much query, manipulate, and show the returned TForm however you want. Just be sure to Free() it when you are done using it.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks Remy, I shall think about which approach to take but I am committed to other work for the next day or two. – Ron Jay Jun 28 '21 at 22:28
  • Your suggestion of using CreateMessageDialog works perfectly and is very simple to implement. Just create a dialog Form, check its dimensions, set its position and then ShowModal after which process the return value and free the form. Even though using WIndows 10 and Rad Studio 10.4, I didn't need to set UseLatestCommonDialogs=false or Visual Styles disabled. Many thanks for pointing me in this direction. – Ron Jay Jun 30 '21 at 10:57
1

You could use an actual TTaskDialog. You can create you own version of it, add a TaskDialogConstructed procedure and get the dimension in the TaskDialogConstructed procedure. Something along the lines of the following.

type
  TTaskDialog = class(Vcl.Dialogs.TTaskDialog)
  protected
    procedure TaskDialogConstructed(Sender: TObject);
  end;

procedure TTaskDialog.TaskDialogConstructed(Sender: TObject);
var
  TaskDialog: TTaskDialog;
  R: TRect;
begin
  TaskDialog := Sender as TTaskDialog;
  Win32Check(GetWindowRect(TaskDialog.Handle, R));
  
  {... Do whatever with R ...}
  
end;
    
function ExecuteTaskDialog(AOwner: TComponent; ATitle, AText: string; ACommonButtons: TTaskDialogCommonButtons = [tcbOK]): integer;
var
  TaskDialog: TTaskDialog;
begin
  TaskDialog := TTaskDialog.Create(AOwner);
  with TaskDialog do
  begin
    Caption := Application.Title;
    Title := ATitle;
    Text := AText;
    MainIcon := tdiNone;
    Flags := Flags + [tfUseHiconMain];
    CommonButtons := ACommonButtons;
    CustomMainIcon.LoadFromResourceName(HInstance, 'MAINICON');
    OnDialogConstructed := TaskDialogConstructed;
    Execute;
    Result := ModalResult;
    Free;
  end;
end;
Greg Dawson
  • 145
  • 8
  • If you are going to derive a new class, then you should override the virtual `DoOnDialogContructed()` method that is inherited from `TCustomTaskDialog`, rather than assigning a handler to the public `OnDialogConstructed` event – Remy Lebeau Jun 30 '21 at 14:10
0

Create the MessageDlg yourself. Add an OnActivate or OnShow event. In this method, ask / change the properties of the dialog.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.StdCtrls;

type
  Tfrm = class(TForm)
    btn: TButton;
    procedure btnClick(Sender: TObject);
  private
   procedure OnDlgActivate(Sender: TObject);
  public
    { Public-Deklarationen }
  end;

var
  frm: Tfrm;


implementation

uses
  Vcl.Dialogs, System.TypInfo;

{$R *.dfm}


procedure Tfrm.btnClick(Sender: TObject);
var
  Ldlg  : TForm;
  LiRet : integer;
begin
  Ldlg := CreateMessageDialog('Hallo World!', mtInformation,mbYesNo, mbYes);
  try
    Ldlg.OnActivate := OnDlgActivate;
    LiRet := Ldlg.ShowModal;
  finally
    Ldlg.free;
  end;

end;

procedure Tfrm.OnDlgActivate(Sender: TObject);
var
  Lfrm: TForm;
  LcTxt: string;
begin
  Lfrm  := Sender as TForm;
  LcTxt := Format('%s %sLeft: %d / Top: %d', [Lfrm.ClassName, sLineBreak, Lfrm.Left, Lfrm.Top]);

  ShowMessage(LcTxt);
end;

end.

USauter
  • 295
  • 1
  • 9
  • 2
    (1) Why not simply `Ldlg.OnActivate := OnDlgActivate`? (2) You leak one form object for each invocation. Basically this is the idea outlined by Remy, but with a subpar implementation. (3) You don't want to use the Windows 95-styled dialogs in new apps. You want to use task dialogs. – Andreas Rejbrand Jun 29 '21 at 12:54
  • @AndreasRejbrand (1) Right. Was probably not possible with an earlier version of Delphi. (2) Right. I added the try block. (3) I cannot see the desired style of dialogue from the request. – USauter Jun 29 '21 at 13:55
  • @USauter: (3) It is safe to assume (unless stated otherwise) that the OP wants to use the current styles rather than styles from a decade and a half old OS. It's the same way that it is assumed that (unless stated otherwise), code related questions refer to the current version of Delphi and current code solutions are appropriate. – Ken White Jun 30 '21 at 03:54
  • @KenWhite My program code is now 20 years old and has grown over time. Nice that I was able to experience something new. – USauter Jun 30 '21 at 05:26