Autor Beitrag
wwwdirk
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38


D6 Prof / D2005 Prof
BeitragVerfasst: Do 05.01.06 09:34 
Hallo,

habe trotz intensiver Recherche hier im Forum, nicht wirklich die passende Lösung für mein Problem gefunden.

Allgemein: Während eines Datenbankzugriffs soll ein Dialog angezeigt werden, der eine Progressbar beinhaltet.

Mein Ansatz:
1) Den Dialog erstellen und anzeigen (mit FormStyle := fsStayOnTop)
2) Den DB-Zugriff über einen seperaten Thread implementierern

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
// Methode meiner Klasse ....
function TMyClass.FetchData (const aSelectStatement: string): TStringList;
var
  dlg        : TDlgProgressBar;
  FetchThread: TFetchThread;

begin
  dlg := TdlgProgressBar.Create(nil);
  try
    // Dialog anzeigen
    dlg.Show;
    // Thread erstellen ...
    FetchThread := TFetchThread.Create (FConnection, aSelectStatement);
    // ... und warten ...
    FetchThread.WaitFor;
    // Thread-Property Result auswerten und als Funktionsergebnis liefern ...
    result := FetchThread.Result;
    // Thread freigeben ...
    FetchThread.Free;
  finally
    // Dialog schliessen
    dlg.Close;
    dlg := nil;
  end;

// Thread-Deklaration
  TFetchThread = class(TThread)
  private
    { Private declarations }
    FSelectStatement : string;
    FConnection      : TADOConnection;
    FResult          : TStringList;
  protected
    procedure Execute; override;
  public
    constructor Create (aConnection: TADOConnection; aSelectStatement: string);
    property Result: TStringList read FResult;
  end;

implementation

uses
  ADOInt;

constructor TFetchThread.Create (aConnection: TADOConnection;
 aSelectStatement: string);
begin
  FResult          := TStringList.Create;
  FConnection      := aConnection;
  FSelectStatement := aSelectStatement;
  FreeOnTerminate  := false;
  inherited Create (false);
end;

procedure TFetchThread.Execute;
begin
  if Assigned (FConnection) then
    // Datenbankzugriff ...
    with CoRecordSet.Create do
      try
        CursorLocation := adUseClient;
        Open (FSelectStatement, FConnection.ConnectionObject, adOpenStatic,
          adLockReadOnly, adCmdText);
        // Ergebnis-TStringList belegen ...
        if RecordCount > 0 then
          FResult.Text := GetString (adClipString, RecordCount, ';', #13#10, '');
      finally
        Close;
      end;
end;


Von der Funktionalität her funktioniert alles einwandfrei. Der Dialog wird während des Datenbankzugriffs angezeigt und schliesst nach Abarbeitung. Allerdings fehlt die sich bewegende Progressbar.

Irgendwelche Tipps?

Danke u. viele Grüße
Dirk
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 05.01.06 14:35 
Ich sehe niergend eine Synchronize-Methode die irgndwie die Progressbar weiter setzt. :gruebel:
wwwdirk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38


D6 Prof / D2005 Prof
BeitragVerfasst: Do 05.01.06 14:48 
Titel: TMarqueeProgressBar
Hallo Michael,

die Dialogmaske beinhaltet diese TMarqueeProgressBar-Komponente (XP-like), die automatisch beim Anzeigen der Form losläuft und solange im "Kreis" läuft, bis meine Maske wieder geschlossen wird. Dies geschieht in der aufrufenden Funktion. Die Frage ist, ist ein Aufruf von Synchronize notwendig? Wenn ja, wie? Evtl. mit dlg.ProgressBar1.Refresh // oder .Repaint????

Danke u. Gruss
Dirk
wwwdirk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38


D6 Prof / D2005 Prof
BeitragVerfasst: Do 05.01.06 15:08 
Titel: Synchronize
Hallo,

habe gerade mal einen Synchronize-Aufruf eingebaut, damit hat's in jedem Fall zu tun. Jetzt ist die ProgressBar nämlich sichtbar, steht allerdings. :(
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TFetchThread.UpdateDlgProgressBar;
begin
  if Assigned (FDialog) then
    FDialog.pgbWait.Refresh;
end;

procedure TFetchThread.Execute;
begin
  { Thread-Code hier einfügen }
  if Assigned (FConnection) then
    with CoRecordSet.Create do
      try
        Synchronize (UpdateDlgProgressBar);
        CursorLocation := adUseClient;
        Open (FSelectStatement, FConnection.ConnectionObject, adOpenStatic,
          adLockReadOnly, adCmdText);
        if RecordCount > 0 then
          FResult.Text := GetString (adClipString, RecordCount, ';', #13#10, '');
      finally
        Close;
      end;

Das Problem ist, ich kann keinen regelmäßigen - etwa in einer Schleife - Aufruf von Synchronize implementieren. Der Fokus fehlt während der DB-Abfrage und die kann je nach Umfang eben unangenehm lange dauern?!?!?

Weitere gute Tipps?

Danke u. Gruss
Dirk
wwwdirk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38


D6 Prof / D2005 Prof
BeitragVerfasst: Di 10.01.06 12:02 
Moin,
habe immer noch keine zufriedenstellende Lösung gefunden. Bin das Problem in der Zwischenzeit mal andersrum angegangen, d.h.

Der zusätzliche Thread ist für die Anzeige der Maske zuständig und der Hauptthread implementiert den Datenbankzugriff:

Hauptfunktion ...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
// ..
// ProgressBar-Dialog instanziieren und anzeigen ...
FdlgProgressBar := TdlgProgressBar.Create (nil);
FdlgProgressBar.Show;
// ... Thread erzeugen und Dialog übergeben ...
FThreadWait := TThreadWait.Create (FdlgProgressBar);
FThreadWait.OnTerminate := OnTerminateThread;

// Datenbankzugriff und Ergebnisverarbeitung ...
result := TStringList.Create;
with CoRecordSet.Create do
  try
    CursorLocation := adUseClient;
    Open (aSelectStatement, FConnection.ConnectionObject, adOpenStatic,
      adLockReadOnly, adCmdText);
    if RecordCount > 0 then
      result.Text := GetString (adClipString, RecordCount, ';', #13#10, NULL);
  finally
    Close;
    // Schliessen des Threads
    FThreadWait.Terminate;
  end;

OnTerminate-Funktion für das Thread-Objekt
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TMyData.OnTerminateThread (Sender: TObject);
begin
  FdlgProgressBar.Close;
  FdlgProgressBar := nil;
  FThreadWait     := nil;
end;

Thread-Klasse:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
  TThreadWait = class (TThread)
  private
    FThreadDialog: TdlgProgressBar;
    procedure UpdateVCL;
  protected
    procedure Execute; override;
  public
    constructor Create (aDialog: TdlgProgressBar);
  end;

implementation

constructor TThreadWait.Create (aDialog: TdlgProgressBar);
begin
  FThreadDialog   := aDialog;
  FreeOnTerminate := true;
  inherited Create (false);
end;

procedure TThreadWait.UpdateVCL;
begin
  FThreadDialog.Update;
end;

procedure TThreadWait.Execute;
begin
  while not Terminated do
  begin
    Synchronize (UpdateVCL);
    Sleep (250);
  end;
end;


Das Problem ist, das der Dialog zwar angezeigt wird, die darauf enthalten TProgressBar-Komponente allerdings nicht. Ich denke das liegt einfach daran, das der DB-Zugriff zuviele Systemresourcen schluckt bzw. dass während des DB-Zugriffs der Thread, der eigentlich meinen Dialog aktualisieren soll, steht.

Tipps u. Anregungen werden füsseküssend ;-) entgegengenommen.

Viele Grüße
Dirk
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 10.01.06 12:44 
Das ist Mist. Wenn die DB Abfrage wieder länger dauert, dann hängt dein Hauptthread ja wieder. Regele alles im extra Thread. Und wie schon gesagt, wo ist die Synchronize Methode, der die Form und die Kontrolls darauf aktualisiert?
wwwdirk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38


D6 Prof / D2005 Prof
BeitragVerfasst: Di 10.01.06 12:56 
Titel: Thread u. Synchronize
So oder so,
der Datenbankzugriff blockiert den "konkurrierenden" Thread, da ich nur einmal Synchronize aufrufen kann. Siehe meinen Post oben, nach deinem Tipp mit dem Synchronize-Aufruf. Die "Open"-Anweisung geht sofort gegen die DB und kommt erst wieder wenn alle Daten "gefetcht" sind.
Ich komme irgendwie nicht weiter! :(
alias5000
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: Di 10.01.06 13:31 
kann man die Datenbank Sache nicht auch noch in einen extra Thread auslagern? (Also ohne Synchronize). Weil so kann ja die synchronize-Methode nicht ausgeführt werden, wenn der Hauptthread die ganze Zeit arbeitet. Und zwischendrin ein Application.ProcessMessages geht ja scheints auch net...

_________________
Programmers never die, they just GOSUB without RETURN
wwwdirk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38


D6 Prof / D2005 Prof
BeitragVerfasst: Di 10.01.06 14:17 
Titel: 2 Threads
Hi,

du meinst quasi, eine Kombi der beiden hier geposteten Lösungsansätze? Also einen Thread zur Verwaltung des Dialogs mit entsprechendem Synchronize und ein zweiter Thread (nicht der Hauptthread) zur Durchführung der DB-Abfrage ohne Synchronize?

Ein Versuch ist's wert!

mfg
Dirk