Editieren/Korrigieren einer Zelle im DBGrid
-
Hallo
Nach dem Laden der Datenbank kann ich in einem DBGrid auf die Einträge (AnsiString) einer Datenbanktabelle zugreifen.
Die Einträge sind stark vereinfacht wie folgt aufgebaut CCC999999 (C=alphanumerisch, 9=numerisch). Um das beizubehalten soll der Editiervorgang im DBGrid überwacht werden. Hierzu verwende ich die Ereignisse DataSet::BeforeEdit, bzw. DataSet::BeforePost.
Bei DataSet::BeforeEdit greife ich den Eintrag der gerade angeklickten Zelle mit DBGrid->SelectedField->AsString ab und speichere ihn als tempStr im private Bereich der TForm1 ab.
Beim Ereignis DataSet::BeforePost prüfe ich mit einer Funktion EingabeOk ob der editierte veränderte AnsiString der gewünschten Form entspricht.
Wenn der Eintrag nicht dem vorgegebenen Schema entspricht, soll er durch Rückspeichern von tempStr überschrieben werden und der alte Zustand wieder hergestellt werden.Das Zurückspeichern klappt. Wenn ich aber dann vom Editiermodus "I" umschalte, z.B. indem ich auf eine andere Zelle klicke, bekomme ich folgende Exception:
EOle Exception "Die zum Aktualisieren angegebene Zeile wurde nicht gefunden. Einige Werte wurden seit dem letzten Lesen ggf geändert"
Was mache ich falsch? Gibt's vielleicht noch eine bessere Möglichkeit als das, was ich beschreibe?

