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/)
-   -   verhindern: Klick auf Titelleiste stoppt Programm (https://www.delphipraxis.net/156304-verhindern-klick-auf-titelleiste-stoppt-programm.html)

SevenOfNine 27. Nov 2010 12:08

verhindern: Klick auf Titelleiste stoppt Programm
 
Hallo zusammen,

ist es irgendwie möglich, das "Einfrieren" des Hauptprogramms in einer Form zu verhindern, wenn man auf die Titelleiste klickt?

Hintergrund ist folgender: Ich übertrage Daten zwischen PC und externer Hardware, wenn ich nun mit der Maus zum Beispiel das
Fenster mit Klick auf die Titelleiste verschiebe, wird das Programm im Fenster angehalten, passiert das zu lange, erfolgt bei
der externen Hardware ein Timeout, es kommt somit zu einem Protokollfehler, die Übertragung wird abgebrochen.

Das Verschieben des Fensters habe ich bereits in der kritischen Phase abgefangen (TWMMoving). Klick auf die Titelleiste stoppt
das Programm aber immer noch. "bsNone" möchte ich ungern nutzen.

Ich könnte mir vorstellen, wenn man die Übertragungsroutine als Thread laufen läßt (eventuell sogar nur in einem OnTimer-Event ?!),
dass es nicht mehr zum "Einfrieren" kommt, da fehlt mir aber noch was KnowHow. Es ist wahrscheinlich auch ein bisschen kompliziert,
Daten zwischen Hauptprogramm und Thread auszutauschen. Am besten wäre eine einfache Lösung, so dass ich auch nicht mehr viel "umbauen" muss.

Vielleicht halt ja jemand mal Tipps, wie ich das machen könnte.

Grüße,
Seven

Sir Rufo 27. Nov 2010 12:09

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Pack die Übertragung in einen Thread

SevenOfNine 27. Nov 2010 12:20

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Zitat:

Zitat von Sir Rufo (Beitrag 1064401)
Pack die Übertragung in einen Thread

Danke für die schnelle Antwort,

dass es mit einem Thread funktioniert, habe ich mir schon gedacht, wollte ich aber möglichst vermeiden, da mir
hier noch KnowHow fehlt, ausserdem muss ich wahrscheinlich deswegen einiges umbauen, zum Beispiel Zugriff
auf visuelle Komponenten wir Progressbar, Status Captions usw. während der Übertragung.

Seven

Bummi 27. Nov 2010 12:26

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
ist ein bisschen Einarbeitung nötig, lohnt sich in jedem Fall, wenn Dein Code jetzt schon sauber strukturiert ist kannst Du die Statusmeldunden über synchronize weiterverwenden.

Sir Rufo 27. Nov 2010 12:33

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Der Durchgriff vom Thread auf die visuellen Komponenten hat durchaus seine Tücken.

Der Hinweis im Quelltext (wenn man ein Thread-Objekt erstellt) alle Zugriffe auf die Oberfläche (HauptThread, bzw. einen anderen ThreadKontext) mittels Synchronize zu realisieren sollte man unbedingt beachten.

Allerdings muss gerade vor diesem Hintergrund folgendes beachten:
Delphi-Quellcode:
procedure TFooThread.Execute;
begin
  while not Terminated do
    begin
      Synchronize( MainForm.Method ); // Es geht erst dann weiter, wenn die Methode komplett abgearbeitet wurde
    end;
end;
Wenn jetzt der HauptThread der Anwendung blockiert ist (durch das Festhalten der TitelLeiste) dann würde in diesem Falle auch der Thread blockiert und damit haben wir hiermit keine Lösung des Problems.

Besser ist es in so einem Fall folgendes zu verwenden:
Delphi-Quellcode:
procedure TFooThread.Execute;
begin
  while not Terminated do
    begin
      Queue( MainForm.Method );
    end;
end;
Die Ausführung der Methode wird in eine Warteschlange gestellt und der HauptThread führt diese dann aus, wenn er wieder Zeit dafür hat. Der Thread wird aber nicht mehr blockiert.

SevenOfNine 27. Nov 2010 12:34

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Ok, dann werde ich mich mal in Threads einarbeiten.

Danke euch beiden.

Seven

Bummi 27. Nov 2010 12:44

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
@Sir Rufo

jepp, ich habe wieder mal zu kurz gedacht...

taveuni 27. Nov 2010 13:24

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Zitat:

Zitat von Sir Rufo (Beitrag 1064407)
Besser ist es in so einem Fall folgendes zu verwenden:
Delphi-Quellcode:
procedure TFooThread.Execute;
begin
  while not Terminated do
    begin
      Queue( MainForm.Method );
    end;
end;
Die Ausführung der Methode wird in eine Warteschlange gestellt und der HauptThread führt diese dann aus, wenn er wieder Zeit dafür hat. Der Thread wird aber nicht mehr blockiert.

Meinst Du damit die Queue von einem 2. Thread abarbeiten zu lassen?
Oder ist das Queue(MainForm.Method) hier eine Methode welche ich noch nicht kenne?

Luckie 27. Nov 2010 13:28

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Queue kenne ich auch nicht. Aber sollte das ein Zugriff auf das Formular sein, muss er synchronisiert werden.

taveuni 27. Nov 2010 13:34

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Hallo Luckie,

Ja ist schon klar.
Aber in Sir Rufos Anwort werden eben diese in eine Queue geschoben.
Denn der Thread macht ja eigentlich was anderes.
Meiner Ansicht nach müssen diese Methoden in der Queue aber dann
von einem anderen Thread abgearbeitet werden. Ansonsten wär es ja witzlos.

Sir Rufo 27. Nov 2010 13:38

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Delphi-Referenz durchsuchenQueue leistet im Prinzip das gleiche wie Delphi-Referenz durchsuchenSynchronize mit einem entscheidenden Unterschied:

Synchronize( AMethod ) arbeitet die Methode in einem synchronisiertem Kontext ab (klar, das wissen wir alle).
Wenn in dieser Methode jetzt eine Wahnsinns-Berechnung durchgeführt wird, die z.B. so 10 Sekunden dauert, dann wird auch der Thread (aus dem Synchronize aufgerufen wurde) für genau diese 10 Sekunden quasi unterbrochen.

Queue( AMethod ) übergibt das (intern) an eine MessageQueue und der HauptThread arbeitet diese ab, wenn er dafür Zeit hat.
Der Thread läuft aber direkt danach weiter und wird nicht durch die lange Abarbeitung unterbrochen.

Somit hat Synchronize ein blockierendes und Queue eine nicht blockierendes Verhalten.
Ansonsten sind die gleich

Zitat:

Zitat von taveuni (Beitrag 1064416)
Aber in Sir Rufos Anwort werden eben diese in eine Queue geschoben.
Denn der Thread macht ja eigentlich was anderes.
Meiner Ansicht nach müssen diese Methoden in der Queue aber dann
von einem anderen Thread abgearbeitet werden. Ansonsten wär es ja witzlos.

Wird die doch auch ... vom HauptThread oder jedem anderen, den man dabei mitgibt (genau wie beim Synchronize)

taveuni 27. Nov 2010 13:40

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Bitte Bitte sag mir dass es das auch bei Delphi 2007 schon gibt.
Kanns leider hier zu Hause nicht überprüfen.

Luckie 27. Nov 2010 13:55

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Ab welcher Delphi Version gibt es die Methode Queue von TThread?

taveuni 27. Nov 2010 13:56

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Zitat:

Zitat von Luckie (Beitrag 1064423)
Ab welcher Delphi Version gibt es die Methode Queue von TThread?

Ich sehe Du hast Delphi 2006.
Gibts die bei Deiner?
(Dann hab ich die auch. Hechel)

Luckie 27. Nov 2010 13:58

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Kann ich im Moment nicht nach gucken, da ich ihr auf dem Netbook nur Delphi 7 installiert habe.

Nachtrag: Unter D7 gibt es die Methode noch nicht.

Sir Rufo 27. Nov 2010 14:19

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Liste der Anhänge anzeigen (Anzahl: 3)
Gute Frage ... bei D2010 gibt es die auf jeden Fall

Im Anhang mal ein kleines Test-Projekt wo man den Unterschied zwischen Queue und Synchronize sehen kann.

In der Listbox wird jeweils der Erstellungszeitpunkt im Thread und der Zeitpunkt der Anzeige geschrieben.
Nach jeder Anzeige schläft der HauptThread 500ms (um eine zeitraubende Bearbeitung zu simulieren)
Bei Synchronize sind beide Zeiten gleich, bei Queue sind diese unterschiedlich.

(exe + src included)

(äh, der Source ist nur so hingeklatscht ... also bitte keine Kommentare wegen dem Stil :mrgreen: )

taveuni 27. Nov 2010 14:22

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Puhh..
Was hab ich mir eigene ThreadPools gebaut genau für diesen Zweck.
Ich hoffe doch sehr dass mich am Montag diese Methode aus D2007 anspringt!

Danke. Man lernt immer wieder dazu.
(bzw. endeckt Features von denen man nur zu träumen wagte)

Luckie 27. Nov 2010 14:26

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Moment, ThreadPools sind was anderes. ThreadPolls verwalten mehrere WorkerThreads. Wie unser Adel schon geschrieben hat ist die Methode Queue die non-blocking Version von Synchronize.

Bummi 27. Nov 2010 17:43

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
@Sir Rufo

es gibt da eine Stelle in Deinem Code, mit dem ich nicht klar komme:

Delphi-Quellcode:
constructor TWorkThread.Create( CreateSuspended : Boolean );
  begin
    FCS := TCriticalSection.Create;

ich war bisher davon ausgegangen dass diese Section ein eindeutiger, einmaliger Abschnitt sein muss.

SirThornberry 27. Nov 2010 19:15

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Es kommt speziell darauf an was du in der Oberfläche aktualisieren willst. Willst du nur eine Progressbar aktualisieren wäre eine Variante den aktuellen Fortschritt in einer Variablen abzulegen und per Timer dann diesen Status in regelmäßigen Abständen abfragen. Oder anstelle von syncronize einfach Nachrichten posten (mit Postmessage). Aber es kommt immer darauf an was genau man machen will um zu schauen welche Methode die beste ist.

Bummi 27. Nov 2010 19:21

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
@SirThornberry

falls Deine Antwort an mich gerichtet war, es ging mir darum daß IMHO eine CriticalSection eineindeutig zu sein hat wenn sie den gewünschten Effekt haben soll, oder bin ich hier auf dem ganz falschen Dampfer.

Luckie 27. Nov 2010 19:22

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Nein, du bist auf dem richtigen Dampfer. SirThornberry fährt mit dem Code auf der Titanic und der Eisberg ist nicht mehr weit. ;)

