Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   TJvTimer (https://www.delphipraxis.net/190441-tjvtimer.html)

Luckner 4. Okt 2016 15:12

Datenbank: Firebird • Version: 2.1 • Zugriff über: Dataset

TJvTimer
 
Hallo,

ich habe eine DBGrid, das über ein Dataset mit einer Tabelle verbunden ist. Dann existiert ein TJvTimer. Das Interval ist eingestellt auf 30000.
Folgender Code:
Delphi-Quellcode:
procedure TFramePlannung.TimerPlanungTimer(Sender: TObject);
begin
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Close;
  Datamodule5.IBDatabasePlannung.DatabaseName := dbpfad;
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Open;
end;
Theoretisch müsste sich der Inhalt des DBGrids ändern (falls sich die Einträge in der Tabelle geändert haben) Es tut sich jedoch nichts. Der TJvTimer funktioniert jedoch, weil wenn ich nur;
DatamodulePlannung.DataModule5.IBDataSetGridPlannu ng.Close;
mache, dann bekommen ich eine leere Tabelle. Woran kann es liegen, dass die Daten nicht aktualisiert werden.
Danke, Luckner

himitsu 4. Okt 2016 15:38

AW: TJvTimer
 
Das TJvTimer-Event wird standardmäßig in einem Thread ausgeführt.

Und dafür, dass du unsynchronisiert auf die VCL zugreifst, wirst du vollkommen zu Recht mit Fehlverhalten bestraft. :warn:



DataSet.DisableControls und EnableContols im Haupthtread
eventuell auch/alternativ die DataSource vom Grid abhängen

und dann kann man das DataSet gern in einem Thread aktualisieren



Alternativ im Thread ein neues DataSet holen
und das danach dann im Hauptthread schnell umhängen.

Jim Carrey 4. Okt 2016 15:38

AW: TJvTimer
 
Zitat:

Das TJvTimer-Event wird standardmäßig in einem Thread ausgeführt.
Muss dafür Threaded nicht auf True stehen? Ich meine es steht standardmäßig auf False, oder?

himitsu 4. Okt 2016 15:41

AW: TJvTimer
 
Hab den schon lange nicht mehr genutzt, aber schnell nochmal nachgeguckt und die Doku meint auch True.
http://wiki.delphi-jedi.org/wiki/JVC...Timer.Threaded

Jim Carrey 4. Okt 2016 15:47

AW: TJvTimer
 
Aber wenn der auf True ist, läuft er doch im Hauptthread und synchronisiert alles.
So ist jedenfalls mein Kenntnisstand.

Ich würde aber eh auf den TTimer umstellen. TJvTimer bringt hier keinerlei Vorteil.

himitsu 4. Okt 2016 16:02

AW: TJvTimer
 
Nee nee, wenn Threaded=True, dann läuft das Event in einem Thread.
Und wenn False, dann wird intern sowieso TTimer verwendet. :stupid:


Wenn die Anfrage "länger" dauert, dann wäre ein Thread schon OK, ABER die VCL darf von dem Thread garnichts mitbekommen
und natürlich auch die DB-Connection muß mit Threads klar kommen.

Jim Carrey 4. Okt 2016 16:07

AW: TJvTimer
 
Zitat:

Wenn die Anfrage "länger" dauert, dann wäre ein Thread schon OK, ABER die VCL darf von dem Thread garnichts mitbekommen
Ich spreche in meinen Threads ständig die VLC an und hatte bisher noch nie Probleme.
Wie sonst soll man einen Fortschrittsbalken steuern?

Luckner 4. Okt 2016 16:44

AW: TJvTimer
 
Habe jetzt einiges ausprobiert aber leider ohne Erfolg. Was mich wundert, dass wenn ich das Dataset.close setze, dann ist das Grid leer. Also reagiert die VCL auf den Timer. Ich muß mal schauen, ob das Grid (auch von Jedi) nicht irgendeinen Cache hat.

Aviator 4. Okt 2016 16:47

AW: TJvTimer
 
Zitat:

Zitat von Jim Carrey (Beitrag 1349709)
Zitat:

Wenn die Anfrage "länger" dauert, dann wäre ein Thread schon OK, ABER die VCL darf von dem Thread garnichts mitbekommen
Ich spreche in meinen Threads ständig die VLC an und hatte bisher noch nie Probleme.
Wie sonst soll man einen Fortschrittsbalken steuern?

Du kannst schon mit deiner GUI aus einem Thread "sprechen". Aber du musst die Aufrufe vorher mit Synchronize() oder Queue() synchronisieren. Aus Threads würde ich aber immer ein Event feuern anstatt direkt darauf zuzugreifen. Das Event handled dann alles was es soll. Und ein Event muss dann auch mit Sychronize(OnFinish) aufgerufen werden.

himitsu 4. Okt 2016 16:56

AW: TJvTimer
 
Die VCL ist per se nicht threadsave, daher darf man niemals unsynchronisert darauf zugreifen, da es immer zu Problemen kommen kann.

Einiges der VCL nutzt ausschließlich Messages (nur ein SendMessage in der Methode ... dann synchronisiert sich das "zufällig" von selber)


Zitat:

Zitat von Jim Carrey (Beitrag 1349709)
Wie sonst soll man einen Fortschrittsbalken steuern?

TThread.Synchronize, TThread.Queue, threadsichere Listen, Windows-Messages oder ähnliches.
Oder aucg Events im Thread setzen und in der VCL (z.B. Timer) reagiert jemand da drauf und liest das Ergebnis synchronisiert aus, wenn er Zeit hat.

SendMessage der besser PostMessage ... 'ne ProgressBar ist ja auch nur 'nen Windows-Control und da kennt die WinAPI eine pasende Message, um das zu steuern.

nahpets 4. Okt 2016 17:23

AW: TJvTimer
 
Also, wenn ich das richtig verstehe ist nach:
Delphi-Quellcode:
procedure TFramePlannung.TimerPlanungTimer(Sender: TObject);
begin
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Close;
end;
das Grid leer.

Was ist denn dann mit:
Delphi-Quellcode:
procedure TFramePlannung.TimerPlanungTimer(Sender: TObject);
begin
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Close;
  ShowMessage('isetnuleer?');
  Datamodule5.IBDatabasePlannung.DatabaseName := dbpfad;
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Open;
  ShowMessage('Jetzsehemerwiederwatt?');
end;
Ist das Grid beim ersten ShowMessage leer und beim zweiten wieder gefüllt?
Dann geht das Neuladen wohl ohne die ShowMessages so schnell, dass man es nicht sieht.
Und wenn sich nix an den Daten geändert hat, dann sieht man halt auch keinen Unterschied.

Ansonsten mal ein bisserl ändern:
Delphi-Quellcode:
procedure TFramePlannung.TimerPlanungTimer(Sender: TObject);
begin
  Screen.Cursor := crSQLWait;
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Close;
  Datamodule5.IBDatabasePlannung.DatabaseName := dbpfad;
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Open;
  Screen.Cursor := crDefault;
end;
Wenn dann die SQL-Sanduhr übrig bleibt, ist (eventuell) irgendwo eine Exception (meldungslos) abgefangen worden und die Routine wird nicht vollständig ausgeführt.
Allerdings würd' ich dann bei 'nem erfolgreichen Close ein leeres Grid erwarten.

Jumpy 4. Okt 2016 17:23

AW: TJvTimer
 
Zum Problem. Schließt du das Grid oder das Dataset, das dahinter steht? Werde aus deiner Benamsung nicht ganz schlau. Afaik muss man nicht das Grid sondern das Dataset/die Query oder was auch immer dahinter steht öffnen und schließen.

himitsu 4. Okt 2016 17:27

AW: TJvTimer
 
Zitat:

Zitat von nahpets (Beitrag 1349732)
Was ist denn dann mit:
Delphi-Quellcode:
procedure TFramePlannung.TimerPlanungTimer(Sender: TObject);
begin
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Close;
  ShowMessage('isetnuleer?');
  Datamodule5.IBDatabasePlannung.DatabaseName := dbpfad;
  DatamodulePlannung.DataModule5.IBDataSetGridPlannung.Open;
  ShowMessage('Jetzsehemerwiederwatt?');
end;
Ist das Grid beim ersten ShowMessage leer und beim zweiten wieder gefüllt?

Wenn er Glück hat, dann bringt ihm das ShowMessage nicht gleich die ganze Anwendung zum Verrecken.

ShowMessage ist VCL und was hatten wir bereits bezüglich Threads angemerkt?

Luckner 4. Okt 2016 17:37

AW: TJvTimer
 
Also ich habe mir erstmal so geholfen:
Habe das DBGrid in ein Frame gepackt.
Beim Aufruf des Frames das übliche: Dataset open usw.
Beim schliessen des Frames: Dataset close.

Jetzt im JvTimer: Frame schliessen und Frame öffnen. Es funktioniert aber leider im einem Blinken am Bildschirm.

nahpets 4. Okt 2016 17:43

AW: TJvTimer
 
@himitsu
und was hatten wir bezüglich des Schalters Threaded=True angemerkt?
Ist er nun gesetzt oder nicht, wenn nein, dann wird TTimer genutzt und dann ist ShowMessage kein Problem.

Selbst wenn der Schalter gesetzt sein sollte, könnte man das ja mal eben ändern und probieren, wie dann das Verhalten mit ShowMessage ist. Oder?

@Jumpy
Ein Grid kann man (meines Wissens) nicht schließen, sondern nur die dahinterliegende Datenmenge.

Die Namen in
Delphi-Quellcode:
DatamodulePlannung.DataModule5.IBDataSetGridPlannung
Intepretiere ich mal dahingehend, das irgendwas mit dem Namen DatamodulePlannung über (mindestens) fünf Datenmodule verfügt, wobei das fünfte Datenmodul über ein IBDataSet verfügt, das dem Grid mit den Namen Planung zugeordnet ist.

---

Prinzipiell sollte der ursprüngliche Quelltext eigentlich wie erwartet funktionieren.

Und wenn's mit TJvTimer nicht funktioniert, dann nimmt man halt mal 'nen TTimer und packt dort die Routine ins Ereignis. Ändert sich das Verhalten dann, ist TJvTimer eventuell die Problemursache. Bleibt das Verhalten aber unverändert, dann müsste man mal schauen, was denn da sonst so im Hintergrund schief gehen könnte.

@Luckner:
Die Sichtbarkeit oder Unsichtbarkeit der Frames dürfte kaum eine Auswirkung auf das Ergebnis des Öffnens und Schließens der Datenmenge haben, es wurde lediglich die Stelle im Quelltext verändert, an der der Vorgang ausgeführt wird.
Und wenn man eine Komponente versteckt und dann wieder anzeigt, dann sieht man das in der Oberfläche.

Hat sich durch Deine Änderung denn jetzt das ursprüngliche Problem erledigt?

Luckner 4. Okt 2016 17:57

AW: TJvTimer
 
Hallo nahpets,

1) habe es auch mit dem TTimer ausprobiert. Ebenfalls kein Erfolg.
2) Es gibt eine Datenmodul und wie aus dem Quellcode abzulesen ist, habe ich natürlich das entsprechende Dataset geschlossen und dann geöffnet (Wie auch im Frame).
3) Problem ist nicht unbedingt erledigt, weil das Geblincke natürlich stört.