// Zellinhalt zwischenspeichern void __fastcall TForm1::ADODataSet1BeforeEdit(TDataSet *DataSet){ tempStr = DBGrid1->SelectedField->AsString; } //Zurückspeichern void __fastcall TForm1::ADODataSet1BeforePost(TDataSet *DataSet){ if (!EingabeOk(DBGrid1->SelectedField->AsString)){ DBGrid1->SelectedField->AsString = tempStr; Abort(); } }
-
Hat die Tabelle auf der du zugreifst einen primären Schlüssel?
falls nicht erstelle mal einen.
-
Hallo @VergissEs
Die Tabelle hatte keinen Primärschlüssel.
Also habe ich auf deinen Vorschlag hin den in meiner MySQL-Tabelle eingefügt und das Ganze nochmal laufen lassen. Leider auch dann ohne Erfolg.Ich habe in der ADODataSet1BeforePost mit dem Debugger einen Breakpoint gesetzt. Die Exception tritt erst auf, wenn die Routine verlassen wird.
Gibt's noch weitere Tipps? Oder komme ich um die Exception nicht herum?
void __fastcall TForm1::ADODataSet1BeforePost(TDataSet *DataSet){ if (!EingabeOk(DBGrid1->SelectedField->AsString)){ DBGrid1->SelectedField->AsString = tempStr; Abort(); // ==>Breakpoint, okay, F8 } // ==>okay, F8 } // ==>okay, F8 // ==>Exception (s. oben)
-
Was soll die Funktion Abort() dort?
-
Hallo @Th,
ich habe Abort() deshalb genommen, weil ich in einem Beispiel aus der BCB-Hilfe folgendes gefunden habe:*In diesem Beispiel wird geprüft, ob ein TDBEdit-Steuerelement einen gültigen Eintrag enthält. Ist das Steuerelement leer, wird die Prozedur Abort aufgerufen, um das Eintragen zu verhindern.
void __fastcall TForm1::Table1BeforePost(TDataSet *DataSet)
{
if (DBEdit1->Text == "")
Abort();
}*Wie man sieht, besteht zwischen meinem Konstrukt und diesem Beispiel eine große Ähnlichkeit
, demzufolge kann das auch sicher nicht so verkehrt sein.
Also so wie ich das sehe, liegt mein Fehler irgendwo in der Zuweisung beiDBGrid1->SelectedField->AsString = tempStr;Ich denke, dass hier etwas faul ist. Allerdings wüßte ich nicht, wie ich sonst der falsch bearbeiteten Zelle den alten Wert zurückgeben könnte?

-
Normalerweise wird die Methode Cancel() verwendet, um die geänderten Werte zu verwerfen und in den Browse-Modus zurückzukehren.
Ok, Abort() ist richtig, da es die Exception EAbort wirft.Was passiert denn, wenn du nur folgendes benutzt?
void __fastcall TForm1::ADODataSet1BeforePost(TDataSet *DataSet) { if (!EingabeOk(DBGrid1->SelectedField->AsString)) { Abort(); } }
-
Hallo @Th,
vielen Dank für Deine Hilfestellung, habe Deinen Rat befolgt und 'mal alles rauskommentiert, was geht:void __fastcall TForm1::ADODataSet1BeforePost(TDataSet *DataSet){ if (!EingabeOk(DBGrid1->SelectedField->AsString)){ }; //funktioniert, klar weil Compiler diese Passage löscht if (!EingabeOk(DBGrid1->SelectedField->AsString)){ Abort(); //bleibt im Editiermodus in der falsch formatierten Zelle hängen u stürzt mit Exception ab, wenn das Format richtig korrigiert ist }; //"Die zum Aktualisieren angegebene Zeile wurde nicht gefunden. Einige Werte wurden seit dem letzten Lesen ggf geändert" if (!EingabeOk(DBGrid1->SelectedField->AsString)){ ADODataSet1->Cancel(); //s. unten }; }Leider funktioniert auch Cancel() nicht richtig.

Wenn ich in meinem DBGrid eine Zelle so editiere, dass die Eingabeform falsch ist, speichert die Funktion Cancel() den alten Wert zurück.
Soweit so gut. Leider speichert sie diesen Wert nicht nur 1x sondern 2x zurück.
Das Ganze sieht dann in etwa so aus:
Zelle vorher:
CCC9999
dann Zelle absichtlich falsch formatiert
CCC9999§§§So sieht das DBGrid nach Korrektur durch Cancel() aus:
..
CCC9999 (erster Eintrag) <--Zeilenposition der ursprünglichen Zelle
CCC5654
CCC1234
..
CCC9999 (zweiter Eintrag) <--letzte Zeile im Grid
-
Hallo Leute, komme gerade hier ins Forum rein und sehe Eure tumultartig rege Anteilnahme an meinem superspannenden Thread! Erinnert mich ein bißchen ans Schweigen im Walde.

Naja es sei nochmals verziehn, ich schieb's 'mal auf die derzeit lähmende Hitze :D, bei der man doch sicher was anderes macht als nur am Computer rumhocken.Und weil ich trotzdem so ein netter Kerl bin, wollte ich Euch die Lösung, die ich eigentlich von Euch erwartet hätte, nicht vorenthalten
:void __fastcall TForm1::ADODataSet1BeforePost(TDataSet *DataSet){ if (!EingabeOk(DBGrid1->SelectedField->AsString)){ ADODataSet1->Cancel(); Abort(); }; }Fazit:
Das Zurückschreiben in die Zelle mitDBGrid1->SelectedField->AsString = tempStr;klappt definitiv nicht. Die dabei auftretende Exception kriege ich einfach nicht los.
die Lösung von @Th nur mit Cancel() zu arbeitern, klappt in BeforePost() deshalb nicht, weil Cancel() zum 1. Mal den Inhalt in die Zelle schreibt und dann BeforePost() ein 2.Mal in eine weitere Zelle.
Demzufolge muß die Lösung sein mit Cancel() den Eintrag zurückzuschreiben und mit Abort() vorzeitig aus der Routine auszusteigen, damit nicht nochmals ein weiterer Eintrag erfolgt.