Sir Rufo 27. Nov 2010 21:55

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Zitat:

Zitat von Bummi (Beitrag 1064468)
@Sir Rufo

es gibt da eine Stelle in Deinem Code, mit dem ich nicht klar komme:

Delphi-Quellcode:
constructor TWorkThread.Create( CreateSuspended : Boolean );
  begin
    FCS := TCriticalSection.Create;

ich war bisher davon ausgegangen dass diese Section ein eindeutiger, einmaliger Abschnitt sein muss.

Jo, aber die ist doch eindeutig für das Objekt? oder ich verstehe deine Frage nicht :gruebel:
Und ich verstehe auch nicht warum es einmalig sein muss?

Ich kann so viele TCriticalSection-Instanzen wie ich möchte/benötige.
Manchmal kann es Sinn machen mehrere Instanzen zu benutzen.

Es geht ja nur darum (in einer MultiThread-Umgebung) einerseits die Zugriffe auf den Speicher zu regeln (gleichzeitiges Lesen und Schreiben erzeugt halt Zugriffsfehler) und andererseits (vergleichbar mit den Transaktionen im DB-Umfeld) konsistente Daten zu erhalten (bei geschickter Verwendung).

Kleines Beispiel zu den konsistenten Daten:
Delphi-Quellcode:
function TMyThread.GetPoint : TPoint;
begin
  FCS.Enter;
  try
    Result := FPoint;
  finally
    FCS.Leave;
  end;