Morgen versuche ich mit einem Querry statt Dataset. Möglicherweise funktioniert es besser.

Wenn ich einen Erfolgt erleben sollte, dann werde es hier mitteilen.

Danke, Luckner

Luckner 5. Okt 2016 12:51

AW: TJvTimer
 
Also es hat mit Querry anstatt Dataset auch nicht funktioniert. Ich belasse es erstmal mit dem Schliessen und Öffnen des Frames. Möglicherweise liegt es am JvDBGrid. Wäre aber dankbar für jeden Lösungsvorschlag.

Gruß, Luckner

nahpets 5. Okt 2016 13:02

AW: TJvTimer
 
Nutze das JvDBGrid schon seit Jahren, habe bisher noch nicht einmal erlebt, dass mir das was anders angezeigt hat, als ich erwartet habe.

Bei 'nem Close der Datenmenge und 'nem anschließenden Open habe ich immer den dann aktuellen Stand der Daten gesehen.

Meiner Meinung nach dürfte die Wahrscheinlichkeit, dass das JvDBGrid was anders anzeigt, als die Datenmenge enthält, gegen 0 tendieren.
Zumindest kann ich mir momentan keinen Programmzustand vorstellen, bei dem dies möglich sein könnte.

Luckner 5. Okt 2016 13:13

