2011. március 17., csütörtök

How to implement custom button captions in a MessageDlg


Problem/Question/Abstract:

Is there a way to show a message box with some custom button captions (not only Yes, No, Cancel, etc.)? I know there are some third party components for using translating an application in different languages, but I would like to do it with only the standard functions or APIs.

Answer:

{
TggMessageDlg Component.
Author: Geurts Guido.
Date: 04 December 1998.
Delphi version: Delphi 3 Client/Server, no patches installed.
Operating System: Windows NT 4 WorkStation.
Known bugs: None at this time

Still to test features:
Try running it under different languages of windows, see if it still is able to change the captions of
the buttons.
}

unit ggMsgDlg;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, DsgnIntf;

type
  TAboutProperty = class(TPropertyEditor)
  private
  protected
  public
    procedure Edit; override;
    function GetAttributes: TPropertyAttributes; override;
    function GetName: string; override;
    function GetValue: string; override;
  end;

  {This class can hold the different values for the caption used in the messagebox}
  TggDlgTypeCaption = class(TPersistent)
  private
    FInformationText: string;
    FWarningText: string;
    FErrorText: string;
    FConfirmationText: string;
    FCustomText: string;
  protected
  public
  published
    property InformationText: string read FInformationText write FInformationText;
    property WarningText: string read FWarningText write FWarningText;
    property ErrorText: string read FErrorText write FErrorText;
    property ConfirmationText: string read FConfirmationText write FConfirmationText;
    property CustomText: string read FCustomText write FCustomText;
  end;

  {This class stores values that can be used later to determine if a "button" is to be included
  in the messagebox or not, and if so, if the caption and/ or width needs to be overriden.}
  TggButton = class(TPersistent)
  private
    FInclude: Boolean;
    FCaption: string;
    FWidth: Integer;
  protected
  public
  published
    property Include: Boolean read FInclude write FInclude;
    property Caption: string read FCaption write FCaption;
    property Width: Integer read FWidth write FWidth;
  end;

  {This class defines the possible buttons that can be set and configured in the messagebox.
  To know if a button is to be included or not, and any other information about this button, is
  stored in the TggButton Class.}
  TggButtons = class(TPersistent)
  private
    FYes: TggButton;
    FNO: TggButton;
    FCancel: TggButton;
    FOK: TggButton;
    FHelp: TggButton;
    FAbort: TggButton;
    FRetry: TggButton;
    FIgnore: TggButton;
    FAll: TggButton;
  protected
  public
    constructor Create;
    destructor Destroy; override;
  published
    property Yes: TggButton read FYes write FYes;
    property NO: TggButton read FNo write FNo;
    property Cancel: TggButton read FCancel write FCancel;
    property OK: TggButton read FOK write FOK;
    property Help: TggButton read FHelp write FHelp;
    property Abort: TggButton read FAbort write FAbort;
    property Retry: TggButton read FRetry write FRetry;
    property Ignore: TggButton read FIgnore write FIgnore;
    property All: TggButton read FAll write FAll;
  end;

  {This is the actual ggMessageBox Component. This is the only registed class of this unit.}
  TggMessageDlg = class(TComponent)
  private
    FAbout: TAboutProperty;
    FDlgType: TMsgDlgType;
    FDlgTypeText: TggDlgTypeCaption;
    FMsgDlgButtons: TMsgDlgButtons;
    FText: string;
    FWidth: Integer;
    FggButtons: TggButtons;
    FDesignTimeTest: Boolean;
  protected
    function DoggMessageDLG(const Msg: string; DlgType: TMsgDlgType;
      ggButtons: TMsgDlgButtons; HelpCtx: LongInt): Integer;
    procedure SetDesignTimeTest(Value: Boolean);
    property MsgDlgButtons: TMsgDlgButtons read FMsgDlgButtons write FMsgDlgButtons;
  public
    constructor Create(aOwner: TComponent); override;
    destructor Destroy; override;
    function Execute: Integer;
  published
    property About: TAboutProperty read FAbout write FAbout;
    property Text: string read FText write FText;
    property DlgType: TMsgDlgType read FDlgType write FDlgType;
    property Width: Integer read FWidth write FWidth;
    property DlgTypeCaption: TggDlgTypeCaption read FDlgTypeText write FDlgTypeText;
    property ggButtons: TggButtons read FggButtons write FggButtons;
    property DesignTimeTest: Boolean read FDesignTimeTest write SetDesignTimeTest;
  end;

