Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi "Don't ask again" Messagedialog ? (https://www.delphipraxis.net/132114-dont-ask-again-messagedialog.html)

ralfiii 6. Apr 2009 13:37


"Don't ask again" Messagedialog ?
 
Hi!

Oftmals wär's ja praktisch dem Benutzer bei Warnungen/Bestätigungen die per MessageDlg erledigt werden eine "Never ask again" checkbox mitanzubieten.

Ein Standardproblem.

Bevor ich jetzt das Rad neu erfinde (bzw. programmiere): Gibt's für das Problem empfohlene Problemlösungen / fertige, halbwegs etablierte Komponenten?

Oder anders: Wo wird das Messagedialog-Fenster denn zusammengebaut? (Das ist ja meines wissens nach keine Kapselung sondern was Delphi-spezifisches, oder lieg' ich da falsch?)

Danke!
Ralf

DeddyH 6. Apr 2009 13:42

Re: "Don't ask again" Messagedialog ?
 
Ich hab da beim Zauberer etwas gefunden: http://www.dbrsoftware.de/delphi/nichtdlg.php

Luckie 6. Apr 2009 13:55

Re: "Don't ask again" Messagedialog ?
 
Meinst du sowas: http://www.michael-puff.de/Artikel/D...logAgain.shtml

gmc616 6. Apr 2009 13:56

Re: "Don't ask again" Messagedialog ?
 
Das Beispiel vom Zauberer funktioniert über die WinAPI und Registry.

Ich hatte mal das gleiche Problem, wollte aber ohne die Registry auskommen. Deshalb hab ich mir selbst etwas gebastelt.
Delphi-Quellcode:
function MyMsgBoxx (psText,psTitle : string; AShowAgainChecked : boolean = false; AIcon : Integer ) : boolean;
VAR
  AMsgDialog                 : TForm;
  ACheckBox                  : TCheckBox;
  AImg : TComponent;
  bShowAgain : boolean;
  btnOk : TControl;
  nHeigth : integer;
BEGIN
  bShowAgain := true;
  AMsgDialog := CreateMessageDialog(psText, mtWarning, [mbOk]);
  AMsgDialog.FormStyle := fsStayOnTop;
  AImg := AMsgDialog.FindComponent('Image');
  if AImg <> nil then
  begin
     // eigene Icon-Lade-Funktion
     TImage(AImg).Picture.Icon := GetIconByName(IntToStr(AIcon));
  end;

  btnOk := AMsgDialog.FindChildControl('OK');
  if btnOk <> nil then
  begin
    nHeigth := btnOk.top + btnOk.Height + 24;
  end else begin
    nHeigth := 169;
  end;

  ACheckBox := TCheckBox.Create(AMsgDialog);
  WITH AMsgDialog DO
  begin
    TRY
      Caption := psTitle;
      ClientHeight := nHeigth;
      WITH ACheckBox DO
      BEGIN
          Parent := AMsgDialog;
          Caption := 'Diesen Hinweis nicht mehr anzeigen.';
          width := 190;
          top := nHeigth - 20;
          Left := 8;
          Checked := AShowAgainChecked;
      END;

      ShowModal;

      bShowAgain := Not (ACheckBox.Checked);
    FINALLY
      ACheckBox.Free;
      Free;
    END;
  END;
  Result := bShowAgain;
end;
Das ganze ist zwar (noch) nicht der Stein des Weißen, aber für mich erfüllt es seine Zwecke.

DeddyH 6. Apr 2009 14:00

Re: "Don't ask again" Messagedialog ?
 
Registry aber nur dann, wenn Du den Dialog wieder anzeigen lassen möchtest, da Du ja dann den Wert löschen musst.

Jakob Ullmann 6. Apr 2009 15:15

Re: "Don't ask again" Messagedialog ?
 
Da finde ich das, was Luckie gepostet hat, aber kürzer. :wink:

ralfiii 6. Apr 2009 15:18

Re: "Don't ask again" Messagedialog ?
 
Zitat:

Zitat von Luckie

So ähnlich.
Tragischerweise ist die M$ MessageBoxCheck Implementierung ziemlich dämlich,
Man kann z.B: nur merken ob das Erscheinen eines Dialogs erwünscht ist, nicht aber das Ergebnis.

Eine typische Frage wäre ja:

"Wollen Sie das Programm wirklich beenden?" - OK, Cancel.
In dem Fall sollte sich der Dialog "OK" merken, Cancel nicht (sonst kann ich das Programm ja nie mehr beenden)

Oder, noch ausgefeilter: "Wollen sie vor dem beenden die Daten speichern?" (Ja, Nein, Abbrechen). Ja und nein sollte sich das Ding merken und beim nächsten Aufruf den selben Wert zurückgeben, bei Abbruch natürlich nicht.


...ich schätze das muss man noch was dazustricken.

mjustin 6. Apr 2009 15:57

Re: "Don't ask again" Messagedialog ?
 
Zitat:

Zitat von ralfiii
Oftmals wär's ja praktisch dem Benutzer bei Warnungen/Bestätigungen die per MessageDlg erledigt werden eine "Never ask again" checkbox mitanzubieten.

Ein Standardproblem.

Standardlösung gibt es in der JVCL - DSA-Dialoge

Cheers,

ralfiii 6. Apr 2009 16:00

Re: "Don't ask again" Messagedialog ?
 
Zitat:

Zitat von mjustin
Standardlösung gibt es in der JVCL - DSA-Dialoge
Cheers,

Uups.
Das kam leider zu spät.

Hier eine Lösung:

Delphi-Quellcode:
// MessageDialog with "Don't ask again" checkbox
// Based on code from [url]http://www.dbrsoftware.de/delphi/nichtdlg.php[/url]
// Discussion: [url]http://www.delphipraxis.net/post1023099.html[/url]
//
// ATT: Could return unexpected values if the list of possible results
//      was changed between versions and such an unexpected value was
//      stored in registry by an older version of the software
// Take standard window captions from Consts.pas, e.g. SMsgDlgConfirm
function DsaMessageDlg(h: THandle; Text, Caption, DsaDialogId: string;
  uType: Uint): integer;
var HL: THandle;
    Dlg: function(h: THandle; Txt, Title: PChar; dw: DWORD; nll: integer;
                  GStr: PChar): integer; stdcall;
    DSA : boolean;
const SxDsaBaseKey = '\Software\SpoonworX\DontShowAgain';
      MsDsaKey = '\Software\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain';
begin
     with TRegIniFile.Create(SxDsaBaseKey, KEY_READ or Key_Write) do
     begin
          // by holding down CTRL -> unlock!
          if GetAsyncKeyState(VK_CONTROL) and $8000<>0 then
             DeleteKey('', DsaDialogId);

          // Check if a default result is already defined
          result:=ReadInteger('', DsaDialogId, -1);
          Free;
     end;

     // Show Messagedialog
     if result=-1 then
     begin
          // Maintain dialog is shown
          //   (clean old preferences - depends only from value in
          with TRegIniFile.Create(MsDsaKey, Key_Write) do
          begin
               DeleteKey('', DsaDialogId);
               Free;
          end;

          // Use standard "hidden" dialog with checkbox
          result := maxint;
          HL := LoadLibrary('shlwapi.dll');
          if HL <> 0 then begin
            @Dlg := GetProcAddress(HL, MAKEINTRESOURCE($B9));
            if Assigned(Dlg) then
              result := Dlg(h, PChar(Text), PChar(Caption),
                uType, 0, PChar(DsaDialogId));
            FreeLibrary(HL);
          end;

          // Determine if "don't show again" checkbox was visible
          with TRegIniFile.Create(MsDsaKey, KEY_READ or Key_Write) do
          begin
               DSA:=ValueExists(DsaDialogId);
               if DSA then
                  DeleteKey('', DsaDialogId);
               Free;
          end;

          // If DSA-checkbox was checked -> store defautl result of dialog
          if DSA and (result<>IDCANCEL) then
             with TRegIniFile.Create(SxDsaBaseKey, Key_Write) do
             begin
                  WriteInteger('', DsaDialogId, result);
                  Free;
             end;
     end;
end;

xZise 6. Apr 2009 17:00

Re: "Don't ask again" Messagedialog ?
 
Hallo,

und unter Windows Vista kann man sogar den TaskDialog nehmen.

MfG
xZise

PS: Cooler Artikel :thumb:

v2afrank 14. Jul 2010 06:51

AW: "Don't ask again" Messagedialog ?
 
Ich hole den Thread jetzt mal wieder nach oben. Unter Delphi 2010 funktioniert das nämlich nicht mehr. Es wird nur der erste Buchstabe des Text und der Caption angezeigt.
Taskdialog kann ich nicht nehmen, da das Programm unter XP auch noch arbeiten soll. Hat einer eine Idee ?

uligerhardt 14. Jul 2010 08:28

AW: "Don't ask again" Messagedialog ?
 
Zitat:

Zitat von v2afrank (Beitrag 1035192)
Taskdialog kann ich nicht nehmen, da das Programm unter XP auch noch arbeiten soll. Hat einer eine Idee ?

Es gibt ja einige TaskDialog-Nachimplementationen (z.B. von JED und TMS). Die haben vermutlich auch diese DSA-Funktionalität.

v2afrank 14. Jul 2010 08:30

AW: "Don't ask again" Messagedialog ?
 
Das schon, aber die Kosten 85 bzw. 185 Euro. Das ist es mir nicht Wert.
Da bau ich mir lieber selber ein Fenster

hoika 14. Jul 2010 09:03

AW: "Don't ask again" Messagedialog ?
 
Hallo,

Zitat:

Unter Delphi 2010 funktioniert das nämlich nicht mehr. Es wird nur der erste Buchstabe des Text und der Caption angezeigt.
Könnte am Unicode liegen.
Ändere beim Bsp.-Code auf Seite 1 alles von String auf AnsiString,
und übergib auch nur einen solchen.


Heiko

uligerhardt 14. Jul 2010 09:07

AW: "Don't ask again" Messagedialog ?
 
Zitat:

Zitat von v2afrank (Beitrag 1035204)
Das schon, aber die Kosten 85 bzw. 185 Euro. Das ist es mir nicht Wert.
Da bau ich mir lieber selber ein Fenster

Ob sich das lohnt, kommt auf deinen Stundensatz an. ;-)

cookie22 14. Jul 2010 09:12

AW: "Don't ask again" Messagedialog ?
 
bau dir einen mit ner form zusammen. wo ist das problem? das dauert höchstens 5 minuten.

himitsu 14. Jul 2010 09:35

AW: "Don't ask again" Messagedialog ?
 
Haben wir nicht auch irgendwo soeinen Dialog als OpenSource in der DP rumliegen?
Dachte ich hätte sowas mal gesehn.

v2afrank 14. Jul 2010 09:38

AW: "Don't ask again" Messagedialog ?
 
Ich finde es schon schöner, wenn sich die Messagebox dem Design von Windows anpasst, was bei einem selbstgebauten Formular nicht so schön ist.

Zitat:

Zitat von hoika (Beitrag 1035208)
Hallo,

Könnte am Unicode liegen.
Ändere beim Bsp.-Code auf Seite 1 alles von String auf AnsiString,
und übergib auch nur einen solchen.
Heiko

Das ist der Grund, allerdings hat ein Umstellen von String auf Ansistring nicht funktioniert. Ich habe stattdessen die Unicodefunktion mit dem Index 191 genommen.
So funktioniert es auch mit Delphi 2010
Delphi-Quellcode:
function MessageBoxCheck; external 'shlwapi.dll' index 191;
function MessageBoxCheck(hWnd: THandle; Text: PWideChar; Title: PWideChar; dwType: DWORD; Default: Integer;
  RegVal: PChar): Integer; stdcall;

mkinzler 14. Jul 2010 10:12

AW: "Don't ask again" Messagedialog ?
 
Zitat:

Ich habe stattdessen die Unicodefunktion mit dem Index 191 genommen.
So funktioniert es auch mit Delphi 2010
Das ist auch die bessere Variante.

himitsu 14. Jul 2010 10:31

AW: "Don't ask again" Messagedialog ?
 
noch eine selbstgebastelte Version:
Delphi-Quellcode:
uses Dialogs, StdCtrls, Math;

var MessageDlgExList: TStringList;

const mbAuto = TMsgDlgBtn(Ord(High(TMsgDlgBtn)) + 1);

function MessageDlgEx(const DlgID, Msg: String; DlgType: TMsgDlgType;
  Buttons: TMsgDlgButtons; DefaultButton: TMsgDlgBtn = mbAuto): Integer;
var
  Dialog: TForm;
  i, X, Y: Integer;
  C: TWinControl;
  Query: TCheckBox;
begin
  if (DlgID <> '') and (MessageDlgExList.IndexOfName(DlgID) >= 0) then begin
    Result := StrToInt(MessageDlgExList.Values[DlgID]);
    Exit;
  end;
  if DefaultButton = mbAuto then
    if     mbOk in Buttons then DefaultButton := mbOk
    else if mbYes in Buttons then DefaultButton := mbYes
    else                         DefaultButton := mbRetry;
  Dialog := CreateMessageDialog(Msg, DlgType, Buttons, DefaultButton);
  try
    if DlgID <> '' then begin
      X := 999;
      Y := 0;
      for i := Dialog.ComponentCount - 1 downto 0 do
        if Dialog.Components[i] is TWinControl then begin
          C := TWinControl(Dialog.Components[i]);
          if C.Visible then begin
            X := Min(C.Left, X);
            Y := Max(C.Top + C.Height, Y);
          end;
        end;
      Query := TCheckBox.Create(Dialog);
      Query.Parent := Dialog;
      Query.Left := X;
      Query.Top := Dialog.ClientHeight;
      Query.Width := 100;
      Query.Caption := 'merken';
      Dialog.ClientHeight := Dialog.ClientHeight + Query.Height + (Dialog.ClientHeight - Y);
    end;
    Result := Dialog.ShowModal;
    if Query.Checked and (Result <> MB_ABORTRETRYIGNORE) then
      MessageDlgExList.Add(DlgID + MessageDlgExList.NameValueSeparator + IntToStr(Result));
  finally
    Dialog.Free;
  end;
end;

initialization
  MessageDlgExList := TStringList.Create;
  MessageDlgExList.Sorted := True;

finalization
  MessageDlgExList.Free;

end.
Diese paßt sich zumindestens an das Aussehn der Delphi-Dialoge an.

MessageDlgExList kann man bei Programmstart laden
und beim Beenden speichern (oder sofort über MessageDlgExList.OnChange speichern)

Die DlgID muß für jeden Dialog vergeben werden.

Wurde der Dialog gespeichert/gemerkt, dann wird beim nächsen Aufruf das letzte Result zurückgegeben und nichts angezeigt.

Will man einen/alle Dialoge wieder anzeigen, dann einfach die MessageDlgExList bearbeiten.

himitsu 14. Jul 2010 10:36

AW: "Don't ask again" Messagedialog ?
 
@v2afrank: bei deinem RegVal solltest du noch aufpassen ... PChar ist ja dynamisch


Aber die API würde ich besser so implementieren, dann klappts hoffentlich überall
Delphi-Quellcode:
function MessageBoxCheck(hWnd: HWND; Text, Title: PChar; dwType: LongWord;
  Default: Integer; RegVal: PChar): Integer; stdcall;
function MessageBoxCheckA(hWnd: HWND; Text, Title: PAnsiChar; dwType: LongWord;
  Default: Integer; RegVal: PAnsiChar): Integer; stdcall;
function MessageBoxCheckW(hWnd: HWND; Text, Title: PWideChar; dwType: LongWord;
  Default: Integer; RegVal: PWideChar): Integer; stdcall;

function MessageBoxCheck; external 'shlwapi.dll' index {$IF SizeOf(Char) = 1}185{$ELSE}191{$IFEND};
function MessageBoxCheckA; external 'shlwapi.dll' index 185;
function MessageBoxCheckW; external 'shlwapi.dll' index 191;
PS: http://msdn.microsoft.com/en-us/library/bb773836.aspx


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz