| Autor |
Beitrag |
wwwdirk
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: 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
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:
| function TMyClass.FetchData (const aSelectStatement: string): TStringList; var dlg : TDlgProgressBar; FetchThread: TFetchThread;
begin dlg := TdlgProgressBar.Create(nil); try dlg.Show; FetchThread := TFetchThread.Create (FConnection, aSelectStatement); FetchThread.WaitFor; result := FetchThread.Result; FetchThread.Free; finally dlg.Close; dlg := nil; end;
TFetchThread = class(TThread) private 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 with CoRecordSet.Create do try CursorLocation := adUseClient; Open (FSelectStatement, FConnection.ConnectionObject, adOpenStatic, adLockReadOnly, adCmdText); 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
|
Verfasst: Do 05.01.06 14:35
Ich sehe niergend eine Synchronize-Methode die irgndwie die Progressbar weiter setzt. 
|
|
wwwdirk 
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: 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 ????
Danke u. Gruss
Dirk
|
|
wwwdirk 
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: 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.
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 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 
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: 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 ...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| FdlgProgressBar := TdlgProgressBar.Create (nil); FdlgProgressBar.Show; FThreadWait := TThreadWait.Create (FdlgProgressBar); FThreadWait.OnTerminate := OnTerminateThread;
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; FThreadWait.Terminate; end; |
OnTerminate-Funktion für das Thread-Objekt
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TMyData.OnTerminateThread (Sender: TObject); begin FdlgProgressBar.Close; FdlgProgressBar := nil; FThreadWait := nil; end; |
Thread-Klasse:
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
|
Verfasst: 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 
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: 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
      
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)
|
Verfasst: 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 
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: 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
|
|
|