Discussion:
DB Grid - Disable Controls?
(zu alt für eine Antwort)
Nicole Wagner
2011-03-02 12:30:12 UTC
Permalink
Hallo User,


wieder habe ich ein Problem, das mir leicht loesbar erscheint, wenn man
nur wuesste, wie. Ich hoffe, ich habe wenigstens diesmal recht.

Ich habe ein DBGrid, ueber das ich iteriere und in dessen Spalten ich
Rechenwerte eintrage. Scrolle ich einmal runter und einmal rauf, dann
sind die eingetragenen Werte wieder weg.

Was muss ich schalten?
"Disable Controls" hat mein Problem leider nicht gelöst.

Am liebsten waere mir, wenn ich einzelnen Spalten temporaer "read only"
und "update protect" schalten koennte.


Danke fuer Tipps!
Nicole
Joe Galinke
2011-03-02 12:50:23 UTC
Permalink
Hallo Nicole,
Post by Nicole Wagner
Ich habe ein DBGrid, ueber das ich iteriere und in dessen Spalten ich
Rechenwerte eintrage. Scrolle ich einmal runter und einmal rauf, dann
sind die eingetragenen Werte wieder weg.
Ich wiederhole mich aus einer früheren Antwort an Dich:

| Du hast das DbGrid noch immer nicht verstanden.

Das DbGrid dient der Anzeige. Wenn Du die eingebaute Editierfunktion nutzt
wird die zugrunde liegende Datenmenge geändert und diese Änderung natürlich
angezeigt.

D.h., Du änderst direkt auf der Tabelle mit
MeinDataset.FieldByName(Fieldname).Asxxxx := ....

Vorher natürlich MeinDataset.Edit und irgendwann auch mal MeinDataset.Post.


Gruß, Joe
--
Nicole Wagner
2011-03-02 15:04:35 UTC
Permalink
Post by Joe Galinke
Hallo Nicole,
Post by Nicole Wagner
Ich habe ein DBGrid, ueber das ich iteriere und in dessen Spalten
ich Rechenwerte eintrage. Scrolle ich einmal runter und einmal
rauf, dann sind die eingetragenen Werte wieder weg.
Du hast das DbGrid noch immer nicht verstanden.
Das DbGrid dient der Anzeige. Wenn Du die eingebaute Editierfunktion
nutzt wird die zugrunde liegende Datenmenge geändert und diese
Änderung natürlich angezeigt.
D.h., Du änderst direkt auf der Tabelle mit
MeinDataset.FieldByName(Fieldname).Asxxxx := ....
Vorher natürlich MeinDataset.Edit und irgendwann auch mal
MeinDataset.Post.
Gruß, Joe
Ich aendere keine DB-generierten-Felder.
Und ich aendere nicht via edit, sondern mit z.B.:
Dataset.FieldByName('Nr').Value:=1;

Diese Werte werden auch wunschgemaess in mein Grid eingetragen. Dort
will ich sie lediglich zur Laufzeit ansehen, keineswegs in meine DB
schreiben.

Doch offenbar werden sie von irgendwoher wieder ueberschreiben, sobald
sich das Grid durch haendisches Scrollen neu schreibt.

Also eine Aktualisierung muss unterbunden werden.
Doch welche und wie?

Ich moechte auch kein Event benutzen, das ununterbrochen feuert.
Sondern das Grid soll sich auf Menue-Befehl via DB und nachfolgende
Iteration fuer die nicht DB-Felder aktualisieren und danach "statisch"
bleiben.


Nicole
Joe Galinke
2011-03-02 16:12:00 UTC
Permalink
Hallo Nicole,
Post by Nicole Wagner
Ich aendere keine DB-generierten-Felder.
Was sind Db-generierte Felder?
Post by Nicole Wagner
Dataset.FieldByName('Nr').Value:=1;
Natürlich wurde vorher, explizit oder implizit, die Datenmenge in den
Edit-Modus versetzt. Aber das kennst du doch.