AW: TJvTimer
 
Aber irgenwie funktioniert der Timer nicht mit diesem Grid zusammen. Es zuckt nicht mal beim Schliessen und Öffnen des Datasets.

nahpets 5. Okt 2016 13:29

AW: TJvTimer
 
Das liegt aber nicht am Grid.

Bau in dem Timer doch mal hinter dem Close oder vor dem Open jeweils ein Sleep(5000) ein.
Oder irgendwie 'ne andere Warteschleife, so dass man an der Oberfläche die einzelnen Schritte sehen kann.

Wie groß ist denn die Datenmenge?
Wenn's nur ein paar wenige Datensätze sind, kann es durchaus sein, dass man das Schließen und Öffnen an der Oberfläche nicht mitbekommt, weil es einfach zu schnell geht.

Luckner 5. Okt 2016 14:14

AW: TJvTimer
 
werde ich ausprobieren. Es sind wirklich nicht viele Datensätze. So um die 50-60. Sleep werde ich sofort ausprobieren.

himitsu 5. Okt 2016 14:24

AW: TJvTimer
 
Die Oberfläche bekommt das mit. Glaubt's mir ruhig, denn das DataSet ist so nett und informiert die DataSource, die den DataLink, der den DataController und am Ende bekommt auch das Grid umgehend mit, wenn aktualisiert wurde.
(außer bei DisableControls, aber dort wird das im EnableControls nachgeholt)

