Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   Android procedure auf ShowModal warten (https://www.delphipraxis.net/186031-android-procedure-auf-showmodal-warten.html)

NickD 29. Jul 2015 08:21

Android procedure auf ShowModal warten
 
Hi Leute,
ich habe eine Frage zu ShowModal auf Android. Wie verwende ich es wenn ich auf eine Benutzereingabe warten möchte? Wenn ich ein Dialog in einer Procedure aufrufe, wird nicht darauf gewartet bis das Modale Fenster wieder geschlossen wurde.
Ich habe mal eine Beispiel Procedure geschrieben. In der function GetRot() sollte solange gewartet werden, bis sich das Modale Fenster wieder schließt und einen Rückgabewert hat, da sonst immer ein leerer String übergeben wird.
Wie löst man das am Besten?

Delphi-Quellcode:
procedure TfrmMain.CreateFarbe();
var
  Rot, Gruen, Blau: String;
begin
  // Buttonindex holen
  Index := (Sender as TButton).Tag;

  Rot := '';
  Gruen := '';
  Blau := '';
  l := Length('RGB');


  for i := 1 to l do
  begin
    ch := Copy('RGB', i,i);
   
    if ch = 'R' then
    begin
      Rot := GetRot;
      if Rot = '' then
        Exit;
    end
    else if ch = 'G' then
    begin
      Gruen := GetGruen;
      if Gruen = '' then
        Exit;
    end
    else if ch = 'B' then
    begin
      Blau := GetBlau;
      if Blau = '' then
        Exit;
    end;
  end;
  FarbeZusammenstellen(Rot, Gruen, Blau)   
end;

function TfrmMain.GetRot: String;
var
  dlgRot: TfrmFarbauswahl;
  sRot: String;
begin
  dlgRot := TfrmFarbauswahl.Create(nil);
  dlgRot.ShowModal(
  procedure(ModalResult: TModalResult)
  begin
    if ModalResult = mrOk then
    begin
      sRot := dlgRot.lbRot.Items[dlgRot.lbRot.ItemIndex];
    end;
    if ModalResult = mrCancel then
    begin
      sRot := '';
    end;
    dlgRot.Close;
  end
  );
  Result := sRot;
end;

Mavarik 29. Jul 2015 09:52

AW: Android procedure auf ShowModal warten
 
Unter Android ist ein ShowModal ein "Don't do"...

Mavarik

Sir Rufo 29. Jul 2015 10:04

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von Mavarik (Beitrag 1310094)
Unter Android ist ein ShowModal ein "Don't do"...

Mavarik

Du meinst sicher ein blockierendes ShowModal ;)

NickD 29. Jul 2015 10:07

AW: Android procedure auf ShowModal warten
 
Ja das habe ich mir schon gedacht.. Gibt es andere Möglichkeiten in einer procedure auf eine Benutzereingabe aus einem anderen Formular zu warten?

Sir Rufo 29. Jul 2015 10:11

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von NickD (Beitrag 1310098)
Ja das habe ich mir schon gedacht.. Gibt es andere Möglichkeiten in einer procedure auf eine Benutzereingabe aus einem anderen Formular zu warten?

Du musst nicht warten, das ist der Trick. Du gibst einen Callback mit, der ausgeführt wird, wenn der Dialog beendet wurde.

Mavarik 29. Jul 2015 11:03

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1310097)
Zitat:

Zitat von Mavarik (Beitrag 1310094)
Unter Android ist ein ShowModal ein "Don't do"...

Mavarik

Du meinst sicher ein blockierendes ShowModal ;)

Ja wie der Name schon sagt...

Zitat:

Zitat von EMBT
Use ShowModal to show a form as a modal form. A modal form is one where the application can't continue to run until the form is closed...

:twisted:

greenmile 29. Jul 2015 11:12

AW: Android procedure auf ShowModal warten
 
Ich persönlich halte nichts von den Callbacks nur für Unterformulare oder Messageboxen, ist mir einfach zu aufwendig.
Du kannst eine globale Variable definieren die von der Unterform gefüllt wird. Das Hauptformular muss nun einfach nur solange warten, bis die Variable gefüllt ist. Beispiel:

Code:
var MsgDlgResult: Integer;

 function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
 begin
   MsgDlgResult := -1;
   FMX.Dialogs.MessageDlg(Msg, DlgType, Buttons, HelpCtx,
             procedure(const AResult: TModalResult)
             begin
               MsgDlgResult:= AResult;
             end
           );
   while MsgDlgResult<0 do Delay(10);
   Result := MsgDlgResult;
 end;

Sir Rufo 29. Jul 2015 11:13

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von Mavarik (Beitrag 1310117)
Zitat:

Zitat von EMBT
Use ShowModal to show a form as a modal form. A modal form is one where the application can't continue to run until the form is closed...

:twisted:

Ich behaupte jetzt mal steif und fest, dass diese Aussage total falsch ist. Meine Anwendung lief weiter (diese modale Form gehört ja auch zu meiner Anwendung).

Richtig ist, dass die Methode/Prozedur, die dieses ShowModal aufruft, erst dann weiter läuft, wenn diese modale Form geschlossen wurde. Die Anwendung selber läuft einwandfrei weiter.

@greenmile

Bitte nicht ... es gibt einen guten Grund, warum die modalen Formulare auf den Mobile Devices eben nicht mehr blockierend sind.

Mavarik 29. Jul 2015 11:26

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von greenmile (Beitrag 1310119)

Code:
   while MsgDlgResult<0 do Delay(10);

Du hast einen Kommentar vergessen..

Delphi-Quellcode:
   while MsgDlgResult<0 do Delay(10); // Töte den Akku
:stupid:

Spass bei Seite... Bitte nicht.. Es gibt bessere Wege

Das war mal ein Post... Als XE6 raus gekommen ist, oder?
Ich hatte das auch so "abgetippt"

[EDIT] Habs gefunden...
Original Post war:

Delphi-Quellcode:
function MyMessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
{$IFDEF ANDROID}
var
  MsgDlgResult : Integer;
{$ENDIF}
begin
  {$IFDEF ANDROID}
  MsgDlgResult := -1;

  FMX.Dialogs.MessageDlg(Msg, DlgType, Buttons, HelpCtx,
    procedure(const AResult: TModalResult)
      begin
        MsgDlgResult:= AResult;
      end);

  while MsgDlgResult<0 do
    begin
      Application.Processmessages; // Makes Android Happy...
      Sleep(10);
    end;

    Result := MsgDlgResult;
  {$ELSE}
  Result := FMX.Dialogs.MessageDlg(Msg, DlgType, Buttons, HelpCtx);
  {$ENDIF}
end;

bra 29. Jul 2015 11:57

AW: Android procedure auf ShowModal warten
 
Application.Processmessages ist eine ganz schlechte Idee unter Android/iOS...

Sir Rufo 29. Jul 2015 12:17

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von bra (Beitrag 1310131)
Application.Processmessages ist eine ganz schlechte Idee unter Android/iOS...

Wieso das denn?

Dieses
Delphi-Quellcode:
Application.ProcessMessages
beim
Delphi-Quellcode:
ShowModal
ist extra für die Mobile Plattformen herausgenommen worden. Da hat sich doch bestimmt keiner etwas bei gedacht. Das ist nur um alle zu ärgern. :mrgreen:

NickD 29. Jul 2015 15:36

AW: Android procedure auf ShowModal warten
 
Ich habe gerade das Gefühl in dieser Situation gibt es kein "Richtig", kann das sein? :)
@SirRufo: Würde mich über ein bisschen Quellcode bezogen auf mein Beispiel freuen, so ganz komme ich mit den Callbacks nicht klar :?


@Mavarik: Wenn ich es so versuche hängt sich die komplette App auf..

bra 31. Jul 2015 09:02

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1310135)
Zitat:

Zitat von bra (Beitrag 1310131)
Application.Processmessages ist eine ganz schlechte Idee unter Android/iOS...

Wieso das denn?

Dieses
Delphi-Quellcode:
Application.ProcessMessages
beim
Delphi-Quellcode:
ShowModal
ist extra für die Mobile Plattformen herausgenommen worden. Da hat sich doch bestimmt keiner etwas bei gedacht. Das ist nur um alle zu ärgern. :mrgreen:

Keine Ahnung, ob das jetzt ironisch gemeint war oder ich es einfach nicht verstehe...

In unserer App haben die Application.ProcessMessages jedenfalls zu massiven Problemen geführt (besonders im Zusammenhang mit Threads). Inzwischen haben wir alle bis auf eine Stelle eliminieren können und seitdem damit keine Probleme mehr. Ist ja nicht so, dass es sonst nicht schon genug Stolpersteine gäbe ^^

jaenicke 31. Jul 2015 10:52

AW: Android procedure auf ShowModal warten
 
Um zur Ausgangsfrage zurückzukehren:
Man macht das so, dass man auf die Events des zweiten Formulars reagiert und gar nicht wartet.

Sprich der Ablauf ist so:
  • Zeige zweites Formular an (normales Show)
  • Im zweiten Formular löse ein Event aus, wenn z.B. eine Farbe ausgewählt wurde
  • Im ersten Formular reagiere auf die Änderung der Farbe, z.B. indem etwas neu gezeichnet werden muss
  • Wenn das zweite Formular geschlossen wird, wird wieder das erste Fenster aktiv
Dann muss niemand irgendwo warten.

greenmile 31. Jul 2015 11:14

AW: Android procedure auf ShowModal warten
 
Da macht es ja vielleicht Sinn. Aber was ist mit einer Messagebox wie "Möchten Sie beenden"? Extra Callback für jede erdenkliche Messagebox, Inputquery und co ist doch wirklich Overkill, oder?

jaenicke 31. Jul 2015 12:56

AW: Android procedure auf ShowModal warten
 
Dafür aber sauber...

Und wenn man von Anfang an so denkt, ist das auch überhaupt kein Problem...

Problematisch ist nur die Umstellung von altem Code.

bra 31. Jul 2015 12:56

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von greenmile (Beitrag 1310494)
Da macht es ja vielleicht Sinn. Aber was ist mit einer Messagebox wie "Möchten Sie beenden"? Extra Callback für jede erdenkliche Messagebox, Inputquery und co ist doch wirklich Overkill, oder?

Für MessageBoxes kann man doch eine anonyme Procedure übergeben, wo man die Ereignisbehandlung macht.

bra 31. Jul 2015 13:01

AW: Android procedure auf ShowModal warten
 
Wir haben uns eine eigene Unit für Standard-MessageBoxes erstellt, läuft mit Windows, iOS und Android:

Code:
unit uMessageDialogs;

interface

uses
  System.UITypes, System.SysUtils, System.Types, System.Generics.Defaults,
  FMX.Dialogs;

type
  TDialogButtons = (dbOk, dbOkCancel, dbYesNo);

  TMessageDialogs = class
  private
    class procedure PlatformDialog(const AMessage: String; const ADialogType: TMsgDlgType; const ADialogButtons: TDialogButtons; const AProcedure: TInputCloseDialogProc);
  public
    class procedure Info(const AMessage: String);
    class procedure Warn(const AMessage: String);
    class procedure Error(const AMessage: String);
    class procedure ConfirmYesNo(const AMessage: String; const ADialogType: TMsgDlgType; const AProcedureOnYes: TProc; const AProcedureOnNo: TProc = nil);
    class procedure ConfirmOkCancel(const AMessage: String; const ADialogType: TMsgDlgType; const AProcedureOnOk: TProc; const AProcedureOnCancel: TProc = nil);
    class procedure Custom(const AMessage: String; const ADialogType: TMsgDlgType; const ADialogButtons: TDialogButtons; const AProcedure: TInputCloseDialogProc);
  end;

implementation

uses
{$IFDEF MSWINDOWS}
  Windows, FMX.Platform.Win,
{$ENDIF}
  fRISApp, uFormSupport, uSupport, uConsts;

class procedure TMessageDialogs.PlatformDialog(const AMessage: String; const ADialogType: TMsgDlgType; const ADialogButtons: TDialogButtons; const AProcedure: TInputCloseDialogProc);
{$IFDEF MSWINDOWS}
var
  uType: Cardinal;
  caption: String;
  res: Integer;
begin
  // Dialoge werden sonst unter Windows nicht Modal angezeigt, lassen sich also in den Hintergrund legen

  uType := MB_OK;
  case ADialogButtons of
    dbOk:      uType := MB_OK;
    dbOkCancel: uType := MB_OKCANCEL;
    dbYesNo:   uType := MB_YESNO;
  end;
  uType := uType or MB_TASKMODAL;

  case ADialogType of
    TMsgDlgType.mtWarning:
      begin
        caption := 'Warnung';
        uType := uType or MB_ICONWARNING;
      end;
    TMsgDlgType.mtError:
      begin
        caption := 'Fehler';
        uType := uType or MB_ICONERROR;
      end;
    TMsgDlgType.mtInformation:
      begin
        caption := 'Information';
        uType := uType or MB_ICONINFORMATION;
      end;
    TMsgDlgType.mtConfirmation:
      begin
        caption := 'Bestätigung';
        uType := uType or MB_ICONQUESTION;
      end;
    else
      Assert(True);
  end;

  if GetMainForm = nil then
    res := Windows.MessageBox(0, PWideChar(AMessage), PWideChar(caption), uType)
  else
    res := Windows.MessageBox(FMX.Platform.Win.WindowHandleToPlatform(GetMainForm.Handle).Wnd, PWideChar(AMessage), PWideChar(caption), uType);
  if Assigned(AProcedure) then
    AProcedure(res);
end;
{$ELSE}
var
  dlgButtons: TMsgDlgButtons;
begin
  case ADialogButtons of
    dbOk:      dlgButtons := [TMsgDlgBtn.mbOK];
    dbOkCancel: dlgButtons := [TMsgDlgBtn.mbOK, TMsgDlgBtn.mbCancel];
    dbYesNo:   dlgButtons := [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo];
  end;
  FMX.Dialogs.MessageDlg(AMessage, ADialogType, dlgButtons, 0, AProcedure);
end;
{$ENDIF}

class procedure TMessageDialogs.Info(const AMessage: String);
begin
  PlatformDialog(AMessage, TMsgDlgType.mtInformation, dbOk, nil);
end;

class procedure TMessageDialogs.Warn(const AMessage: String);
begin
  PlatformDialog(AMessage, TMsgDlgType.mtWarning, dbOk, nil);
end;

class procedure TMessageDialogs.Error(const AMessage: String);
begin
  PlatformDialog(AMessage, TMsgDlgType.mtError, dbOk, nil);
end;

class procedure TMessageDialogs.Custom(const AMessage: String; const ADialogType: TMsgDlgType; const ADialogButtons: TDialogButtons; const AProcedure: TInputCloseDialogProc);
begin
  PlatformDialog(AMessage, ADialogType, ADialogButtons, AProcedure);
end;

class procedure TMessageDialogs.ConfirmOkCancel(const AMessage: String; const ADialogType: TMsgDlgType; const AProcedureOnOk, AProcedureOnCancel: TProc);
begin
  PlatformDialog(AMessage, ADialogType, dbOkCancel,
    procedure(const AResult: TModalResult)
    begin
      if GetMainForm <> nil then
        GetMainForm.Status(Format('Dialog-Result: %d, Dialog: %s', [AResult, AMessage]), TStatusType.stDebug);
      if AResult = mrOK then begin
        if Assigned(AProcedureOnOK) then
          AProcedureOnOK;
      end
      // Alternativ-Prozedur wird immer ausgeführt, wenn vorhanden.
      // Damit wird ein Problem unter Android behoben, wo sich Dialoge durch Klicken außerhalb abbrechen lassen
      else if Assigned(AProcedureOnCancel) then
        AProcedureOnCancel;
    end
  );
end;

class procedure TMessageDialogs.ConfirmYesNo(const AMessage: String; const ADialogType: TMsgDlgType; const AProcedureOnYes: TProc; const AProcedureOnNo: TProc);
begin
  PlatformDialog(AMessage, ADialogType, dbYesNo,
    procedure(const AResult: TModalResult)
    begin
      if GetMainForm <> nil then
        GetMainForm.Status(Format('Dialog-Result: %d, Dialog: %s', [AResult, AMessage]), TStatusType.stDebug);
      if AResult = mrYes then begin
        if Assigned(AProcedureOnYes) then
          AProcedureOnYes;
      end
      // Alternativ-Prozedur wird immer ausgeführt, wenn vorhanden
      // Damit wird ein Problem unter Android behoben, wo sich Dialoge durch Klicken außerhalb abbrechen lassen
      else if Assigned(AProcedureOnNo) then
        AProcedureOnNo;
    end
  );
end;

end.

NickD 31. Jul 2015 23:12

AW: Android procedure auf ShowModal warten
 
Zitat:

Zitat von jaenicke (Beitrag 1310493)
Um zur Ausgangsfrage zurückzukehren:
Man macht das so, dass man auf die Events des zweiten Formulars reagiert und gar nicht wartet.

Sprich der Ablauf ist so:
  • Zeige zweites Formular an (normales Show)
  • Im zweiten Formular löse ein Event aus, wenn z.B. eine Farbe ausgewählt wurde
  • Im ersten Formular reagiere auf die Änderung der Farbe, z.B. indem etwas neu gezeichnet werden muss
  • Wenn das zweite Formular geschlossen wird, wird wieder das erste Fenster aktiv
Dann muss niemand irgendwo warten.

So würde man natürlich vorgehen. Geht man aber mal davon aus, das ein neues Formular in einer Prozedur angezeigt werden muss und nach der Benutzereingabe diese Prozedur fotgesetzt werden muss, gibt es keine Lösung in der mobilen Entwicklung. Habe ich das richtig verstanden?

jaenicke 31. Jul 2015 23:25

AW: Android procedure auf ShowModal warten
 
Keine gute, weil das unter Android nicht so gemacht werden soll.

Und warum sollte auch eine Prozedur fortgesetzt werden? Du brauchst den Code nach dem Aufruf des Fensters doch nur in das Event zu schreiben, dass das zweite Fenster bestätigt oder abgebrochen wurde.


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