Einfach mit
Dataset.Open;
Dataset.FieldByName(Bal').As.. := Blub

erntest Du eine Exception.


Wenn du aber schreibst, Du änderst mit
Dataset.FieldByName('Nr').Value:=...,
dann verstehe ich Deine ursprüngliche Aussage
| Ich habe ein DBGrid, ueber das ich iteriere und in dessen Spalten ich
| Rechenwerte eintrage.

nicht.
Post by Nicole Wagner
Diese Werte werden auch wunschgemaess in mein Grid eingetragen. Dort
will ich sie lediglich zur Laufzeit ansehen, keineswegs in meine DB
schreiben.
Oder ich verstand Dich doch richtig.
Dann brauchst Du ein TClientDataSet oder eine Memorytabelle. Hier verwenden
wir sehr gerne TkbmMemtable.
(http://www.components4programmers.com/products/kbmmemtable/download/index.htm)

Eine Tabelle nur im Speicher kann in vielerlei Hinsicht sehr praktisch
sein.
Post by Nicole Wagner
Doch offenbar werden sie von irgendwoher wieder ueberschreiben, sobald
sich das Grid durch haendisches Scrollen neu schreibt.
Zum 3. Mal: Schreib nicht ins Grid.
Dein Ansatz ist falsch.


Gruß, Joe
--
Nicole Wagner
2011-03-02 16:42:15 UTC
Permalink
Post by Joe Galinke
Hallo Nicole,
Post by Nicole Wagner
Ich aendere keine DB-generierten-Felder.
Was sind Db-generierte Felder?
in meinem DBGrid gibt es 2 Arten von Feldern:
Solche, die mit der Query verbunden sind (nenne ich DB-generiert) und
solche, die aus den Daten der vorhandenen ausgefuellten Spalten
errechnet werden.

z.B. das Grid bildet die ersten 2 Spalten der Datenbank ab und
schreibt: Himbeer und Saft, Nicole presst daraus "Himbeersaft" und
schreibt es in die dritte Spalte.
Post by Joe Galinke
Eine Tabelle nur im Speicher kann in vielerlei Hinsicht sehr praktisch
sein.
Glaube ich Dir gerne und werde mir das Link aufheben.
Doch meine Werte stehen (leider nur temporaer) in den dafuer
vorgesehenen Spalten des DBGrid und genau dort will ich sie.
Post by Joe Galinke
Post by Nicole Wagner
Doch offenbar werden sie von irgendwoher wieder ueberschreiben,
sobald sich das Grid durch haendisches Scrollen neu schreibt.
Zum 3. Mal: Schreib nicht ins Grid.
Dein Ansatz ist falsch.
Rechtklicke auf eine Query, die zu einem DBGrid gehoert.
Rechtsklicke auf Feldeditor und danach auf Felder hinzufuegen.
Da oeffnet sich eine Maske, die in der Mitte die Option "errechnet" hat.
Wenn es falsch waere, damit zu arbeiten, waere sie nicht dort, denke
ich mal.

Irgendwo dort muss ich ansetzen und was abdrehen.
Weil ich aber noch nie zuvor mit diesen Dingen gearbeitet habe, weiss
ich nicht wo.

Vielleicht liege ich ja damit ganz falsch. Doch es sieht ausnahmsweise
mal richtig aus. Zumindest bis zum ersten Scrollen.


Nicole
Joe Galinke
2011-03-02 16:58:04 UTC
Permalink
Hallo Nicole,
Post by Nicole Wagner
Solche, die mit der Query verbunden sind (nenne ich DB-generiert) und
Das sind einfach Daten aus deiner Datenmenge. Punkt.
Post by Nicole Wagner
solche, die aus den Daten der vorhandenen ausgefuellten Spalten
errechnet werden.
Berechnete Felder.
Post by Nicole Wagner
Post by Joe Galinke
Eine Tabelle nur im Speicher kann in vielerlei Hinsicht sehr praktisch
sein.
Glaube ich Dir gerne und werde mir das Link aufheben.
Doch meine Werte stehen (leider nur temporaer) in den dafuer
vorgesehenen Spalten des DBGrid und genau dort will ich sie.
Nein. :-) D.h., Du willst sie dort anzeigen, aber auch nur das.

Das Grid zeigt sie nur an. Bitte, bitte, glaubs doch einfach. Du willst,
kannst und musst die darunter liegende Datenmenge ändern. Du willst es
nicht im konkreten Fall, dafür mag es Gründe geben.

Dann bleiben als praktikable Lösungen das TClientDataSet oder die
Memorytabelle, in welche die Du die Daten aus Deiner Datenmenge erst einmal
reinpumpen musst.

Du kannst natürlich in Deiner Datenbank auch eine neue temporäre Tabelle
mit diesen Daten anlegen.
Post by Nicole Wagner
Post by Joe Galinke
Zum 3. Mal: Schreib nicht ins Grid.
Dein Ansatz ist falsch.
Rechtklicke auf eine Query, die zu einem DBGrid gehoert.
Rechtsklicke auf Feldeditor und danach auf Felder hinzufuegen.
Da oeffnet sich eine Maske, die in der Mitte die Option "errechnet" hat.
Wenn es falsch waere, damit zu arbeiten, waere sie nicht dort, denke
ich mal.
Was hat das damit zu tun? Hier änderst Du an der Query, nicht irgendwas am
Grid.

Oder habe ich Dich falsch verstanden und Du willst nur die Daten in den
berechneten Feldern ändern? Mir schien sich die Anforderung gerade auf das
Ändern der nicht berechneten Felder zu beziehen.

Wenn es sich nur um die berechneten Felder handelt ist es immer noch der
falsche Ansatz die Daten im Grid zu ändern, dafür ist dann das Ereignis
OnCalcFields (o.s.ä.) Deines Datasets zuständig.

Gruß, Joe
--
Nicole Wagner
2011-03-03 11:01:56 UTC
Permalink
Post by Joe Galinke
Oder habe ich Dich falsch verstanden und Du willst nur die Daten in
den berechneten Feldern ändern?
So ist es.
Stell es Dir bitte vor, wie einen Einkaufszettel.

Meine Daten sind mein Hausrat = nicht berechnete Felder.
Einiges in der Grid-Anzeige ist der Einkaufszettel = berechnete Felder.

Ich kaufe damit ein und werfe den Zettel sofort weg.

Der "Einkauf" erfolgt in einer anderen Maske, die in die DB schreibt,
was ich von meinem "Notizzettel" ablese, haendisch bearbeite und
selektiere. Der Einkaufsvorgang ist hier nicht mein Thema.
Post by Joe Galinke
Mir schien sich die Anforderung
gerade auf das Ändern der nicht berechneten Felder zu beziehen.
noe, soviel habe sogar ich verstanden.
Die sind ja meine DB. Die moechte ich um Gottes Willen nicht mit jedem
Mausklick beschaedigen.
Post by Joe Galinke
Wenn es sich nur um die berechneten Felder handelt ist es immer noch
der falsche Ansatz die Daten im Grid zu ändern, dafür ist dann das
Ereignis OnCalcFields (o.s.ä.) Deines Datasets zuständig.
siehe anderes Posting.
Mit dem Ereignis kaempfe ich.


Nicole
Joe Galinke
2011-03-03 12:24:35 UTC
Permalink
Hallo Nicole,
Post by Nicole Wagner
Post by Joe Galinke
Oder habe ich Dich falsch verstanden und Du willst nur die Daten in
den berechneten Feldern ändern?
So ist es.
Was erzählst Du dann vom Grid? Das hat damit genau nichts zu tun oder
höchstens so viel wie ein schlichter Ausdruck Deiner Daten
Post by Nicole Wagner
Stell es Dir bitte vor, wie einen Einkaufszettel.
[ Snip ]

Ich weiß sehr wohl was berechnete Felder sind, Deine Erklärung verstehe ich
nicht.
Post by Nicole Wagner
noe, soviel habe sogar ich verstanden.
Die sind ja meine DB. Die moechte ich um Gottes Willen nicht mit jedem
Mausklick beschaedigen.
Post by Joe Galinke
Wenn es sich nur um die berechneten Felder handelt ist es immer noch
der falsche Ansatz die Daten im Grid zu ändern, dafür ist dann das
Ereignis OnCalcFields (o.s.ä.) Deines Datasets zuständig.
siehe anderes Posting.
Mit dem Ereignis kaempfe ich.
Dann zeige, wie Dich auch Burkhard schon gebeten hat, Code.
Zeige Deinen Code aus OnCalcFields und wie Du die Daten veränderst.

Hier mal ein schlichtes Einsatzbeispiel für OnCalcFields:

Du hast eine Tabelle mit Wägungsdaten von Fahrzeugen, darin enthalten der
Wert der Leerwägung (Tara) und der Vollwägung (Brutto). Kein Netto? Nein,
das ergibt sich ja aus der Differenz, muss als nicht in der Tabelle
gespeichert werden. Aber der Anwender will diesen Wert sehen.
Du legst ein berechnetes Feld "Netto" an und machst im OnCalcFields des
Datasets nur:

DataSet.FieldByName('Netto').AsInteger :=
DataSet.FieldByName('Brutto').AsInteger -
DataSet.FieldByName('Tara').AsInteger


Auf keinen Fall iteriere ich in dem Event über die Datenmenge.

Vielleicht beschreibst Du mal was Du möchtest, aber bitte nicht mit
Einkaufszetteln. Vielleicht ist der Ansatz mit OnCalcFields gar nicht der
Geeignete.


Gruß, Joe
--
Burkhard Schneider
2011-03-03 07:42:20 UTC
Permalink
Post by Nicole Wagner
Rechtklicke auf eine Query, die zu einem DBGrid gehoert.
Rechtsklicke auf Feldeditor und danach auf Felder hinzufuegen.
Da oeffnet sich eine Maske, die in der Mitte die Option "errechnet" hat.
Hallo Nicole,
das ist doch wahrscheinlich das DBGrid mit den berechneten Feldern, das wir
in einem anderen Thread bereits ausführlich durchgekaut haben oder?

Ich versuche jetzt mal, aus deinen Postings zusammenzutragen, was du da
machst. (Zitate natürlich ordentlich gekennzeichnet ;-) )
Post by Nicole Wagner
Rechtklicke auf eine Query, die zu einem DBGrid gehoert.
Rechtsklicke auf Feldeditor und danach auf Felder hinzufuegen.
Da oeffnet sich eine Maske, die in der Mitte die Option "errechnet" hat.
Also berechnete Felder. Das ist doch erstmal OK. Damit sollte aber das von
dir beschreibene Problem (Inhalte nach Scrollen weg) nicht auftreten.
Post by Nicole Wagner
Ich aendere keine DB-generierten-Felder.
Dataset.FieldByName('Nr').Value:=1;
Das steht in OnCalcFields, nehme ich an? Deshalb hast du auch kein Edit,
weil die Datenmenge an dieser Stelle implizit im Editmodus ist.
Post by Nicole Wagner
Ich moechte auch kein Event benutzen, das ununterbrochen feuert.
Das hat was von "wasch mich, aber mach mich nicht nass". Wenn du mit
berechneten Feldern arbeitest, muss du diese in OnCalcFields mit Inhalten
füllen, und das ist ein Event, der irgendwann feuert, wenn die Daten
benötigt werden.
Post by Nicole Wagner
Ich habe ein DBGrid, ueber das ich iteriere und in dessen Spalten ich
Rechenwerte eintrage.
Das hat mich stutzig gemacht. Wo iterierst du da? Doch nicht etwa in
OnCalcFields. Du musst überhaupt nichts iterieren, sondern einfach in
OnCalcFields die errechneten Werte zuweisen. Zeig doch mal ein bischen Code.


