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 Formular korrekt Freigeben (https://www.delphipraxis.net/189344-formular-korrekt-freigeben.html)

QuickAndDirty 2. Jun 2016 10:36


Formular korrekt Freigeben
 
Hallo.
Ich gebe ein Firemonkey Formular frei, ausgelöst durch eine Benutzer aktion auf dem selbigen.

Irgendwo innerhalb von TListview.OnChange kommt dieser Code.
Delphi-Quellcode:
Form.Close;
Form.Release;
Application.processmessages;
Form := nil;
Meist funktioniert das.
Seltsamer weise nicht immer.
Ich kann eine Zugriffverletzung provozieren, wenn ich im TListview.DoChange einen Breakpoint hinterlege.
Die Zugriffsverletzung passiert dann in der Mousdown Behandlung.
Delphi-Quellcode:
procedure TCommonCustomForm.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
var
  P: TPointF;
  Obj: IControl;
  SG: ISizeGrip;
  NewCursor: TCursor;
begin
  Engage;
  try
    { translate coord }
    FMousePos := PointF(X, Y);
    FDownPos := FMousePos;
    NewCursor := Cursor; // use the form cursor only if no control has been clicked
    Obj := ObjectAtPoint(ClientToScreen(FMousePos));
    if Obj <> nil then
      if (IInterface(Obj).QueryInterface(ISizeGrip, SG) = 0) then
        StartWindowResize
      else
      begin
        P := Obj.ScreenToLocal(ClientToScreen(FMousePos));
        if (Obj.DragMode = TDragMode.dmAutomatic) and (Button = TMouseButton.mbLeft) then
          Obj.BeginAutoDrag
        else
          Obj.MouseDown(Button, Shift, P.X, P.Y);
        NewCursor := Obj.Cursor; //<<< hier passiert die Zugriffsverletzung
      end
    else
      DoMouseDown(Button, Shift, X, Y);

    if FCursorService <> nil then
      FCursorService.SetCursor(NewCursor);
  finally
    Disengage;
  end;
end;
Eigentlich sollte es vermutlich immer schiefgehen. Seltsamer weise ist das nicht der Fall.

TListview verwendet einen DelayedIncidentTimer vielleicht liegt es daran, dass es in 99% der Fälle klappt.

Muss ich das Formular über einen eigenen DelayTimer freigeben oder gibts eine vorgefertigte Methode die das leistet?

FarAndBeyond 2. Jun 2016 10:43

AW: Formular korrekt Freigeben
 
"Release" und "Nil" sollte doch eigentlich reichen?

Warum schickst du dir nicht 'ne Message an das Hauptfenster und wenn das Hauptfenster diese empfängt, dann wird freigegeben?

QuickAndDirty 2. Jun 2016 10:53

AW: Formular korrekt Freigeben
 
Auch mit Release und nil ohne close
kommt es (wenn ich es mit breakpoint provoziere) zu besagter zugriffsverletzung.

Ich habe das bisher so gemacht wie es ist, weil der Fehler in Android scheinbar nicht auftritt und in Windows nur sehr sehr selten. Bin halt gerade eben erst auf die Ursache gestoßen.

Das Release findet im Navigations Befehl statt.
Ich könnte das also per PosMessage auslösen.
PostMessage mag ich nur nicht so gerne, weil man nie weiß wo ein Processmessages einem die Reihenfolge der Queue wieder durcheinander bringt.


Macht ihr das auch so?


Es müsste ein Timer sein in dem
Delphi-Quellcode:
TFmxFormState.Engaged in self.Formstate
abgefragt wird.
Ist das korrekt?

FarAndBeyond 2. Jun 2016 11:09

AW: Formular korrekt Freigeben
 
Aus dem Event heraus das Fenster freizugeben sieht für mich nicht gut aus...
Wenn du Postmessage nicht magst dann versuch doch irgendwo Sendmessage einzubauen oder gibt es in FMX QueueAsyncCall bzw. etwas ähnliches?
"IAsyncCall" ??? oder so...

Da muß es doch noch was geben was man nehmen kann...

himitsu 2. Jun 2016 11:13

AW: Formular korrekt Freigeben
 
Delphi-Quellcode:
var
  [WEAK] Form: TForm;

Form.Free; // oder Form.Close, wenn FireMonkes auch sowas wie caFree hat
Wenn die Form freigegeben wird, wird die Variable automatisch auf NIL gesetzt.

Aber nur, in NextGen-Compilern. :?

QuickAndDirty 2. Jun 2016 11:17

AW: Formular korrekt Freigeben
 
@FarAndBeyond:
Ja die Lazarus Leute haben da genau das was ich jetzt bräuchte.

Ich weiß auch nicht ob WindowsMessages so eine tolle Sache sind wenn die App in Android läuft.

@himitsu:
Ich habe probleme damit dass nach dem DoChange ereignis von TListview noch
Delphi-Quellcode:
newcursor := Obj.cursor
passiert.
Es findet noch Verarbeitung des "Mouseereignesses" statt.

Ich bräuchte ein Ereignis das feuert wenn der Formstate kein "Engaged" mehr enthält. So das dann dort die Navigation und die implizite Freigabe des Formulars stattfinden kann.
Oder ich bräuchte ne möglichkeit die Navigation delayed zu feuern. Ich kann mir das bauen mit nem Timer...es wäre halt nur schöner wenn es was fertiges gäbe.

FarAndBeyond 2. Jun 2016 11:26

AW: Formular korrekt Freigeben
 
Gutes Argument... :-)
Stimmt, da hängt Android echt hinterher... sie kriegen es einfach nicht hin die WINApi zu integrieren...

QuickAndDirty 2. Jun 2016 11:34

AW: Formular korrekt Freigeben
 
Hab den Fehler....
ohne Processmessages nach Release funktioniert alles wie es soll. Release zerstört es verzögert, via Messagequeue.

himitsu 2. Jun 2016 11:34

AW: Formular korrekt Freigeben
 
Zitat:

Oder ich bräuchte ne möglichkeit die Navigation delayed zu feuern. Ich kann mir das bauen mit nem Timer...es wäre halt nur schöner wenn es was fertiges gäbe.
theoretisch
Delphi-Quellcode:
TThread.Queue(procedure
  begin
    // machwas, aber nicht gleich
  end);
Aber zumindestens im Windows ist das so blöd implementiert, dass es eben nicht verzögert ausgeführt wird, wenn man das im VCL-MainThread ausführt.
http://www.delphipraxis.net/179193-t...der-queue.html

FarAndBeyond 2. Jun 2016 11:51

AW: Formular korrekt Freigeben
 
Zitat:

Hab den Fehler....
ohne Processmessages nach Release funktioniert alles wie es soll. Release zerstört es verzögert, via Messagequeue.
Ich höre sowieso immer man soll das "ProcessMessages" nicht benutzen... warum ist mir entgangen...
Und ich wollte gerade fragen wo du dann den Timer wieder freigibst, den sollte man ja auch nicht aus seinem eigenen Event freigeben...

himitsu 2. Jun 2016 12:33

AW: Formular korrekt Freigeben
 
Man kann Objekte in den eigenen Events freigeben, allerdings nur dann, wenn in den aufrufenden Funktionen nicht nochmal auf das Objekt zugegriffen wird und man das nicht irgendwie unterbinden kann.
Also nach dem END deiner Event-Methode darf nicht nochmal auf das Objekt zugegriffen werden, dann kann man sowas machen.

Close bei der Form kann man überall aufrufen, da es die Form nicht sofort frei gibt, sondern der Form eine Message sendet, in der die Form freigegeben wird.
PS: Da gibt die Form sich dann auch in einer eigenen Methode selber frei. :zwinker:

Zitat:

Ich höre sowieso immer man soll das "ProcessMessages" nicht benutzen... warum ist mir entgangen...
Weil das "unvorhersehbare" Aktionen an der Stelle ausführt und das den aktuellen Arbeitspfad stören könnte?

Delphi-Quellcode:
Form.Caption := 'blubb';
Form.Close;
Application.ProcessMessages; // oder ShowMessage('Hallo');
ShowMessage(Form.Caption); // peng...
Neben der Message für CM_RELEASE können/werden hier auch noch viele andere Messages ausgeführt.
Es braucht also nichtmal Form.Close, wenn du z.B. vorher auf das [X] der Form klickst, aber das Ereignis/die Message erst jetzt verarbeitet würde.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  Button1.Tag := 1; // eine globale Variable
  for i := 1 to 15 do begin
    Sleep(1000);
    Application.ProcessMessages;
    Memo1.Lines.Add(Format('%d %d', [i, Button1.Tag]));
    Button1.Tag := Button1.Tag + 1;
  end;
end;
Knopf drücken und nach über 15 Sekunden nochmal drücken
und dann auch einmal Knopf drücken und innerhalb der 15 Sekunden nochmal drücken.

FarAndBeyond 2. Jun 2016 13:14

AW: Formular korrekt Freigeben
 
@himitsu
Danke für die Info...
Ich hab' auch schon aus 'nem Event Objekte freigegeben... hab' dafür aber auch schon Prügel bezogen in 'nem anderen Forum. Auch wenn das in dem Fall gefunzt hat.

Zitat:

Weil das "unvorhersehbare" Aktionen an der Stelle ausführt und das den aktuellen Arbeitspfad stören könnte?
und man sich damit sein "Release" zerschießt :P


Ja, manchmal sieht man das Fenster nicht, weil es zu sehr in der Mitte des Monitors direkt vor der Nase angezeigt wird...


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:42 Uhr.

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