end;

procedure TMyThread.Execute;
begin
  while not Terminated do
    begin

      // Diese Daten sind immer konsistent bei der Abfrage

      FCS.Enter;
      try
        FPoint.X := 1;
        FPoint.Y := 1;
      finally
        FCS.Leave;
      end;

      // Hier ist die Konsistenz nicht gewährleistet - also schlechter Code :o)

      FCS.Enter;
      try
        FPoint.X := 2;
      finally
        FCS.Leave;
      end;

      // Erfolgt jetzt ein Zugriff von aussen, dann hat FPoint ja den Wert (2,1)

      FCS.Enter;
      try
        FPoint.Y := 2;
      finally
        FCS.Leave;
      end;

    end;
end;

Luckie 27. Nov 2010 22:05

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Wenn mehrere Threads aufeinander warten müssen, dann dürfen sie auch nur die gleiche CriticalSection nutzen. Das ist wie bei einer Ampelkreuzung, die darf auch nur von einer Schaltung gesteuert werden. Hätte jede Ampel ihre eigene Steuerung würde es krachen.

Sir Rufo 27. Nov 2010 23:21

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Eine CriticalSection soll ja nur vor dem gleichzeitigen Lesen und Schreiben schützen.

Somit kommt es darauf an, was man schützen möchte, denn nur ein Thread kann die CriticalSection betreten. Alle anderen warten solange, bis die CriticalSection wieder betreten werden kann und dann geht wieder ein Thread in diese CriticalSection.

