2009-07-08 28 views

Respuesta

10

Respondiendo a mi propia pregunta .... Escribí la siguiente unidad que funciona bien para mí.

Delphi proporciona CreateMessageDialog() para darle una plantilla de diálogo, que puede modificar antes de mostrar. Lo utilicé para crear una función que llamé MessageDlgCustom, que toma los mismos parámetros que un MessageDlg estándar, pero agrega uno más para los títulos de los botones de reemplazo.

Maneja correctamente las fuentes personalizadas y ajusta automáticamente los botones para que sean lo suficientemente anchos para su mensaje. Si los botones desbordan el diálogo, entonces eso también se ajusta.

Después de usar esa unidad, el ejemplo siguiente funciona:

case MessageDlgCustom('Save your changes?',mtConfirmation, 
    [mbYes,mbNo,mbCancel], 
    ['&Yes, I would like to save them with this absurdly long button', 
    '&No, I do not care about my stupid changes', 
    '&Arg! What are you talking about? Do not close the form!'], 
    nil) //nil = no custom font 
of 
    mrYes: 
    begin 
     SaveChanges; 
     CloseTheForm; 
    end; //mrYes (save & close) 
    mrNo: 
    begin 
     CloseForm; 
    end; //mrNo (close w/o saving) 
    mrCancel: 
    begin 
     //do nothing 
    end; //mrCancel (neither save nor close) 
end; //case 

Si alguien sabe una mejor manera, por favor, comparta.

unit CustomDialog; 

interface 

uses 
    Dialogs, Forms, Graphics, StdCtrls; 

function MessageDlgCustom(const Msg: string; DlgType: TMsgDlgType; 
    Buttons: TMsgDlgButtons; ToCaptions: array of string; 
    customFont: TFont) : integer; 
procedure ModifyDialog(var frm: TForm; ToCaptions : array of string; 
    customFont : TFont = nil); 


implementation 

uses 
    Windows, SysUtils; 

function GetTextWidth(s: string; fnt: TFont; HWND: THandle): integer; 
var 
    canvas: TCanvas; 
begin 
    canvas := TCanvas.Create; 
    try 
    canvas.Handle := GetWindowDC(HWND); 
    canvas.Font := fnt; 
    Result := canvas.TextWidth(s); 
    finally 
    ReleaseDC(HWND,canvas.Handle); 
    FreeAndNil(canvas); 
    end; //try-finally 
end; 

function MessageDlgCustom(const Msg: string; 
    DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; ToCaptions: array of string; 
    customFont: TFont): integer; 
var 
    dialog : TForm; 
begin 
    try 
    dialog := CreateMessageDialog(Msg, DlgType, Buttons); 
    dialog.Position := poScreenCenter; 
    ModifyDialog(dialog,ToCaptions,customFont); 
    Result := dialog.ShowModal; 
    finally 
    dialog.Release; 
    end; //try-finally 
end; 

procedure ModifyDialog(var frm: TForm; ToCaptions: array of string; 
    customFont: TFont); 
const 
    c_BtnMargin = 10; //margin of button around caption text 
var 
    i,oldButtonWidth,newButtonWidth,btnCnt : integer; 
begin 
    oldButtonWidth := 0; 
    newButtonWidth := 0; 
    btnCnt := 0; 
    for i := 0 to frm.ComponentCount - 1 do begin 
    //if they asked for a custom font, assign it here 
    if customFont <> nil then begin 
     if frm.Components[i] is TLabel then begin 
     TLabel(frm.Components[i]).Font := customFont; 
     end; 
     if frm.Components[i] is TButton then begin 
     TButton(frm.Components[i]).Font := customFont; 
     end; 
    end; 
    if frm.Components[i] is TButton then begin 
     //check buttons for a match with a "from" (default) string 
     //if found, replace with a "to" (custom) string 
     Inc(btnCnt); 

     //record the button width *before* we changed the caption 
     oldButtonWidth := oldButtonWidth + TButton(frm.Components[i]).Width; 

     //if a custom caption has been provided use that instead, 
     //or just leave the default caption if the custom caption is empty 
     if ToCaptions[btnCnt - 1]<>'' then 
     TButton(frm.Components[i]).Caption := ToCaptions[btnCnt - 1]; 

     //auto-size the button for the new caption 
     TButton(frm.Components[i]).Width := 
     GetTextWidth(TButton(frm.Components[i]).Caption, 
      TButton(frm.Components[i]).Font,frm.Handle) + c_BtnMargin; 

     //the first button can stay where it is. 
     //all other buttons need to slide over to the right of the one b4. 
     if (1 < btnCnt) and (0 < i) then begin 
     TButton(frm.Components[i]).Left := 
      TButton(frm.Components[i-1]).Left + 
      TButton(frm.Components[i-1]).Width + c_BtnMargin; 
     end; 

     //record the button width *after* changing the caption 
     newButtonWidth := newButtonWidth + TButton(frm.Components[i]).Width; 
    end; //if TButton 
    end; //for i 

    //whatever we changed the buttons by, widen/shrink the form accordingly 
    frm.Width := Round(frm.Width + (newButtonWidth - oldButtonWidth) + 
    (c_BtnMargin * btnCnt)); 
end; 

end. 
+0

Bueno, si está utilizando al menos Delphi 2007, crearía una función MessageDlg() completamente nueva, verificando primero la versión de Windows, utilizando las nuevas clases de diálogo en Vista, y usaría una versión modificada del MessageDlg original () Funciona de otra manera. Eso le permitiría agregar fácilmente casillas de verificación "No volver a mostrar" también. – mghie

+1

El código tal como está actualmente no se compila. Necesita reorganizar algunos de los métodos. GetTextWidth debe avanzar hasta la parte superior de la implementación y si mueve ModifiyDialog sobre el método MessageDlgCustom en la implementación, puede eliminar la declaración de la sección de interfaz. En WinXP, el último botón de los cuadros de diálogo modificados, utilizando su llamada de ejemplo, se encuentra casi en el borde del borde de la ventana. Por alguna razón, el método no recalcula correctamente el ancho del diálogo. –

+0

@Ryan - gracias, lo reorganicé para poner lo más importante en la parte superior, olvidando que rompería la compilación. He restaurado el orden original. Debería compilar ahora. Tendré que probarlo en una máquina con XP, estoy usando Vista. Esperemos que el problema que describes solo ocurra en casos extremos, de todos modos ... – JosephStyons

1

Además, asegúrese de que sus controles de 3 ª parte también llame a su DLG mensaje personalizado y no estándar de la función MessageDlg . Eso es si realmente están usando el . Es posible que los controles de terceros no utilicen el mensaje de Delphi y llamen directamente al MessageBox API. Si ese es el caso, puede terminar con inconsistencias al mostrar el mensaje cajas.

2

Como alternativa, puede utilizar la unidad de código abierto SynTaskDialog. SynTaskDialog utiliza la API TaskDialog de Windows de forma nativa en las versiones más nuevas de Windows y la emula en versiones anteriores. Incluso puede use it with FireMonkey.

Para ver un ejemplo de una función MessageDlg personalizable echa un vistazo a this answer.

Cuestiones relacionadas