DBLookupCombobox bei erster Anzeige leer

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
sierdolg
Beiträge: 66
Registriert: Mi 24. Okt 2012, 15:50

DBLookupCombobox bei erster Anzeige leer

Beitrag von sierdolg »

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?

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von hde »

Wir kennen ein solches Problem nicht, aber sag uns mal bitte, mit welchen Tools / Modueln du arbeitest und wie.

sierdolg
Beiträge: 66
Registriert: Mi 24. Okt 2012, 15:50

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von sierdolg »

... das macht Hoffnung ;-) Entschuldigung, die Randbedingungen hatte ich vorhin mit einzufügen vergessen:
  • 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
Auch ein Minimalprojekt verhält sich in derselben Weise (vgl. Demo.pdf).

"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

knight
Beiträge: 802
Registriert: Mi 13. Sep 2006, 22:30

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von knight »

Ä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

sierdolg
Beiträge: 66
Registriert: Mi 24. Okt 2012, 15:50

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von sierdolg »

Hallo knight,

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;         
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:

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;
 

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von hde »

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.

sierdolg
Beiträge: 66
Registriert: Mi 24. Okt 2012, 15:50

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von sierdolg »

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.
Dateianhänge
Test.png

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von hde »

sierdolg hat geschrieben:"ListIndex(-1) out of bounds"
ein solcher Fehler MUSS kommen wenn ein LookUp auf eine icht aktive Query/Table stößt.
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

sierdolg
Beiträge: 66
Registriert: Mi 24. Okt 2012, 15:50

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von sierdolg »

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:

Code: Alles auswählen

procedure TForm1.FormActivate(Sender: TObject);
     WriteLn(DataModule1.ZQueryTblLieferschein.Active);
     WriteLn(DataModule1.ZQueryRechnungsempfaenger.Active);
     WriteLn(DataModule1.ZQueryRechnungssteller.Active);
end; 
 
In der Debug-Konsole erscheint beim Programmstart:

Code: Alles auswählen

TRUE
TRUE
TRUE
und beim Klick auf den Refresh-Button:

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?
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.

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von hde »

@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

sierdolg
Beiträge: 66
Registriert: Mi 24. Okt 2012, 15:50

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von sierdolg »

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:
hde hat geschrieben:Ändere lpr so, dass das Datamodul als erstes creiert wird,
* 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 die

Code: Alles auswählen

     DataModule1.ZConnection1.Disconnect;
     DataModule1.ZConnection1.Connect; //usw.
 
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!
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
* Mit "Login" meist Du wohl einen eigenen, separaten Dialog - oder gibt es da etwas, das ich bisher übersehen habe?
* 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!

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

Re: DBLookupCombobox bei erster Anzeige leer

Beitrag von hde »

sierdolg hat geschrieben: daß man die Reihenfolge steuern kann
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.

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

Antworten