Somit kann man mit einer CriticalSection auch einen/mehrere Threads blockieren. Schlimmstenfalls sind sogar Deadlocks möglich.

Aus diesem Grund kann es von Vorteil sein, unterschiedliche CriticalSections zu benutzen um eine ungewollte Blockade zu vermeiden. Ansonsten verspielt man den Vorteil von Queue und hat sich wieder ein Synchronize draus gebaut.

Bummi 27. Nov 2010 23:32

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
BWT, wir gehen Offtopic, vielleicht sollten wir einen neue Thread "CriticalSection" aufmachen

Aber die Criticalsection wird ja nur von denen beachtet die sie nutzen.
Wenn Du einen Bereich als Critical kennzeichnest in den ein anderer schreiben kann dann muß er auch so zugreifen, wenn kein anderer zugreifen kann brauchst Du keine CriticalSection.

Ich habe mal ein Beispiel für das angehängt wo ich das Problem sehe.
Button 1 Klicken und direkt danach Button2 klicken

in TMyThread.Execute die Auskommentierung wechslen, das gleiche passiert auch wenn man statt einer anderen, gar keine CriticalSection verwendet.

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,SyncObjs, StdCtrls;

type
  TMyThread = CLass(TThread)

   protected
    procedure Execute; override;

     public
     constructor Create( CreateSuspended : Boolean );
    destructor Destroy; override;
  End;
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  FCS ,FCS2: TCriticalSection;

  txt:String;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  tc:Cardinal;
begin
  FCS.Enter;
  txt := 'Button1';
  tc := GetTickCount;
  while GetTickCount < (tc + 5000) do Application.ProcessMessages;
  Showmessage(txt);
  FCS.Leave;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    TMyThread.Create(false);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   FCS := TCriticalSection.Create;
   FCS2 := TCriticalSection.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FCS.Free;
  FCS2.Free;
end;

{ TMyThread }

constructor TMyThread.Create(CreateSuspended: Boolean);
begin
 inherited;
 FreeOnTerminate := true;
end;

destructor TMyThread.Destroy;
begin
  inherited;
end;

procedure TMyThread.Execute;
begin
  inherited;
  // das liefert Thread als Ergebnis in
  //Showmessage von Button1Click
  FCS2.Enter;
  txt := 'Thread';
  FCS2.Leave;

  // das liefert das erwartete Ergebnis in
  //Showmessage von Button1Click
  {
  FCS.Enter;
  txt := 'Thread';
  FCS.Leave;
  }
end;

end.

Sir Rufo 27. Nov 2010 23:52

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Aus diesem Grund hänge ich die Instanz von TCriticalSection auch direkt an den Thread, um dessen Properties so zu schützen, dass kein gleichzeitiger Zugriff darauf erfolgen kann. Mittels Getter und Setter wird dann automatisch die CS betreten/verlassen. Somit wird der Zugriff auf selbige extrem stressfrei.

Wir sollten tatsächlich einen neuen Thread draus machen ...

v2afrank 29. Nov 2010 07:32

AW: verhindern: Klick auf Titelleiste stoppt Programm
 
Ich habe gerade mal in meinem Delphi 2006 nachgeschaut. Das gibt es die Methode schon


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