Gruß
Burkhard Schneider
Nicole Wagner
2011-03-03 10:50:35 UTC
Permalink
Post by Joe Galinke
Hallo Nicole,
das ist doch wahrscheinlich das DBGrid mit den berechneten Feldern,
das wir in einem anderen Thread bereits ausführlich durchgekaut haben
oder?
ja klar.
Ich habe alle meine Felder gelöscht und neu angelegt.
Klappte wunderbar und auch schnell.

Den Spalteneditor habe ich weder angegriffen, noch ging er mir ab dabei.
Post by Joe Galinke
Post by Nicole Wagner
Ich habe ein DBGrid, ueber das ich iteriere und in dessen Spalten
ich Rechenwerte eintrage.
Das hat mich stutzig gemacht. Wo iterierst du da? Doch nicht etwa in
OnCalcFields. Du musst überhaupt nichts iterieren, sondern einfach in
OnCalcFields die errechneten Werte zuweisen. Zeig doch mal ein
bischen Code.
Ich habe das Problem, dass meine Rechenoperation ein paar Sekunden
dauert. Den Code dazu willst Du nicht wirklich sehen, ;-)
In kurzen Worten: Ich schicke meine Grid-Zellen-Information an eine
andere Unit und die schickt Informationen zurueck.

Die Felder wurden im OnCalcEvent zu oft "refreshed". Jetzt habe ich
versucht, das dort wieder rauszunehmen. Offenbar habe ich etwas falsch
gemacht.