procedure register;

implementation

{The TggButtons Class}

constructor TggButtons.Create;
begin
  inherited Create;
  FYes := TggButton.Create;
  FNo := TggButton.Create;
  FCancel := TggButton.Create;
  FOK := TggButton.Create;
  FHelp := TggButton.Create;
  FAbort := TggButton.Create;
  FRetry := TggButton.Create;
  FIgnore := TggButton.Create;
  FAll := TggButton.Create;
end;

destructor TggButtons.Destroy;
begin
  FYes.Free;
  FNo.Free;
  FCancel.Free;
  FOK.Free;
  FHelp.Free;
  FAbort.Free;
  FRetry.Free;
  FIgnore.Free;
  FAll.Free;
  inherited Destroy;
end;

{The TggMessageDlg Component}

constructor TggMessageDlg.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDlgTypeText := TggDlgTypeCaption.Create;
  FggButtons := TggButtons.Create;
  ggButtons.OK.Include := True;
  DlgType := mtInformation;
  {if (csAncestor in ComponentState) then
    DesignTimeTest := True;  //Does not work yet}
end;

destructor TggMessageDlg.Destroy;
begin
  FDlgTypeText.Free;
  FggButtons.Free;
  inherited Destroy;
end;

{This published property can show the designed messagebox at designtime so the developer
does not have to his program every time he changes the messagebox and want's to see what he
has made of it. Its value remains false, because there simply is no use for storing anything here.}

procedure TggMessageDlg.SetDesignTimeTest(Value: Boolean);
begin
  {There's no need to set anything here, so let's not confuse the user to much here.}
  if Value then
  begin
    if Text = '' then
      Text := 'FreeWare' + #13 + 'by' + #13 + 'Geurts Guido' + #13 + '1998' + #13 + 'Delphi 3';
    Execute;
    if Text = 'FreeWare' + #13 + 'by' + #13 + 'Geurts Guido' + #13 + '1998' + #13 + 'Delphi 3' then
      Text := '';
  end;
end;

{This public procedure still needs to be rebuild to give back the modal result of the messagebox.
Damned, why did I not think of this before. It will popup the messagebox at runtime.}

function TggMessageDlg.Execute: Integer;
begin
  Result := -1;
  MsgDlgButtons := [];
  with ggButtons do
  begin
    if YES.Include then
      MsgDlgButtons := MsgDlgButtons + [mbYes];
    if NO.Include then
      MsgDlgButtons := MsgDlgButtons + [mbNO];
    if Cancel.Include then
      MsgDlgButtons := MsgDlgButtons + [mbCancel];
    if OK.Include then
      MsgDlgButtons := MsgDlgButtons + [mbOK];
    if Help.Include then
      MsgDlgButtons := MsgDlgButtons + [mbHelp];
    if Abort.Include then
      MsgDlgButtons := MsgDlgButtons + [mbAbort];
    if Retry.Include then
      MsgDlgButtons := MsgDlgButtons + [mbRetry];
    if Ignore.Include then
      MsgDlgButtons := MsgDlgButtons + [mbIgnore];
    if All.Include then
      MsgDlgButtons := MsgDlgButtons + [mbAll];
  end;
  Result := DoggMessageDLG(Text, DlgType, MsgDlgButtons, 0);
end;

{This function is the actual motor of the component. It will change the layout of the messabox
while Delphi is creating it, to the layout speficied by the devoloper.}

function TggMessageDlg.DoggMessageDLG(const Msg: string; DlgType: TMsgDlgType;
  ggButtons: TMsgDlgButtons; HelpCtx: LongInt): Integer;
var
  I: Integer;
begin
  with CreateMessageDialog(Msg, DlgType, ggButtons) do
  try
    case DlgType of
      mtInformation:
        if DlgTypeCaption.InformationText <> '' then
          Caption := DlgTypeCaption.InformationText;
      mtWarning:
        if DlgTypeCaption.WarningText <> '' then
          Caption := DlgTypeCaption.WarningText;
      mtError:
        if DlgTypeCaption.ErrorText <> '' then
          Caption := DlgTypeCaption.ErrorText;
      mtConfirmation:
        if DlgTypeCaption.ConfirmationText <> '' then
          Caption := DlgTypeCaption.ConfirmationText;
      mtCustom:
        if DlgTypeCaption.CustomText <> '' then
          Caption := DlgTypeCaption.CustomText;
    end;
    for I := 0 to ComponentCount - 1 do
    begin
      if (Components[I]).name = 'Yes' then
      begin
        if Self.ggButtons.Yes.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.Yes.Caption;
        if Self.ggButtons.Yes.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.Yes.Width;
      end;
      if (Components[I]).name = 'No' then
      begin
        if Self.ggButtons.NO.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.NO.Caption;
        if Self.ggButtons.NO.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.NO.Width;
      end;
      if (Components[I]).name = 'Cancel' then
      begin
        if Self.ggButtons.Cancel.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.Cancel.Caption;
        if Self.ggButtons.Cancel.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.Cancel.Width;
      end;
      if (Components[I]).name = 'OK' then
      begin
        if Self.ggButtons.OK.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.OK.Caption;
        if Self.ggButtons.OK.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.OK.Width;
      end;
      if (Components[I]).name = 'Help' then
      begin
        if Self.ggButtons.Help.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.Help.Caption;
        if Self.ggButtons.Help.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.Help.Width;
      end;
      if (Components[I]).name = 'Abort' then
      begin
        if Self.ggButtons.Abort.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.Abort.Caption;
        if Self.ggButtons.Abort.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.Abort.Width;
      end;
      if (Components[I]).name = 'Retry' then
      begin
        if Self.ggButtons.Retry.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.Retry.Caption;
        if Self.ggButtons.Retry.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.Retry.Width;
      end;
      if (Components[I]).name = 'Ignore' then
      begin
        if Self.ggButtons.Ignore.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.Ignore.Caption;
        if Self.ggButtons.Ignore.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.Ignore.Width;
      end;
      if (Components[I]).name = 'All' then
      begin
        if Self.ggButtons.All.Caption <> '' then
          TButton(Components[I]).Caption := Self.ggButtons.All.Caption;
        if Self.ggButtons.All.Width <> 0 then
          TButton(Components[I]).Width := Self.ggButtons.All.Width;
      end;
    end;
    HelpContext := HelpCtx;
    {Width := Self.Width;}
    Result := ShowModal;
  finally
    Free;
  end;
end;

{TAboutProperty}

procedure TAboutProperty.Edit;
begin
  MessageBox(0, PChar('TggMessageDlg component' + #13 + #13 + 'by Geurts
    Guido - guido.geurts@advalvas.be ' + #13 + ' 10 / 03 / 1999'),
    PChar('The GuidoG utilities present...'), MB_OK);
end;

function TAboutProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paDialog, paReadOnly];
end;

function TAboutProperty.GetName: string;
begin
  Result := 'About';
end;

function TAboutProperty.GetValue: string;
begin
  Result := GetStrValue;
end;

{Non class related procedures and functions}

procedure register;
begin
  RegisterComponents('GuidoG', [TggMessageDlg]);
  RegisterPropertyEditor(TypeInfo(TAboutProperty), TggMessageDlg, 'About', TAboutProperty);
end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése