Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Frage zu MessageDlg (https://www.delphipraxis.net/50355-frage-zu-messagedlg.html)

BTeam 24. Jul 2005 12:30


Frage zu MessageDlg
 
Hi,
Ich habe da eine kleine Frage... In MessageDlg kann man ja mittels [mbYes, mbNo,...] usw. festlegen welche Buttons angezeigt werden.
Meine Frage ist nun wenn mein Programm das mit einer deutschen Delphi geschrieben wurde auf einen Englischen Windows ausgeführt wird...werden dann die Button Caption auch in englisch statt in deutsch angezeigt?

dahead 24. Jul 2005 13:00

Re: Frage zu MessageDlg
 
nein, sie bleiben deutsch. genauso umgekehrt.

du kannst aber hier im forum mal nach "mymessagedlg" suchen. diese funktion formatiert den button text.

SMO 24. Jul 2005 13:03

Re: Frage zu MessageDlg
 
Leider nein. Die Captions erscheinen in der Sprache deiner Delphi-Version, weil Delphi Konstanten dafür benutzt. Immerhin sind es resourcestrings, sie können also in der Exe mit einem Ressourceneditor bearbeitet werden. Aber dass sich die Beschriftung automatisch der Sprache des Betriebssystems anpasst, schafft man so nicht.

BTeam 24. Jul 2005 16:37

Re: Frage zu MessageDlg
 
Oha...danke für die Antwort.
Dann werde ich mir diese mymessagedlg Function mal ansehen oder zur Not bastel ich mir halt einen eigenen MsgDlg.

jfheins 24. Jul 2005 16:39

Re: Frage zu MessageDlg
 
Oder du probierst mal MSDN-Library durchsuchenMessageBox, imho müsste das dann entsprechend der Windowsversion anzeigen ;)

BTeam 24. Jul 2005 17:56

Re: Frage zu MessageDlg
 
Auch interessant...werde mir einfach mal beides ansehen.
Wobei MyMessageDlg schon prima Funktioniert. Da ich ja keine "Neuen" Buttons reinmachen, sondern nur die Vorhandenen entsprechend der gewählten Sprache anpassen will. Das Funktioniert recht gut mit MyMessageDlg.

Killer 2. Aug 2005 22:20

Re: Frage zu MessageDlg
 
Hy

hab grad auch noch was zu dem Thema. Entweder suche ich falsch oder ich bin zu blöd dafür. Wenn ich nach "mymessagedlg" suche, find ich nur diesen Thread. Hab als Alternative MessageBox probiert, ein Problem von mir is nun folgendes:
Code:
if MessageBox(self.Handle, 'Soll der User ' + PChar(GetSelectedUser.User) + ' wirklich gelöscht werden?','Titel',MB_ICONQUESTION or MB_YESNO) = IDYES then
    // TODO: User löschen
GetSelectedUser.User ist natürlich vom Typ String. Mit MessageDlg geht das ja auch, nur MessageBox erwartet da PAnsiChar...

Lässt sich aus folgendem Grund nicht kompilieren:
Zitat:

[Error] Unit1.pas(243): Incompatible types: 'String' and 'PAnsiChar'
Es liegt an diesem Teil:
Code:
PChar(GetSelectedUser.User)
wenn ich das entferne, gehts soweit. Nur ich möchte es trotzdem drin haben. Sollte mit PChar() ja worken normal :roll:

dahead 2. Aug 2005 23:48

Re: Frage zu MessageDlg
 
also ich poste mal das, was ich dachte bei diesem thread stand. hier der daraus entstandene code:

Delphi-Quellcode:

function MyMessageDlg(const Msg: String; DlgType: TMsgDlgType;
 Buttons: TMsgDlgButtons; Captions: Array of String): Integer;
var
  aMsgDlg: TForm;
  I: Integer;
  DlgButton: TButton;
  CaptionIndex: Integer;
begin
  aMsgDlg := CreateMessageDialog(Msg, DlgType, Buttons);
  CaptionIndex := 0;

  for I := 0 to aMsgDlg.ComponentCount - 1 do
  begin
   if (aMsgDlg.Components[i] is TButton) then
   begin
    DlgButton := TButton(aMsgDlg.Components[I]);
    if CaptionIndex > High(Captions) then
     Break; // Keine weiteren Buttons da

    DlgButton.Caption := Captions[CaptionIndex]; //<- ändern

    // Todo: MyMessageDlg: Problem bei zu langen Captions wird die
    // Buttonbreite nicht geändert.
    //DlgButton.Width  :=
    //DlgButton.Left   :=

    Inc(CaptionIndex);
   end;
  end;

 Result := aMsgDlg.ShowModal;
end;

BTeam 2. Aug 2005 23:52

Re: Frage zu MessageDlg
 
MyMessageDlg ist eine Funktion...weis leider auch nicht mehr genau wo ich sie dann gefunden habe darum poste ich sie einfach mal mit rein.
Die dlg_xxx Variablen enthalten hier in meinem Fall einen String in der entsprechenden Sprache.
Das Prinzip der Funktion sollte aber klar sein.

Delphi-Quellcode:
function MyMessageDlg(const Msg: String; AType: TMsgDlgType; AButtons:TMsgDlgButtons; HelpCtx: Longint): Word;
var
  Comp: TComponent;
  k: Integer;
begin
  with CreateMessageDialog(Msg, AType, AButtons) do begin
    for k := 0 to ComponentCount - 1 do
    begin
      Comp := Components[k];
      if Comp is TButton then with TButton(Comp) do
      begin
        if UpperCase(Name) = 'YES'   then Caption := dlg_yes;
        if UpperCase(Name) = 'NO'    then Caption := dlg_no;
        if UpperCase(Name) = 'OK'    then Caption := dlg_ok;
        if UpperCase(Name) = 'CANCEL' then Caption := dlg_cancel;
      end;
    end;
    Result := ShowModal;
  end;
end; {Popov}

dahead 2. Aug 2005 23:52

Re: Frage zu MessageDlg
 
so sollte es mit deinem code gehen:

delphi-code:

@('Soll der User ' + PChar('Test') + ' wirklich gelöscht werden?')[1] ...

also einfach ein @ vor den string, sowie ein [1] danach. (habe 'test' eingefügt, da ich mit deiner variablen nichts anfangen konnte).

ps: gehen delphi tags sowie bold-tags egtl. nicht gleichzeitg?

BlackJack 3. Aug 2005 00:34

Re: Frage zu MessageDlg
 
Zitat:

Zitat von Killer
hab grad auch noch was zu dem Thema. Entweder suche ich falsch oder ich bin zu blöd dafür. Wenn ich nach "mymessagedlg" suche, find ich nur diesen Thread. Hab als Alternative MessageBox probiert, ein Problem von mir is nun folgendes:
Code:
if MessageBox(self.Handle, 'Soll der User ' + PChar(GetSelectedUser.User) + ' wirklich gelöscht werden?','Titel',MB_ICONQUESTION or MB_YESNO) = IDYES then
    // TODO: User löschen
GetSelectedUser.User ist natürlich vom Typ String. Mit MessageDlg geht das ja auch, nur MessageBox erwartet da PAnsiChar...

Lässt sich aus folgendem Grund nicht kompilieren:
Zitat:

[Error] Unit1.pas(243): Incompatible types: 'String' and 'PAnsiChar'
Es liegt an diesem Teil:
Code:
PChar(GetSelectedUser.User)
wenn ich das entferne, gehts soweit. Nur ich möchte es trotzdem drin haben. Sollte mit PChar() ja worken normal :roll:

ich würde sagen du musst einfach den PChar-typecast um den gesamten string machen und nicht nur um diesen User-record, also so:
Delphi-Quellcode:
MessageBox(self.Handle, PChar('Soll der User ' + GetSelectedUser.User + ' wirklich gelöscht werden?'),'Titel',MB_ICONQUESTION or MB_YESNO)
man kann nicht PChars und strings einfach so mit einem + aneinanderreihen, da es nunmal verschiedene typen sind (im grunde sind PChars nur pointer, allerdings benutzt Delphi da ein bisschen CompilerMagic)

(eventuell muss noch "Titel" auf PChar getypecastet werden, ich weiss jetzt nicht was da für ein parameter erwartet wird und ob delphi gegebenenfalls automatisch typecastet.)

edit:
ich hab mal nachgeschaut, bei meinem Delphi erwartet die Function MessageBox eh keine PChars, sondern direkt strings als parameter, von daher kannst du einfach komplett mit strings arbeiten und dir den typecast auf PChar sparen.

edit2:
Zitat:

Zitat von dahead
@('Soll der User ' + PChar('Test') + ' wirklich gelöscht werden?')[1] ...

krass, so eine syntax ist mir noch nie untergekommen und ich hätte auch nie erwartet dass das funktioniert (vor allem weil auch strings und PChars gemischt werden)... naja man lehrnt nie aus.
ach ja, wo im speicher steht dann überhaupt dieser string?

dahead 3. Aug 2005 01:06

Re: Frage zu MessageDlg
 
@blackjack:

Zitat:

krass, so eine syntax ist mir noch nie untergekommen und ich hätte auch nie erwartet dass das funktioniert (vor allem weil auch strings und PChars gemischt werden)... naja man lehrnt nie aus.
nicht dass du denkst ich würde das selbst so lösen. ich wollte nur schnell testen, ob das problem in oder außerhalb der klammer liegt. daher mein vorschlag mit @...[1].

da ich immer noch nicht weiß, welchen typ die besagte variable hat, hab ich sie einfach durch 'test' ersetzt.

edit: ich muss allerdings zu meiner schande gestehen, dass ich das projekt nicht gestartet habe, also nicht weiß wie die message dann dadurch evtl. zerstückelt wurde.

da du schreibst es funktioniert, wird der string korrekt angezeigt?

Luckie 3. Aug 2005 01:40

Re: Frage zu MessageDlg
 
Zitat:

Zitat von dahead
Code:
[b]@[/b]('Soll der User ' + PChar('Test') + ' wirklich gelöscht werden?')[b][1][/b] ...

:roll:
Wie wäre es mit:
Delphi-Quellcode:
var
  sUser: String;
begin
...
PChar('Soll der User ' + sUser + ' wirklich gelöscht werden?')

Olli 3. Aug 2005 09:55

Re: Frage zu MessageDlg
 
Zitat:

Zitat von dahead
Code:
[b]@[/b]('Soll der User ' + PChar('Test') + ' wirklich gelöscht werden?')[b][1][/b] ...

Bitte den PChar-Cast weglassen! -> Nein, den braucht's bei dieser Syntax, wenn der String mehr als ein terminierendes #0 enthält!

Zitat:

Zitat von Luckie
Delphi-Quellcode:
PChar('Soll der User ' + sUser + ' wirklich gelöscht werden?')

Auch du, Luckie?

tss tss tss ....

Luckie 3. Aug 2005 10:03

Re: Frage zu MessageDlg
 
Liste der Anhänge anzeigen (Anzahl: 1)
Und wie dann? Siehe Anhang.

Olli 3. Aug 2005 12:03

Re: Frage zu MessageDlg
 
Zitat:

Zitat von Luckie
Und wie dann?

So wie dahead es vormacht.

Der Punkt ist folgender. Die Syntax mit dem PChar-Cast mag funktionieren (tut sie ja bekanntlich auch), sie mag sogar schneller sein (zumindest kann sie das unter bestimmten Umständen), aber @String[1] ist eine viel klarere Syntax.
Hier wird mit Compiler-Magic gespielt, ohne daß die meisten Leute wissen, was unter ihren Füßen vorgeht! Obwohl unnötig, entscheidet der Compiler über weitere Checks. Wie wir wissen, besitzen Strings einen Referenz- und einen Längenzähler.
Delphi-Quellcode:
type
      StrRec = record
        allocSiz: Longint;
        refCnt:  Longint;
        length:  Longint;
      end;
Da soviel am AnsiString und WideString und String "managed" abläuft, kann man fast sagen, daß es sich verhält wie bei einer Klasse in C++. Dort kann man Operatoren auch überladen. In Delphi geht dies nicht, also hat der Compiler eine explizite Unterstützung für Strings eingebaut. Die kann man ihm nehmen, indem man die System-Unit mal ein wenig ausmistet - aber das gehört hier nicht her.

Delphis Strings sind immer nullterminiert, sie sind also schonmal prinzipiell kompatibel mit PAnsiChar/PWideChar. Außerdem ist im Binärcode immer der Zeiger auf den Stringpuffer das Element, auf welches verwiesen wird. Die Offsets des o.g. Records werden also über negative Werte erreicht. Eigentlich ist also ein String in Delphi der Record von oben plus Zeiger auf den Puffer.

Und weil es so schön ist, habe ich mal folgende zwei Codeschnipsel in Delphi und im Disassembler verglichen:
Code:
var
  StringVar: string;
  dwSize: DWORD;
begin
  dwSize := MAX_PATH;
  SetLength(StringVar, MAX_PATH + 1);
  GetComputerName([color=red]@StringVar[1][/color], dwSize);
  Writeln(StringVar);
  Readln;
end.
Code:
var
  StringVar: string;
  dwSize: DWORD;
begin
  dwSize := MAX_PATH;
  SetLength(StringVar, MAX_PATH + 1);
  GetComputerName([color=red]PChar(StringVar)[/color], dwSize);
  Writeln(StringVar);
  Readln;
end.
Wie man im folgenden Code sieht, wird für jeden Typecast eine Funktion reingepappt. Wenn man sich die Funktionen anschaut, ist sogar die vom PChar-Cast (oft) schneller.
Code:
CODE:00408312                 mov    ds:dwSize, 260
CODE:0040831C                mov    eax, offset StringVar
CODE:00408321                 mov    edx, 261
CODE:00408326                 call   SetLength
CODE:0040832B                push   offset dwSize
CODE:00408330                 mov    eax, offset StringVar
[color=red]CODE:00408335                 call   @System@UniqueString$qqrr17System@AnsiString[/color]
CODE:0040833A                push   eax
CODE:0040833B                call   GetComputerNameA
CODE:00408340                 mov    eax, ds:ExceptionHandler
CODE:00408345                 mov    edx, ds:StringVar
CODE:0040834B                call   sub_4034A0
CODE:00408350                 call   _WRITELN
Code:
CODE:004082DE                mov    ds:dwSize, 260
CODE:004082E8                 mov    eax, offset StringVar
CODE:004082ED                mov    edx, 261
CODE:004082F2                 call   SetLength
CODE:004082F7                 push   offset dwSize
CODE:004082FC                mov    eax, ds:StringVar
[color=red]CODE:00408301                 call   @System@@LStrToPChar$qqrv[/color]
CODE:00408306                 push   eax
CODE:00408307                 call   GetComputerNameA
CODE:0040830C                mov    eax, ds:off_4092DC
CODE:00408311                 mov    edx, ds:StringVar
CODE:00408317                 call   sub_40346C
CODE:0040831C                call   _WRITELN
Was mich denn dann doch verwunderte, war daß auch bei der @String[1]-Syntax überhaupt eine extra Funktion aufgerufen wird. Diese wird benutzt um dem String, so er denn auf den Puffer eines anderen zugewiesenen Strings zeigt, eine eigene Kopie des eigentlichen Strings (i.e. Inhalt) zu verschaffen. Man muß sich also dazu klarmachen, daß ein String auch auf den Puffer eines ursprünglich anderen Strings zeigen kann. Bei einer Zuweisung wird dann der Zeiger zugewiesen, aber nicht der Puffer selbst kopiert. Das macht die Delphistrings natürlich äußerst effizient. Aber in unserem Fall verschafft es der klareren Syntax einen kleinen Nachteil, weil nämlich dieser Check erst dazwischengeschoben wird. Dieser Check wird offenbar forciert, wenn ich keinen Cast mache, sondern einen Pointer auf meinen String übergebe.

Fazit: Ich bleibe bei meiner klareren Syntax. Ihr dürft weiter PChar-Casts benutzen ... und dank obiger Erkenntnis sage ich auch nix böses mehr darüber ;) ...

BTW: Vielleicht solltet ihr diesen Beitrag in die Codelib oder so schieben? Also splitten.

Killer 3. Aug 2005 12:31

Re: Frage zu MessageDlg
 
Hy

Also funktionieren tun ja beide Varianten, über den PChar Cast und über dieses @(String)[1].
Nur komisch, warum die Funktion MessageBox da ein PAnsiChar erwartet und nicht etwa einen String.

Danke für eure Hilfe!! :-D

Übrigens guter Vergleich Olli! :)

dahead 3. Aug 2005 12:49

Re: Frage zu MessageDlg
 
@olli: ja, wirklich interessanter vergleich. danke dass du dir solche mühe gemacht hast.

@killer:

Zitat:

Nur komisch, warum die Funktion MessageBox da ein PAnsiChar erwartet und nicht etwa einen String.
messagebox ist ein api befehl. die erwarten immer pchars oder pansichars.

auszug aus windows.pas
Delphi-Quellcode:
function MessageBox; external user32 name 'MessageBoxA';
function MessageBoxA; external user32 name 'MessageBoxA';
function MessageBoxW; external user32 name 'MessageBoxW';
auszug aus delphi hilfe:
Zitat:

public function MessageBox(const Text: PAnsiChar, const Caption: PAnsiChar, Flags: Integer): Integer;
d.h. du musst keine funktion schreiben. deine funktionen sind PChar sowie @String[1].
(edit: ich sehe gerade, du hast deinen beitrag editiert und diesen wunsch zurückgenommen).

man möge mich korrigieren falls ich falsch liege.

Motzi 3. Aug 2005 13:10

Re: Frage zu MessageDlg
 
@Olli: ich weiß, dass du weißt, dass ich ein String-Tutorial geschrieben hab (du hast ja schon öfters darauf verwiesen), aber hast du auch selbst schonmal reingeguckt? Das was du da oben geschrieben hast steht nämlich eigentlich schon alles drinnen.. ;)

@rest: wen es interessiert, das Tutorial findet man auf www.manuel-poeter.de

PS: es gibt noch eine weitere Möglichkeit, man castet den String einfach auf Pointer, dann wird gar keine Zwischenfunktion aufgerufen.. ;)

Olli 3. Aug 2005 14:03

Re: Frage zu MessageDlg
 
Zitat:

Zitat von Motzi
@Olli: ich weiß, dass du weißt, dass ich ein String-Tutorial geschrieben hab (du hast ja schon öfters darauf verwiesen), aber hast du auch selbst schonmal reingeguckt? Das was du da oben geschrieben hast steht nämlich eigentlich schon alles drinnen.. ;)

Nun gut, du weißt ich bin Pedant. Aber du hast recht, es ist ja schon enthalten.

Übrigens wäre das wohl richtiger ;)
Delphi-Quellcode:
type
  PStringInfo = ^TStringInfo;
  TStringInfo = packed record
    Rec : StrRec;
    pStringAddr : Pointer;
  end;
Die Rolle des ersten Elementes von StrRec scheint mir durchaus relevant, wenn wir zB Zuweisungen betrachten.

Im Tut steht ja ganz am Ende:
Womit auch klar sein sollte, mit welcher Typecast-Methode man einen String an eine API Funktion (die Daten in diesen String schreibt) übergeben sollte, wenn man sich nicht sicher ist, dass dieser String ein „Unikat“ (mit einem Referenzzähler von 1) ist.
Darf man fragen, welche Methode dies denn nach Ansicht des großen Meisters ist?! :mrgreen:

Motzi 3. Aug 2005 21:48

Re: Frage zu MessageDlg
 
Zitat:

Zitat von Olli
Übrigens wäre das wohl richtiger ;)
Delphi-Quellcode:
type
  PStringInfo = ^TStringInfo;
  TStringInfo = packed record
    Rec : StrRec;
    pStringAddr : Pointer;
  end;
Die Rolle des ersten Elementes von StrRec scheint mir durchaus relevant, wenn wir zB Zuweisungen betrachten.

Ok du Pedant! ;) Wenn ich das Tut mal überarbeite werd ich das berücksichtigen und korrigieren!

Zitat:

Im Tut steht ja ganz am Ende:
Womit auch klar sein sollte, mit welcher Typecast-Methode man einen String an eine API Funktion (die Daten in diesen String schreibt) übergeben sollte, wenn man sich nicht sicher ist, dass dieser String ein „Unikat“ (mit einem Referenzzähler von 1) ist.
Darf man fragen, welche Methode dies denn nach Ansicht des großen Meisters ist?! :mrgreen:
Naja, der wichtigste Teil in diesem Satz ist:
Zitat:

[..]wenn man sich nicht sicher ist, dass dieser String ein „Unikat“ (mit einem Referenzzähler von 1) ist.
Nur eine der 3 Cast-Methoden stellt sicher, dass der übergebene Pointer auf ein Unikat zeigt und das ist @String[1], da bei dieser Methode intern UniqueString aufgerufen wird. Bei den beiden anderen Methoden werden ja auch gleichzeitig alle anderen Strings verändert, die ebenfalls den übergebenen String referenzieren. Wobei das ja nur wichtig ist, wenn die API Daten im String ablegt und ihn dadurch verändert.

Gruß, Motzi

Olli 3. Aug 2005 22:09

Re: Frage zu MessageDlg
 
Zitat:

Zitat von Motzi
Ok du Pedant! ;) Wenn ich das Tut mal überarbeite werd ich das berücksichtigen und korrigieren!

Da du es ja eh angeboten hast, könnte ich dir dann gern auch helfen (im Rahmen von de-delphi).

Zitat:

Zitat von Motzi
Nur eine der 3 Cast-Methoden stellt sicher, dass der übergebene Pointer auf ein Unikat zeigt und das ist @String[1], da bei dieser Methode intern UniqueString aufgerufen wird.

Gut, wollte nur wissen, ob wir es gleich sehen. IMO ist die Formulierung eindeutig, aber sie könnte ruhig auch noch die Auflösung enthalten ;)

Motzi 3. Aug 2005 22:26

Re: Frage zu MessageDlg
 
Zitat:

Zitat von Olli
Zitat:

Zitat von Motzi
Ok du Pedant! ;) Wenn ich das Tut mal überarbeite werd ich das berücksichtigen und korrigieren!

Da du es ja eh angeboten hast, könnte ich dir dann gern auch helfen (im Rahmen von de-delphi).

Stimmt, können es dann auch gemeinsam machen...

Zitat:

Zitat:

Zitat von Motzi
Nur eine der 3 Cast-Methoden stellt sicher, dass der übergebene Pointer auf ein Unikat zeigt und das ist @String[1], da bei dieser Methode intern UniqueString aufgerufen wird.

Gut, wollte nur wissen, ob wir es gleich sehen. IMO ist die Formulierung eindeutig, aber sie könnte ruhig auch noch die Auflösung enthalten ;)
Ts.. du bist ja wirkliche pingelig..! ;) Hab das eigentlich absichtlich so formuliert, damit der Leser auch ein bisschen mitdenken muss (wofür heutzutage ja einige zu faul sind)! :mrgreen:


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:10 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