Weisst Du vielleicht, wann genau und wodurch das Event aufgerufen wird?
Jedes Grid-Create, jedes Grid-Neu-Zeichnen fuer jede Zelle wieder
oder...?

Ich braeuchte etwas, das nur auf benutzer-Eingabe aktualisiert.

Was mir wirklich helfen wuerde, waere eine systematische Dokumentation
der Events. Wenn ich hingegen in der Hilfe lese: "Ein Rechen-Event ist
ein Event, das rechnet", dann wuerde ich gerne den Autor solchen
mir-die-Zeit-stehlenden Unfugs erwuergen.


Nicole
Burkhard Schneider
2011-03-03 11:53:57 UTC
Permalink
Post by Nicole Wagner
Ich habe das Problem, dass meine Rechenoperation ein paar Sekunden
dauert. Den Code dazu willst Du nicht wirklich sehen, ;-)
Deinen Rechen-Code will ich natürlich nicht sehen, aber den Code, wo du die
Werte den berechneten Feldern zuweist.
Post by Nicole Wagner
In kurzen Worten: Ich schicke meine Grid-Zellen-Information an eine
andere Unit und die schickt Informationen zurueck.
Die Felder wurden im OnCalcEvent zu oft "refreshed". Jetzt habe ich
versucht, das dort wieder rauszunehmen. Offenbar habe ich etwas falsch
gemacht.
In einem solchen Fall würde ich zuerst alle Werte berechnen und irgendwo
zwischenspeichern, und zwar noch bevor das Grid angezeigt wird. (Oder mit
DisableControls abklemmen) In OnCalcField greifst du dann nur noch auf den
gespeicherten Wert zu.

