Announcement

Collapse
No announcement yet.

Refresh einer Form mit einem Thread ?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Refresh einer Form mit einem Thread ?

    Wie kann man ein Thread erzeugen das dauernt ein Formular neuzeichnet (Refresh).

    Mein 1 Problem: Ich habe ein Status Formular das im Programm anzeigt wie weit er mit der Arbeit ist (Form mit Progressbar bzw. Gauge). Zwischen der Arbeit rufe ich immer "Form.refresh" auf. Diesen Aufruf möchte ich mir ersparen.

    Mein 2 Problem: Ich möchte in diesem Status Formular ein "Abbrechen" Button einfügen. Leider ist das Programm während der Arbeit so ausgelaßtet das niemand mehr dieses Button Drücken kann.

    Ich hoffe das mir jemand bei diesen Problemen helfen kann.

    Danke im voraus.

  • #2
    Hallo,

    auf die Benutzeroberfläche einer VCL-Anwendung sollte <b>nur</b> innerhalb des primären Threads der VCL zugegriffen werden, aber <b>in der Regel nicht</b> aus einem zweiten Thread heraus. Aus diesem Grund stellt TThread auch die Methode <b>Synchronize</b> zur Verfügung.

    Damit der Button "Abbrechen" funktioniert, muss das Programm während der Arbeit regelmässig <b>Application.ProcessMessages</b> aufrufen. Bei jedem Aufruf kann die VCL die Botschaftswarteschlange auslesen und so auf die Benutzeraktion reagieren

    Comment


    • #3
      Danke für die Ihre Antwort Hr. Kosch

      Leider nützt mir das nichts. In meinem Programm starte ich ca. 30 Access Abfragen nacheinander mittels ADO oder DAO. D.h. ich habe erst nach der Abfrage wieder die möglichkeit ProcessMessages aufzurufen. Während der Abfrage steht jedoch mein Programm. Deshalb habe ich gedacht man könnte vielleicht dafür ein Thread verwenden

      Comment


      • #4
        Ja, kannste auch, aber eben nur "umgekehrt" gedacht.
        Lagere Deine ADO-Abfragen in einen Thread aus und warte im
        Hauptthread der Anwendung auf deren Fertigstellung

        Gruß Hage

        Comment


        • #5
          Hallo,

          prinzipiell hat Hagen Recht, aber bei ADO ist dies nicht notwendig, da ADO bei entsprechender Konfiguration dies automatisch erledigt. Das folgende Beispiel demonstriert den Einsatz von <b>eoAsyncFetchNonBlocking</b>. ADO lädt in diesem Fall die Daten automatisch in einem zweiten Thread, so dass die Benutzeroberfläche nicht einfriert und ganz normal bedient werden kann. Über spezielle Ereignisse kann sich das eigene Programm vom Ladezustand ständig informieren lassen:
          <pre>
          uses ADOInt;

          procedure TForm1.ButtonInfoClick(Sender: TObject);
          begin
          ShowMessage(ADODataSet1.CommandText);
          end;

          procedure TForm1.ButtonRecordCountClick(Sender: TObject);
          begin
          StatusBar1.Panels[2].Text := IntToStr(ADODataSet1.RecordCount);
          end;

          procedure TForm1.RadioGroup1Click(Sender: TObject);
          resourcestring
          cSQL1 = 'SELECT * FROM LONGFETCH';
          cSQL2 = 'SELECT * FROM LONGFETCH WHERE ID < 1000';
          begin
          if CheckBoxWHERE.Checked then
          ADODataSet1.CommandText := cSQL2
          else
          ADODataSet1.CommandText := cSQL1;
          case RadioGroup1.ItemIndex of
          0 : ADODataSet1.Active := False;
          1 : begin
          ADODataSet1.Active := False;
          ADODataSet1.ExecuteOptions := [];
          ADODataSet1.Active := True;
          end;
          2 : begin
          FFetch := 0;
          ADODataSet1.Active := False;
          ADODataSet1.ExecuteOptions := [eoAsyncFetchNonBlocking];
          ADODataSet1.Active := True;
          end;
          end;
          end;

          procedure TForm1.ButtonResyncClick(Sender: TObject);
          begin
          ADODataSet1.Recordset.Resync(adAffectCurrent, adResyncAllValues);
          end;

          procedure TForm1.ADODataSet1FetchComplete(DataSet: TCustomADODataSet;
          const Error: Error; var EventStatus: TEventStatus);
          begin
          MemoLog.Lines.Add('OnFetchComplete');
          end;

          procedure TForm1.ADODataSet1FetchProgress(DataSet: TCustomADODataSet;
          Progress, MaxProgress: Integer; var EventStatus: TEventStatus);
          begin
          if CheckBoxCancel.Checked then
          EventStatus := esCancel;
          Inc(FFetch);
          StatusBar1.Panels[0].Text := IntToStr(FFetch);
          MemoLog.Lines.Add('OnFetchProgress');
          end;

          procedure TForm1.ADODataSet1PostError(DataSet: TDataSet; E: EDatabaseError;
          var Action: TDataAction);
          var
          i : Integer;
          s : String;
          begin
          if E is EADOError then
          with E as EADOError do
          MemoLog.Lines.Add(e.Message);
          with ADOConnection1 do
          for i:= 0 to Errors.Count - 1 do
          begin
          s := Format('Source: %s', [Errors[i].Source]);
          MemoLog.Lines.Add(s);
          s := Format('NativeError: %d', [Errors[i].NativeError]);
          MemoLog.Lines.Add(s);
          s := Format('%s; (SQLState: %s)',
          [Errors[i].Description, Errors[i].SQLState]);
          MemoLog.Lines.Add(s);
          MemoLog.Lines.Add(' --- ');
          end;
          Action := daAbort;
          end;

          procedure TForm1.ADODataSet1AfterOpen(DataSet: TDataSet);
          begin
          with TCustomADODataSet(DataSet) do
          begin
          Recordset.MoveFirst;
          CursorPosChanged;
          Resync([]);
          end;
          end;
          </pre&gt

          Comment


          • #6
            Hi,

            von ADO habe ich keine Ahnung Ist das das mit der "Goldkante" ?

            Comment


            • #7
              Hi,

              danke für die Infos. Aber leider nutzt mir das nichts. Ich verwende ADO und DAO gleichzeitig in einem von mir Entwickelten Tool. Dehalb möchte ich ein eigenes Thread erzeugen das den Button zum Abbrechen Druckbar läßt

              Comment


              • #8
                Ok, ich weis zwar nicht ob's funktioniert aber probier das:

                <pre>

                procedure TProcessingThread.Execute;
                begin
                AttachThreadInput(GetCurrentThreadID, MainThreadID, True);
                try
                while not Terminated and not Application.Terminted do
                Application.ProcessMessages;
                finally
                AttachThreadInput(GetCurrentThreadID, MainThreadID, False);
                end;
                end;

                <pre>

                Damit könntest Du das problem mit dem Button gelösst bekommen.
                Wie Du dann aber Dein ADO/DAO abbrichst weiß ich nicht.

                Gruß Hage

                Comment


                • #9
                  hallo andreas

                  ich hab auch das problem, daß ich eine query die zu lange dauert abbrechen muß. (die query läuft im sql queryanalyser manchmal bis zu 12 minuten) mit einem thread hab ich es nicht geschaft die query wenn sie mal an den sql server abgeschickt wurde wieder zu terminieren. um die applikation aber während der ausführung der query (ohne thread) nicht zu freezen verwende ich jetzt auch eoAsyncFetchNonBlocking.
                  das funktioniert auch ganz gut. kannst du mir aber bitte nochmals erklären wie ich da die query canceln kann ???

                  danke

                  lg rober

                  Comment

                  Working...
                  X