DBLookupCombobox bei erster Anzeige leer
DBLookupCombobox bei erster Anzeige leer
Hallo beisammen,
enthält ein Formular eine DBLookupCombobox und DBEdit-Felder, die allesamt an Felder einer Datenbanktabelle gebunden sind (sowie die DBLookupCombobox natürlich des weiteren an die ListSource unter Einstellung von ListField und ListFieldIndex), so erscheinen ohne weiteren Code beim Start des Programms die Werte nur in den DBEdit-Feldern. Die DBLookupComboboxen bleiben hingegen leer, bis man entweder (z.B. über einen DBNavigator) einmal Refresh auslöst wird oder den Datensatz wechselt. Dann aber erscheinen die Werte in sämtlichen Steuerelementen jeweils sofort, wie man es auch erwarten würde (jedenfalls wenn man bisher nur mit MS Access gearbeitet hatte).
Ist dieses Verhalten (Notwendigkeit eines Refresh bei der allerersten Anzeige) so normal und habe ich nur eine Lazrus-spezifische Besonderheit übersehen?
Falls es kein Bug ist: Was wäre "best practice", um für eine sofortige Anzeige aller Daten auch in den Comboboxen zu sorgen?
enthält ein Formular eine DBLookupCombobox und DBEdit-Felder, die allesamt an Felder einer Datenbanktabelle gebunden sind (sowie die DBLookupCombobox natürlich des weiteren an die ListSource unter Einstellung von ListField und ListFieldIndex), so erscheinen ohne weiteren Code beim Start des Programms die Werte nur in den DBEdit-Feldern. Die DBLookupComboboxen bleiben hingegen leer, bis man entweder (z.B. über einen DBNavigator) einmal Refresh auslöst wird oder den Datensatz wechselt. Dann aber erscheinen die Werte in sämtlichen Steuerelementen jeweils sofort, wie man es auch erwarten würde (jedenfalls wenn man bisher nur mit MS Access gearbeitet hatte).
Ist dieses Verhalten (Notwendigkeit eines Refresh bei der allerersten Anzeige) so normal und habe ich nur eine Lazrus-spezifische Besonderheit übersehen?
Falls es kein Bug ist: Was wäre "best practice", um für eine sofortige Anzeige aller Daten auch in den Comboboxen zu sorgen?
Re: DBLookupCombobox bei erster Anzeige leer
Wir kennen ein solches Problem nicht, aber sag uns mal bitte, mit welchen Tools / Modueln du arbeitest und wie.
Re: DBLookupCombobox bei erster Anzeige leer
... das macht Hoffnung
Entschuldigung, die Randbedingungen hatte ich vorhin mit einzufügen vergessen:
"Testprojekt.zip" enthält das verwendete Minimalprojekt,
"testdaten.zip" die Daten hierfür (phpmyadmin-Export).