Alternative wäre die von Joe vorgeschlagende Memorytabelle. Die würde zuerst
alle Felder aus der Query laden und in einem zweiten Schritt über alle
Datensätze iteriren und das Feld mit den berechneten Werte füllen. Dieses
wäre dann aber kein "berechnetes Feld" mehr sondern ein normales Datenfeld
der Memorytabelle.
Post by Nicole Wagner
Weisst Du vielleicht, wann genau und wodurch das Event aufgerufen wird?
Jedes Grid-Create, jedes Grid-Neu-Zeichnen fuer jede Zelle wieder
oder...?
Das weiß ich nicht genau, ist aber ziemlich häufig. Wenn dann darin Code mit
einer langen Laufzeit aufgerufen wird, kann es schon problematisch werden.

Gruß
Burkhard Schneider
Joe Galinke
2011-03-03 12:33:18 UTC
Permalink
Hallo Nicole,
Post by Nicole Wagner
Weisst Du vielleicht, wann genau und wodurch das Event aufgerufen wird?
Jedes Grid-Create, jedes Grid-Neu-Zeichnen fuer jede Zelle wieder
Wenn das Grid erzeugt wird kennt es keine Daten und liest also auch nicht
aus der Datenmenge mit der es über TDatasource verbunden ist. Beim Scrollen
im Grid wird natürlich immer wieder neu gelesen.

Hast Du in der Hilfe nachgesehen? Dort steht es drin wann OnCalcFields
feuert.
Post by Nicole Wagner
Ich braeuchte etwas, das nur auf benutzer-Eingabe aktualisiert.
Auch das klingt so, als bräuchtest Du nicht OnCalcFields, sondern
vielleicht doch die Memorytabelle. Aber noch kann ich hier nur raten.


Gruß, Joe
--
Günter Kieninger
2011-03-03 14:08:25 UTC
Permalink
Post by Nicole Wagner
Die Felder wurden im OnCalcEvent zu oft "refreshed". Jetzt habe ich
versucht, das dort wieder rauszunehmen. Offenbar habe ich etwas falsch
gemacht.
Das ist der Nachteil von calculierten Feldern. Die werden nicht einmal
berechnet und dann immer wieder hergenommen sondern jedesmal neu
berechnet.
Was bei einem