Zitat:

Zitat von Luckner (Beitrag 1349832)
Aber irgenwie funktioniert der Timer nicht mit diesem Grid zusammen. Es zuckt nicht mal beim Schliessen und Öffnen des Datasets.

Das DataSet hält die Daten, eine DataSource bildet die Schnittstelle zwischen DataSet und DataLink und zuletzt der DataLink dann als Schnittstelle zum DataController des Grids,
der DataController kopiert sich sie Daten aus dem DataSet und stellt sie für das Grid bereit und das Grid läd dann die Daten aus dem DataController.
Weder DataSet, noch DataSource, DataController, DataLink, Grid und vorallem nicht fast die ganze VCL sind threadsave.

Wenn da gleichzeitig das Grid versucht zu lesen/zeichnen, während ein anderer Idiot unsynchronisiert an den Daten rumpfuscht, weil er das DataSet aktuallisiert, dann kommt es nunmal schnell zu eine klitzekleinem Problemchen.

Aber da das keiner kappieren will, bin ich hier raus.
Tschau und viel Glück noch.

Luckner 5. Okt 2016 15:10

AW: TJvTimer
 
Sleep hat auch nichts gebracht.
An himitsu: Wenn ich das Dataset.close mache und so belasse, dann bekommen ich, nach der Timerzeit, ein leeres Grid (mit einer leeren Zeile). Wenn ich aber Datase.close und dan Datase.open, dann müsste das Grid wenigstens zucken. Aber es passiert nichts.

Aviator 5. Okt 2016 15:14

AW: TJvTimer
 
Zitat:

Zitat von Luckner (Beitrag 1349856)
Sleep hat auch nichts gebracht.
An himitsu: Wenn ich das Dataset.close mache und so belasse, dann bekommen ich, nach der Timerzeit, ein leeres Grid (mit einer leeren Zeile). Wenn ich aber Datase.close und dan Datase.open, dann müsste das Grid wenigstens zucken. Aber es passiert nichts.

Da du nach dem Close ein Sleep(x) ausführst und danach direkt wieder öffnest, hat die GUI gar keine Möglichkeit sich zu aktualisieren bevor die neuen Daten kommen. Folglich siehst du auch nicht, dass das Grid "zuckt" und aktualisiert wird. Wenn du jetzt im Main Thread bist, kannst du mal versuchen vor dem Sleep(x) ein Application.ProcessMessages einzubauen. Dann bekommt die GUI wenisgtens noch Zeit sich vor dem Sleep einmal zu aktualisieren.

Aber das ist keine gängige Methode. Application.ProcessMessages solltest du eigentlich wenn möglich vermeiden und alles über Threads und dem entsprechenden Synchronize() ausführen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:32 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 by Thomas Breitkreuz