- Lazarus 1.2.4 (gtk2)
- zeosdb/ZEOSDBO-7.1.3a-stable
- auf Debian/testing (64 bit)
- die Daten kommen von mysql Ver 14.14 Distrib 5.5.39, for debian-linux-gnu (x86_64) using readline 6.3
"Testprojekt.zip" enthält das verwendete Minimalprojekt,
"testdaten.zip" die Daten hierfür (phpmyadmin-Export).
- Dateianhänge
-
testdaten.zip
- (1.1 KiB) 95-mal heruntergeladen
-
Testprojekt.zip
- (66.55 KiB) 104-mal heruntergeladen
-
Demo.pdf
- Screenshots
- (65.7 KiB) 90-mal heruntergeladen
Re: DBLookupCombobox bei erster Anzeige leer
Ändert sich etwas, wenn du die Verbindung der Komponenten nicht per Objektinspektor vornimmst, sondern im Quellcode regelst? Bei einem ähnlichen Problem hat das bei mir geholfen.
knight
knight
Re: DBLookupCombobox bei erster Anzeige leer
Hallo knight,
gute Idee! Ich hätte im einfachsten Fall an etwas wie
gedacht, und siehe da, das hilft tatsächlich.
Trotzdem, und damit versuche ich die Profis und Komponentenentwickler anzusprechen, bleibt der diffuse Eindruck, daß TDBLookupCombo das (gemeint ist: Daten aus dem ListField sicher anzeigen, wenn die Datenquellen verbunden sind und ein Wert für das DataField in der DataSource vorliegt) besser selbst "können" sollte - denn wer sagt uns, daß ähnliche Randbedingungen nicht irgendwann später im Programmlauf erneut vorkommen und fälschlich keine Daten angezeigt werden, obwohl eigentlich welche in der DataSource stecken? (im gestern hochgeladenen Minimalbeispiel kann man es leicht zeigen, wenn man neben die Combobox einfach noch ein DBEdit setzt, das ans selbe DataField gebunden ist. Dort erscheint der Schlüssel, während die Combobox leer bleibt).
(Ich würde dem Problemkern ja gerne näher auf den Grund gehen, doch geht das leider weit über meine Anfängermöglichkeiten hinaus...)
Es kam dann noch die Idee, daß es vielleicht nur an "mangelder Sichtbarwerdung" der Daten liegen könnte. Mit einem zusätzlichen Button und diversen darüber aufgerufenen Aktualisierungsaufforderungen zeigt sich, daß dies offenbar nicht der Fall ist:
gute Idee! Ich hätte im einfachsten Fall an etwas wie
Code: Alles auswählen
procedure TForm1.FormActivate(Sender: TObject);
begin //In FormCreate noch zu früh - SIGSEV dort!
DataModule1.ZConnection1.Disconnect;
DataModule1.ZConnection1.Connect;
DataModule1.ZQueryRechnungssteller.Active:=True;
DataModule1.ZQueryRechnungsempfaenger.Active:=True;
DataModule1.ZQueryTblLieferschein.Active:=True;
end;
Trotzdem, und damit versuche ich die Profis und Komponentenentwickler anzusprechen, bleibt der diffuse Eindruck, daß TDBLookupCombo das (gemeint ist: Daten aus dem ListField sicher anzeigen, wenn die Datenquellen verbunden sind und ein Wert für das DataField in der DataSource vorliegt) besser selbst "können" sollte - denn wer sagt uns, daß ähnliche Randbedingungen nicht irgendwann später im Programmlauf erneut vorkommen und fälschlich keine Daten angezeigt werden, obwohl eigentlich welche in der DataSource stecken? (im gestern hochgeladenen Minimalbeispiel kann man es leicht zeigen, wenn man neben die Combobox einfach noch ein DBEdit setzt, das ans selbe DataField gebunden ist. Dort erscheint der Schlüssel, während die Combobox leer bleibt).
(Ich würde dem Problemkern ja gerne näher auf den Grund gehen, doch geht das leider weit über meine Anfängermöglichkeiten hinaus...)
Es kam dann noch die Idee, daß es vielleicht nur an "mangelder Sichtbarwerdung" der Daten liegen könnte. Mit einem zusätzlichen Button und diversen darüber aufgerufenen Aktualisierungsaufforderungen zeigt sich, daß dies offenbar nicht der Fall ist:
Code: Alles auswählen
procedure TForm1.Button1Click(Sender: TObject);
begin
// Form1.Refresh; // hilft nicht
// Form1.Repaint; // hilft nicht
// DBLookupComboBox1.Refresh; // hilft auch nicht
// DBLookupComboBox1.Repaint; // hilft auch nicht
end;
Re: DBLookupCombobox bei erster Anzeige leer
es liegt nicht am Ort der Zuweisung, sondern an der Reihenfolge der Open's.
Wenn du die im Designer machst gibt's eine zufällige Reihenfolge, und wenn der Lieferschein aktiviert wird während die andren Tabellen noch nicht da sind müsste eigentlich ein Fehler kommen.
Wenn du die im Designer machst gibt's eine zufällige Reihenfolge, und wenn der Lieferschein aktiviert wird während die andren Tabellen noch nicht da sind müsste eigentlich ein Fehler kommen.
Re: DBLookupCombobox bei erster Anzeige leer
Hallo hde,
an Zufall bei der Aktivierungsreihenfolge hatte ich auch gedacht - aber zunächst angenommen, der Fehler dürfe dann nur manchmal auftreten statt immer
(jedenfalls habe ich an zwei Tagen nicht einmal gesehen, daß die Comboboxen unmittelbar beim Start Daten angezeigt hätten). Dagegen könnte freilich sprechen, daß der Zufall durch eine irgendwie deterministrische Reihenfolge, in welcher der Compiler das Gegebene immer wieder aus den Einstellungen der in IDE zusammenbastelt, ja doch außen vor bleibt und die Aktivierungsreihenfolge im Binary auch bei wiederholtem Kompilieren daher doch stets dieselbe bleibt.
Man kann immerhin mit zwei Grids für die ListSources und zwei DBEdits für die beiden DataFields zeigen (siehe Screenshots). daß alle Daten in den DataSourcen vorliegen. Freilich schließt das nicht aus, daß irgend etwas "in" den DBLookupComboboxen zu früh abläuft.
Aber habe ich Dich recht verstanden, daß auch Du dann von der DBLookupCombobox Eigeninitative (einen Fehler) erwarten würdest?
(Sollte die vielleicht nicht auf Ereignisse ihrer ListSource "hören" und sich automatisch aktualisieren, wenn sich diese ändert, im Spezialfall also auch wenn sie endlich verbunden ist? Sie würde dann vielleicht als optionale Eigenschaft etwas wie "Autoupdate" haben. Ich bin deshalb nochmals alle Eigenschaften im Objektinspektor durch, aber diesbezüglich nicht fündig geworden. Alle suspekten Kandidaten "LookupCache", "ScrollListDataset", "Sorted" und "Style", die das Verhalten eventuell beeinflussen könnten, habe ich jeweils testweise umgestellt, ohne daß sich das gewünschte Verhalten jemals eingestellt hätte.)
Anders als gestern kommt heute übrigens eine "ListIndex(-1) out of bounds" Exception, wenn man den Refresh-Knopf für die gemeinsame Datasource (Lieferschein) drückt. Wenn man den ignoriert und bestätigt hat, werden die Nachschlagewerte angezeigt. Beim Weiter-und-zurück-Blättern kommt kein Fehler.
an Zufall bei der Aktivierungsreihenfolge hatte ich auch gedacht - aber zunächst angenommen, der Fehler dürfe dann nur manchmal auftreten statt immer
(jedenfalls habe ich an zwei Tagen nicht einmal gesehen, daß die Comboboxen unmittelbar beim Start Daten angezeigt hätten). Dagegen könnte freilich sprechen, daß der Zufall durch eine irgendwie deterministrische Reihenfolge, in welcher der Compiler das Gegebene immer wieder aus den Einstellungen der in IDE zusammenbastelt, ja doch außen vor bleibt und die Aktivierungsreihenfolge im Binary auch bei wiederholtem Kompilieren daher doch stets dieselbe bleibt.
Man kann immerhin mit zwei Grids für die ListSources und zwei DBEdits für die beiden DataFields zeigen (siehe Screenshots). daß alle Daten in den DataSourcen vorliegen. Freilich schließt das nicht aus, daß irgend etwas "in" den DBLookupComboboxen zu früh abläuft.
Aber habe ich Dich recht verstanden, daß auch Du dann von der DBLookupCombobox Eigeninitative (einen Fehler) erwarten würdest?
(Sollte die vielleicht nicht auf Ereignisse ihrer ListSource "hören" und sich automatisch aktualisieren, wenn sich diese ändert, im Spezialfall also auch wenn sie endlich verbunden ist? Sie würde dann vielleicht als optionale Eigenschaft etwas wie "Autoupdate" haben. Ich bin deshalb nochmals alle Eigenschaften im Objektinspektor durch, aber diesbezüglich nicht fündig geworden. Alle suspekten Kandidaten "LookupCache", "ScrollListDataset", "Sorted" und "Style", die das Verhalten eventuell beeinflussen könnten, habe ich jeweils testweise umgestellt, ohne daß sich das gewünschte Verhalten jemals eingestellt hätte.)
Anders als gestern kommt heute übrigens eine "ListIndex(-1) out of bounds" Exception, wenn man den Refresh-Knopf für die gemeinsame Datasource (Lieferschein) drückt. Wenn man den ignoriert und bestätigt hat, werden die Nachschlagewerte angezeigt. Beim Weiter-und-zurück-Blättern kommt kein Fehler.
Re: DBLookupCombobox bei erster Anzeige leer
ein solcher Fehler MUSS kommen wenn ein LookUp auf eine icht aktive Query/Table stößt.sierdolg hat geschrieben:"ListIndex(-1) out of bounds"
Die internen Abläufe einer Client/Server-Datenbankverbindung sind nicht trivial. und die LookUpCombobox sucht evtl. in einer noch leeren / nicht existierenden Listbox/Datentabelle und das MUSS Fehler produzieren.
Es ist einfach Murks einen Connect usw. im Objektinspektor zu machen, da hast du keine Kontrolle. Was ist wenn die Db auf dem PC nicht existiert oder keine Verbindung besteht? Dein Prog crasht ohne eine konkrete Fehlermeldung.
Das Datamodul sollte man als erstes creieren und kontrolliert nach Programmstart connecten usw. (Login ??)
hde
Re: DBLookupCombobox bei erster Anzeige leer
Tausend Dank für die deutlichen Worte!
Erstens: Die Notwendigkeit, alle "Datenbankanbindungsvorgänge" im Code erledigen zu müssen, war mir in dieser Deutlichkeit bisher nicht klar geworden - IDE & OI suggerieren ja gerade, daß es "auch so" gehe
. Mehr noch, erst gestern habe ich in http://www.freepascal.org/~michael/arti ... rtlaz7.pdf sinngemäß die vor 7 Jahren zu Lazarus gemachte Aussage gelesen, daß eine Anwendung mit datenbanksensitiven Controls idealerweise ohne eine einzige Zeile Code auskomme: "Most of this can be accomplished without a single line of code" (Seite 11). Das, noch dazu aus dem Munde eines der Lazarus-Väter, klingt halt schon sehr autoritativ. Drum hatte ich die Möglichkeit eines kleinen Bugs in DBLookupControl nicht ausgeschlossen, weil das Beobachtete einfach nicht zu der Ansage paßt.
Bleibt mir nur noch die Frage:
Ist FormActivate (das war von mit nur geraten, nachdem es in FormCreate augenscheinlich noch nicht funktioniert) dann der beste Platz für diese Dinge?
Zweitens: "nicht trivial" spricht jedem Lazarus-Neuling aus der Seele
und trifft ja auch auf die Events zu.
Drittens habe ich, jetzt nur mehr der Neugier halber, folgendes in das Beispiel von gestern (das den "List index (-1) out of bounds" nicht brachte und in dem alles per Designmode connected und active ist) eingefügt:
In der Debug-Konsole erscheint beim Programmstart:
und beim Klick auf den Refresh-Button:
Bis hin zu den Datasources, also unmittelbar vor die Controls, wenn ich den Zusammenhang recht verstanden habe. scheint damit doch alles in Ordnung zu sein, auch wenn es kaum lohnt, dem weiter nachzuspüren.
Erstens: Die Notwendigkeit, alle "Datenbankanbindungsvorgänge" im Code erledigen zu müssen, war mir in dieser Deutlichkeit bisher nicht klar geworden - IDE & OI suggerieren ja gerade, daß es "auch so" gehe

Bleibt mir nur noch die Frage:
Ist FormActivate (das war von mit nur geraten, nachdem es in FormCreate augenscheinlich noch nicht funktioniert) dann der beste Platz für diese Dinge?
Zweitens: "nicht trivial" spricht jedem Lazarus-Neuling aus der Seele

Drittens habe ich, jetzt nur mehr der Neugier halber, folgendes in das Beispiel von gestern (das den "List index (-1) out of bounds" nicht brachte und in dem alles per Designmode connected und active ist) eingefügt:
Code: Alles auswählen
procedure TForm1.FormActivate(Sender: TObject);
WriteLn(DataModule1.ZQueryTblLieferschein.Active);
WriteLn(DataModule1.ZQueryRechnungsempfaenger.Active);
WriteLn(DataModule1.ZQueryRechnungssteller.Active);
end;
Code: Alles auswählen
TRUE
TRUE
TRUE
Code: Alles auswählen
TApplication.HandleException List index (-1) out of bounds
Stack trace:
$0000000000483E4C
WARNING: TLCLComponent.Destroy with LCLRefCount>0. Hint: Maybe the component is processing an event?
Re: DBLookupCombobox bei erster Anzeige leer
@Sierdolg, natürlich kann man mit Lazarus, mit Delphi und vielen anderen RAD-Tools CRUD Datenbanksachen (fast) ohne Code zu schreiben erstellen, sofern man die SQL-Abfragen nicht als Code ansieht, nur Tables nutzt oder RAD-Tools benutzt die auch einen SQL-Builder dabei haben. Aber in meinen Augen ist es mehr als grenzwertig sowas als "DatenbankAnwendung" zu verkaufen es sei denn, man nimmt eine embedded Datenbank.
Du verwendest z.B. mySQL, einen echten Datenbankserver. Der läuft unabhängig von deinem Programm. Dein Programm stellt eine Anfrage an mySQL (z.B. als select ..) und dieser Datenbankserver schickt deinem Programm Daten, die dieses für sich zwischenspeichern muss (Dataset). Ein Lookup läuft in deinem Programm (nicht im Server). D.h. wenn du deine Lieferschein-Query active setzt, dann sucht dein Program im entsprechenden Dataset den passenden Datensatz. Was aber, wenn dieses Dataset noch gar nicht da ist oder leer? (z.B. Listenindex -1) Deshalb brauchst du bei Looklup fast immer etwas Code.
Und üblicherweise läuft ein Datenbankserver auf einem anderen Rechner. Ohne Code crasht dein Programm schon beim Start wenn keine Verbindung besteht oder mySQl nicht läuft, Hostadresse, Password o.dgl. nicht stimmt.
Ändere lpr so, dass das Datamodul als erstes creiert wird, dann kannst in der unit1, entweder per Login oder, was ich nicht empfehle, im Formcreate, eine Verbindung / Connect herstellen und die Verbindung prüfen und ggf. dem Anwender saubere Infos geben, wenn's Probleme gibt. FormActivate ist kein gutes Event.
hde
Du verwendest z.B. mySQL, einen echten Datenbankserver. Der läuft unabhängig von deinem Programm. Dein Programm stellt eine Anfrage an mySQL (z.B. als select ..) und dieser Datenbankserver schickt deinem Programm Daten, die dieses für sich zwischenspeichern muss (Dataset). Ein Lookup läuft in deinem Programm (nicht im Server). D.h. wenn du deine Lieferschein-Query active setzt, dann sucht dein Program im entsprechenden Dataset den passenden Datensatz. Was aber, wenn dieses Dataset noch gar nicht da ist oder leer? (z.B. Listenindex -1) Deshalb brauchst du bei Looklup fast immer etwas Code.
Und üblicherweise läuft ein Datenbankserver auf einem anderen Rechner. Ohne Code crasht dein Programm schon beim Start wenn keine Verbindung besteht oder mySQl nicht läuft, Hostadresse, Password o.dgl. nicht stimmt.
Ändere lpr so, dass das Datamodul als erstes creiert wird, dann kannst in der unit1, entweder per Login oder, was ich nicht empfehle, im Formcreate, eine Verbindung / Connect herstellen und die Verbindung prüfen und ggf. dem Anwender saubere Infos geben, wenn's Probleme gibt. FormActivate ist kein gutes Event.
hde
Re: DBLookupCombobox bei erster Anzeige leer
Hallo hde,
das stimmt schon alles. Allerdings ist der geplante Einsatzzweck im konkreten Fall gar nicht so hoch aufgehängt wie der mysql-Server als Datenhalde vielleicht suggeriert. Datenbank und Anwendung laufen lokal am selben Rechner, und alle Daten stehen sowieso auf Papier in den Ordnerregalen frei zugänglich über dem Schreibtisch. Deshalb dürfen die Anmeldedaten auch im Binary stecken und sollen das auch, weil die Anwendung sehr oft gestartet wird, um schnell was zu suchen. Ein Login per separatem Dialog wäre in dem Fall hinderlich.
Unabhängig davon finde ich einige Deiner Anmerkungen sehr spannend und der Nachfrage wert, verzeih bitte soviel Anfänger-Unwissen:
tatsächlich als erstes versucht und nur "Projekt project1 hat Exception-Klasse »External: SIGSEGV« ausgelöst. ... in Zeile 44: DataModule1.ZConnection1.Disconnect;" erhalten. Dummerweise sieht man der Meldung nicht zwingend an, daß es ein Problem der Erstellreihenfolge ist, wenn man es weiß, ist es freilich trivial. Mit umgestellter Reihenfolge ist dem nicht mehr so!
* Unter der Randbedingung, daß die Anwendung den Login selbst übernehmen soll und zwar einmal beim Start, was wäe dann noch besser als FormCreate? (Eine separte Funktion, falls es Dir um Übersichtlichkeit geht, würde man dann aber doch zumindest hier aufrufen, oder?)
* Warum ist "FormActivate" noch schlechter?
Allerherzlichsten Dank nochmals!
das stimmt schon alles. Allerdings ist der geplante Einsatzzweck im konkreten Fall gar nicht so hoch aufgehängt wie der mysql-Server als Datenhalde vielleicht suggeriert. Datenbank und Anwendung laufen lokal am selben Rechner, und alle Daten stehen sowieso auf Papier in den Ordnerregalen frei zugänglich über dem Schreibtisch. Deshalb dürfen die Anmeldedaten auch im Binary stecken und sollen das auch, weil die Anwendung sehr oft gestartet wird, um schnell was zu suchen. Ein Login per separatem Dialog wäre in dem Fall hinderlich.
Unabhängig davon finde ich einige Deiner Anmerkungen sehr spannend und der Nachfrage wert, verzeih bitte soviel Anfänger-Unwissen:
* Meinst Du Projektinspektor:Projekteinstellungen/Formulare und hier die Reihenfolge in der Liste? In der Tat steht hier (im Mini-Beispiel) "Form1" über "DataModule", und mir war nicht bewußt, daß man die Reihenfolge steuern kann, darf und wie man sieht manchmal sogar soll. Ich hatte diehde hat geschrieben:Ändere lpr so, dass das Datamodul als erstes creiert wird,
Code: Alles auswählen
DataModule1.ZConnection1.Disconnect;
DataModule1.ZConnection1.Connect; //usw.
* Mit "Login" meist Du wohl einen eigenen, separaten Dialog - oder gibt es da etwas, das ich bisher übersehen habe?hde hat geschrieben: dann kannst in der unit1, entweder per Login oder, was ich nicht empfehle, im Formcreate, eine Verbindung / Connect herstellen und die Verbindung prüfen... . FormActivate ist kein gutes Event.hde
* Unter der Randbedingung, daß die Anwendung den Login selbst übernehmen soll und zwar einmal beim Start, was wäe dann noch besser als FormCreate? (Eine separte Funktion, falls es Dir um Übersichtlichkeit geht, würde man dann aber doch zumindest hier aufrufen, oder?)
* Warum ist "FormActivate" noch schlechter?
Allerherzlichsten Dank nochmals!
Re: DBLookupCombobox bei erster Anzeige leer
die .lpr ist eine ganz normale Datei die beim Programmstart der Reihe nach abgearbeitet wird. Diese kann man, und in deinem Falle muss man, diese auch bearbeiten. Du kannst auf eine Unit oder Form nur zugreifen, wenn diese auch bereits existiert. Wird die erst später creiert, dann crasht es zwangsläufig.sierdolg hat geschrieben: daß man die Reihenfolge steuern kann
MySQL ist ein eigenständiges Datenbankprogramm das völig unabhängig von deinem Programm arbeitet und und in der Regel zentral auf einem Server läuft und auf das von allen Clients aus zugegriffen wird. In diesem Falle sollte man ein saubers Login machen damit die Verbindung gesichert hergestellt wird.
Aber auch in deinem Falle laufen auf dem PC zwei unabhägige Programme, mySQL meist als Windows-Dienst und dein Prog. Schau in die Processliste.
Wenn dein Fall so einfach, wie du schilderst, dann würde ich eine embedded Datenbank nehmen, z.B, SQLite, dann braucht es keinen Login weil nur ein Programm startet und läuft. Aber das gilt nur wenn wirklich nur ein Instanz des Progs laufen soll.
hde