Wert := Menge * Preis;

wurscht ist aber bei einem

Wert := KomplizierteLangeFunction;

nicht.

Also hör auf Joe und nimm eine Memtable (kbmMemTable zB), lade deine
Query in die Table, rechne in der Memtable was zu rechnen ist und dann
ist es erledigt.

Gruß aus den Bergen
Günter
Thomas G. Liesner
2011-03-03 14:13:24 UTC
Permalink
Post by Nicole Wagner
Ich habe das Problem, dass meine Rechenoperation ein paar Sekunden
dauert.
Also brauchst du einen Cache für die Rechenergebnisse. Also eine
Zwischenfunktion, die einen Key auf Basis der Rechenkriterien berechnet,
im Cache auf dessen Existenz prüft und im Erfolgsfall den gepufferten
Wert zurückliefert oder ihn ansonsten berechnet, in den Cache schreibt
und als Ergebnis zurückliefert.

Die Details der Implementierung hängen im wesentlichen davon ab, an
welchen Daten die Berechnung hängt und unter welchen Umständen eine
Neuberechnung auch für schon gepufferte Werte nötig werden könnte.

Ob der Cache dann eine simple Stringlist mit Strings[i] für den Key und
Objects[i] für ein Miniobjekt mit dem Ergebnis ist oder was
Aufwendigeres, ist dann ein Implementierungsdetail.
Post by Nicole Wagner
Weisst Du vielleicht, wann genau und wodurch das Event aufgerufen wird?
Jedes Grid-Create, jedes Grid-Neu-Zeichnen fuer jede Zelle wieder
oder...?
Wohl immer dann, wenn er die entsprechende Grid-Zelle neu malen muss -
einen internen Cache für die Werte dürfte er nicht haben.
Post by Nicole Wagner
Ich braeuchte etwas, das nur auf benutzer-Eingabe aktualisiert.
Der Zusammenhang zwischen einer Benutzereingabe und komplexen
berechneten Feldern wird auch noch nicht deutlich.
Post by Nicole Wagner
Was mir wirklich helfen wuerde, waere eine systematische Dokumentation
der Events.
Ich neige in solchen Fällen dazu, den Quellcode der entsprechenden
Komponente anzulesen. Wobei die Hilfe zu Delphi 2 bis 7-Zeiten noch
deutlich besser war, auch wenn der Trend wieder positiv sein soll.

So long,
Thomas G. Liesner
Nicole Wagner
2011-03-07 15:03:48 UTC
Permalink
Hallo Leute,


mein Problem ist geloest, so halbwegs halt.
Dafuer waren 3 Dinge ausschlaggegend.

1) in der IBQuery ist die Eigenschaft AutoCalcFields auf false zu setzen

2) ich habe endlich eine Hilfe gefunden, die aussagekraeftig ist und
bei der nicht gegen Ende die Links immer duenner gesaeht sind, weil
noch nicht fertiggestellt. Man setze einfach ein "wiki" hinter die alte
Doc-Adresse.

hier ist sie:
http://docwiki.embarcadero.com/RADStudio/en/Main_Page

Sie baut auf die Delphi 7 Hilfe auf und ist fuer XE geschrieben.
Dort endlich fand ich die Erklaerungen, die mir z.B. die Sache mit dem
Property erklaerten.

3) und last noch least: Die Komponenten sind buggy. Nach einer
Aenderung zeigte meine IBQuery beharrlich in einem Bereich auf eine
alte Datasource. Ich brachte sie nicht heraus und fand die Property
auch nirgens. Und ich musste erst mal herausfinden, dass ich 2
Datasources "drin" hatte.
Endlich habe ich die "falsche" DataSource einfach geloescht und das
Formular im relevanten Teilbereich neu aufgesetzt. Dann ging es.
Hierin lag es vermutlich, dass meine Eingaben "nachträglich
verschwanden" und auch Disable Controls wirkungslos blieb.

Auch der Feldeditor ist buggy. Etwa nach einem Veraendern der
Feldreihendfolge mit der Maus wurden properties "verwurzt". Das aber
nur am Rande, falls jemand mal hier nachliest: Im Zweifel die
Reihenfolgen lieber im Spalteneditor aendern.


Nicole

Loading...