AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Lazarus (IDE) Float und Integer in TDBGrid validieren
Thema durchsuchen
Ansicht
Themen-Optionen

Float und Integer in TDBGrid validieren

Ein Thema von Oniessen · begonnen am 1. Mär 2018 · letzter Beitrag vom 9. Mär 2018
Antwort Antwort
Seite 1 von 2  1 2      
Oniessen

Registriert seit: 17. Feb 2010
18 Beiträge
 
#1

Float und Integer in TDBGrid validieren

  Alt 1. Mär 2018, 09:24
Hallo zusammen!

Ich habe nun ein Problem, welches möglicherweise einige haben, nämlich , das es möglich ist in eine numerische Zelle eines TDBGrid folgenden Unsinn zu schreiben:

'-56-5,33,6'

Also das minus und Komma(und punkt) mehrfach einzutippen.
(Buchstaben und sonstige Zeichen werden schon gefiltert, aber die Mehrfacheingabe halt nicht )

Dann kracht es logischerweise bei der Übergabe an die DataSource.
Wie und wo kann ich das bei einem TDBGrid (Lazarus,FPC) abfangen?

So wirklich habe ich noch keine Stelle gefunden, zumal es scheint, das, je nach Ereignis, das gesamte Grid geprüft wird ;-(
Mir würde sogar reichen, wenn erst mal nach dem eintippen geprüft und Unsinn einfach komplett gelöscht wird.(evtl. mit Meldung)

Für normale Edits und StringGrids hatte ich das ja mal vor einigen Jahren heraus gefunden, aber bei dem TDBgrid steh ich Grad auf dem Schlauch, zumal ich die Zelle ja nicht ganz so einfach ansprechen kann...

Vielen Dank, Gruß, Oliver
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.490 Beiträge
 
Delphi 7 Professional
 
#2

AW: Float und Integer in TDBGrid validieren

  Alt 1. Mär 2018, 10:12
Noch nicht ausprobiert, Ereignis OnDBGrid1DrawColumnCell?

Ganz grobe Idee für das Prinzip:
Delphi-Quellcode:
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  Try
    StrToInt(Column.Field.AsString);
  except
    Column.Field.AsString := 'Bitte keinen Mist eingeben';
  end;
end;
Natürlich sollte die Fehlermeldung zielführend sein und man muss prüfen, in welcher Spalte (DataCol) man sich befindet, da die Prüfung ja ggfls. abhängig von der geänderten Spalte sein kann.

Über Column.Field.DataType kann man auch abfragen, von welchem Typ die gerade dargestellte Spalte ist und kann dann entsprechend reagieren.

In Column.Field.FieldName bekommt man den Spaltennamen des Wertes.

Wann genau das Ereignis aufgerufen wird, hab' ich nicht nachgeschaut. Es kann aber sein, dass die Prüfungen sehr oft ausgeführt werden. Ob das Ereignis für eine Plausibilitätsprüfung wirklich sinnvoll einzusetzen ist, wage ich daher eher zu bezweifeln.

Dann gäbe es eventuell noch das Ereignis OnDataSourceDataChange zur dem TDBGrid zugewiesenen TDataSource:
Delphi-Quellcode:
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  Try
    StrToInt(Field.AsString);
  except
    Field.AsString := 'Bitte keinen Mist eingeben';
  end;
end;
Nächste Möglichkeit wäre das Ereignis OnBeforePost der TDataSet-Komponente, die der DataSource-Eigenschaft des TDBGrid zugewiesen wurde:
Delphi-Quellcode:
procedure TForm1.DataSetKomponenteBeforePost(DataSet: TDataSet);
begin
  Try
    StrToInt(DataSet.FieldByName('ZuPruefendeSpalte').AsString);
  except
    DataSet.FieldByName('ZuPruefendeSpalte').AsString := 'Bitte keinen Mist eingeben';
    // oder mit
    DataSet.Cancel;
    // das Speichern abbrechen.
  end;
end;
Musst halt mal ausprobieren, ob da ein für Dich sinnvoller und brauchbarer Ansatz bei sein könnte.
  Mit Zitat antworten Zitat
Oniessen

Registriert seit: 17. Feb 2010
18 Beiträge
 
#3

AW: Float und Integer in TDBGrid validieren

  Alt 2. Mär 2018, 10:42
Hallo Delphi.Narium

Vielen Dank für deine Antworten und Anregungen!

Die Möglichkeit den Datentyp abzufragen ist auch ein sehr guter Tipp, denn ich habe neben Flots auch Strings und Boolean in der Tabelle. Dann kann ich alles an einer Stelle machen.

Leider hat mein TDBGrid unter Lazarus nur eine ColumnS Eigenschaft und da gibts leider kein .Field.DataType

Als Stelle hatte ich bislang auch an "TDBGrid.OnEditingDone" gedacht.

Insofern muß ich vielleicht wirklich auf das Dataset ausweichen. in meinem Fall ein BufDataSet



Also irgendwie funktioniert das alles noch nicht so ganz bzw. ich dreh mich im Kreis

Trotzdem vielen Dank, hast mir insofern schon geholfen, als das es ja mehrere stellen gibt, an denen ich angreifen könnte

Mit OnDBGrid1DrawColumnCel lande ich übrigens in einer art Endlosschleife


Gruß,Oliver
  Mit Zitat antworten Zitat
Oniessen

Registriert seit: 17. Feb 2010
18 Beiträge
 
#4

AW: Float und Integer in TDBGrid validieren

  Alt 6. Mär 2018, 10:37
Hallo!

Ich habe jetzt eine "halbe Lösung"

Folgendes funktioniert schon mal für das minus und alle anderen Zeichen:

Delphi-Quellcode:
procedure TMyForm.MyDBGridKeyPress(Sender: TObject; var Key: char);
  var
  CellText:Widestring;
  selStart : integer;
  cellRow, cellCol : integer;
  MyDecSep : Char;
  MyGrid : TStringGrid;
  begin
    // First some exessive Typecasting to access the position
    MyGrid := TStringGrid(Sender as TDBGrid);
    MyDecSep:= DefaultFormatSettings.DecimalSeparator;

    if TStringCellEditor(MyGrid.Editor).SelLength > 0 then
       TStringCellEditor(MyGrid.Editor).SelText:= '';

    cellRow:= (MyGrid).Row;
    cellCol:= (MyGrid).Col;
    CellText:= (MyGrid).Cells[cellCol,cellRow];
    // exessive Typecasting to access SelStart
    selStart:= TStringCellEditor(MyGrid.Editor).SelStart ;

    // #8 = Backspace; #0 = empty key ;
    if not (Key in [#8, '0'..'9', '-', MyDecSep]) then Key := #0

    else if ((Key = MyDecSep) or (Key = '-'))
             and (Pos(Key, CellText) > 0) then Key := #0

    else if (Key = '-') and (selStart <> 0) then Key := #0;
  end;
Nur leider nicht für das Komma

Das lässt sich immer noch mehrfach eintippen...
Ich hab es auch schon mit ',' oder #44 versucht, aber irgendwie will das nicht funktionieren

Irgendeine Idee??

Gruß, Oliver


PS:
So komme ich übrigens doch an den DataType
Delphi-Quellcode:
...
 if (sender as TDBGrid).SelectedColumn.Field.DataType = ftfloat then
...

Geändert von Oniessen ( 6. Mär 2018 um 10:43 Uhr) Grund: PS hinzu
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#5

AW: Float und Integer in TDBGrid validieren

  Alt 6. Mär 2018, 10:41
Zitat:
Delphi-Quellcode:
  Try
    StrToInt(Column.Field.AsString);
  except
    Column.Field.AsString := 'Bitte keinen Mist eingeben';
  end;
Bitte nicht so einen Mist.

Der arme Typ am Debugger kommt sonst und erwürgt dich.
Delphi-Referenz durchsuchenTryStrToInt oder Delphi-Referenz durchsuchenStrToIntDef
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.490 Beiträge
 
Delphi 7 Professional
 
#6

AW: Float und Integer in TDBGrid validieren

  Alt 6. Mär 2018, 11:42
Zitat:
Delphi-Quellcode:
  Try
    StrToInt(Column.Field.AsString);
  except
    Column.Field.AsString := 'Bitte keinen Mist eingeben';
  end;
Bitte nicht so einen Mist.

Der arme Typ am Debugger kommt sonst und erwürgt dich.
Delphi-Referenz durchsuchenTryStrToInt oder Delphi-Referenz durchsuchenStrToIntDef
Das Beispiel war dahingehend gedacht:

Bau da bitte gefälligst eine vernünftige Fehlerbehandlung ein, aber niemals: Mach das genau so

Es sollte doch klar sein, dass man bei der Prüfung eines nummerischen Wertes, diesen im Fehlerfalle keinesfalls mit einem Text befüllt. Da kann man doch nur scheitern.

Bezüglich Dezimaltrenner:

Was steht in DefaultFormatSettings.DecimalSeparator und was wird eingegeben?

Stimmen Eingabe, Anzeige und DefaultFormatSettings.DecimalSeparator überein oder wird das "intern" bereits übersetzt?

Was soll hiermit erreicht werden, irgendwie verstehe ich es nicht:
Delphi-Quellcode:
 // #8 = Backspace; #0 = empty key ;
    if not (Key in [#8, '0'..'9', '-', MyDecSep]) then Key := #0

    else if ((Key = MyDecSep) or (Key = '-'))
             and (Pos(Key, CellText) > 0) then Key := #0

    else if (Key = '-') and (selStart <> 0) then Key := #0;
SetText wird vorher auf '' gesetzt. SelStart kann daher nur noch 0 sein, ebenso SelLength. Wann soll dann diese Bedingung erfüllt sein (selStart <> 0) ?
Wenn bei not key in auf - abgefragt wird und der - gefunden wird, wie soll dann im Else die Abfrage auf Key = '-' funktionieren?

Wie wäre es mit einem Ansatz in diese Richtung, statt If-Else-Kaskade per Case?
Delphi-Quellcode:
Case key of
  // zuerst mal alles das, was in Ordnung ist: (if not key in ...)
  #8 : ;
  '0'..'9' : ;
  '-' : ;
  ...
  // und dann das, was geändert oder verworfen werden muss.
else
  // die erste Else aus dem If bekommen wir hier schon nichtmehr
  // abgebildet, da vorher ja '-' und MyDecSep schon verarbeitet wurden.
  // In der zweiten Else wäre es eher unwahrscheinlich, dass sie
  // noch jemals zum Tragen kommt. '-' wurde vorher schon verarbeitet
  // und SelStart dürfte kaum jemals <> 0 sein.
end;
Eventuell eher so in der Art:
Delphi-Quellcode:
Case key of
  // zuerst mal alles das, was in Ordnung ist: (if not key in ...)
  #8 : ;
  '0'..'9' : ;
  '-' : ;
  ... // hier noch Dezimalseparator und ggfls. Tausendertrenner einfügen
  ... // und dann das, was geändert werden muss (wenn's sowas geben sollte).
else
  key := #0; // Alles andere wird verworfen.
end;
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
970 Beiträge
 
Delphi 6 Professional
 
#7

AW: Float und Integer in TDBGrid validieren

  Alt 6. Mär 2018, 11:53
Hmm..

ab hier gerade kein Lazarus, jedoch habe ich deine Prüfroutine mal anders Formuliert:

Delphi-Quellcode:
    if Key in['0'..'9',#8,'-',MyDecSep] then begin
      if Key = '-then if (selStart <> 0) then Key := #0; // '-' muss an erster Stelle sein (Wenn nicht mit 'E')
      if Key = MyDecSep then begin
        if (selStart = 0) // Nicht an erster Stelle
         or (Pos(Key, CellText) > 0) // Nicht schon vorhanden
         or ((Pos('-', CellText) > 0) and (selStart < 2)) // Nicht direkt nach einem '-'
          then Key := #0;
      end;
    end else Key := #0;
(Ungetestet...)
  Mit Zitat antworten Zitat
Oniessen

Registriert seit: 17. Feb 2010
18 Beiträge
 
#8

AW: Float und Integer in TDBGrid validieren

  Alt 6. Mär 2018, 20:04
Hallo Delphi.Narium

zu deinen Fragen:

mit
Delphi-Quellcode:
if TStringCellEditor(MyGrid.Editor).SelLength > 0 then
       TStringCellEditor(MyGrid.Editor).SelText:= '';
Unterbinde ich das einfügen meine ich mich zu erinnern-

ansonsten hat HolgerX ja schon recht gut kommentiert.

'-' minus muss immer am Anfang stehen und darf nur einmal vorkommen
',' das Dezimaltrennzeichen darf nur einmal vorkommen
und ansonsten nur ziffer-eingabe erlauben ( das könnte ich mir schenken, weil das schafFt das TDB grid schon alleine...)

(das Komma an erster Stelle oder hinter minus würde ich sogar erlauben, das funktioniert, wird als Float erkannt)


Der Decimalseparator stimmt. wie gesagt, auch mit ',' oder #44 geht es nicht bzw. multiple eingaben möglich

Der Fehler scheint hier zu liegen:
CellText:= (MyGrid).Cells[cellCol,cellRow]; Der momentane Inhalt wird nicht ausgelesen.

mit CellText:= (Sender as TDBGrid).SelectedColumn.Field.AsString; wird er zwar ausgelesen, klappt aber auch nicht, wie gewünscht

Gruß, Oliver
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.490 Beiträge
 
Delphi 7 Professional
 
#9

AW: Float und Integer in TDBGrid validieren

  Alt 6. Mär 2018, 20:53
Die Lösung mit den If-Abfragen dürfte hier den Ablauf deutlich verkomplizieren.

Versuch bitte eine Lösung mit Case zu finden, dann sind mehrere Bedingungen besser abzubilden.
Delphi-Quellcode:
Case key of
  // zuerst mal alles das, was in Ordnung ist:
  #8 : ; // Zurücktaste
  '0'..'9' : ; // die Ziffern
  // Beim - schauen, ob CellText noch leer ist, nur dann ist der - erlaubt.
  '-' : if Length(CellText) <> 0 then key := #0;
  // der MyDecSep darf nur einmal vorkommen.
  MyDecSep : if Pos(MyDecSep,CellText) <> 0 then key := #0;
else
  key := #0; // Alles andere wird verworfen.
end;
Hast Du momentan den Inhalt der zu prüfenden Spalte?

Wird das Ergebnis mit meinem Vorschlag besser?
  Mit Zitat antworten Zitat
Oniessen

Registriert seit: 17. Feb 2010
18 Beiträge
 
#10

AW: Float und Integer in TDBGrid validieren

  Alt 7. Mär 2018, 11:08
Hallo!

Hab den Fehler gefunden!
Vielen Dank für eure Hilfe!

Das Problem war, mit:
CellText:= (Sender as TDBGrid).SelectedColumn.Field.AsString; Bekam ich immer nur den "alten", im Grid gespeicherten Wert/String zurück.
Damit funktioniert das natürlich nicht.

Mit Änderung auf:
CellText:= TStringCellEditor(MyGrid.Editor).Text; Funktioniert es jetzt, da der wirkliche, aktualisierte "editor"-string zurück gegeben wird.

Die Case Version habe ich mal ausprobiert, finde sie jedoch auch nicht wirklich Übersichtlicher.
mit If else if habe ich insgesamt 4 zeilen (3 wenn ich das 'and' der 2. Bedingung noch in eine zeile Packe oder 6 etwas anders formatiert)
Mit Case habe ich min. 6 Zeilen...
Dazu kommt noch, das Case konstanten erwartet und ich dann den MyDecSep auch irgendwie verpacken muss

Vom Grundsatz her gebe ich dir allerdings vollkommen Recht, das Case meist eleganter ist!!!!
(Und ich habe gar nicht mehr dran gedacht, das das ja auch mit Chars geht)

Hier also mal (m)eine Version, die funktioniert:
Delphi-Quellcode:
procedure TMyForm.MyDBGridKeyPress(Sender: TObject; var Key: char);
var
  CellText: Widestring;
  selStart : integer;
  cellRow, cellCol : integer;
  MyGrid : TStringGrid;
  MyDecSep : Char;
begin

    // First some Typecasting to access the Cell Editor
    MyGrid := TStringGrid(Sender as TDBGrid);

    // to avoid copy/paste - no multiple Chars
    if TStringCellEditor(MyGrid.Editor).SelLength > 0 then
       TStringCellEditor(MyGrid.Editor).SelText:= '';

    // get the system-Decimal-Separator ',' or '.'
    MyDecSep := DefaultFormatSettings.DecimalSeparator;
    cellRow:= MyGrid.Row;
    cellCol:= MyGrid.Col;

    // Typecast to access SelStart and actual typed Text
    selStart:= TStringCellEditor(MyGrid.Editor).SelStart ;
    CellText:= TStringCellEditor(MyGrid.Editor).Text;

    // #8 = Backspace; #0 = empty key ;
    if not (Key in [#8, '0'..'9', '-', MyDecSep])
        then Key := #0
    // '-' minus and decimal separator only once
    else if ((Key = MyDecSep) or (Key = '-')) and (Pos(Key, CellText) > 0)
         then Key := #0
    // '-' minus always first character
    else if (Key = '-') and (selStart <> 0)
         then Key := #0;

 end;
---

Eine andere Sache noch:
Ich habe festgestellt, das leider die "OnEditingDone" Methode des TDBGrids nicht so funktioniert wie gedacht oder gehofft.
Es scheint, als würde sie erst aufgerufen, nachdem die Daten schon an die DataSource übergeben wurden.
Zumindest, wenn ich einfach nur eine " ShowMessage()" dort hinein setze, knallts bei Fehleingaben, bevor die Message überhaupt angezeigt wird
(bei korrekter Eingabe wird die Box angezeigt)

Könnte das ein Fehler der Implementierung sein oder doch Absicht?

Gruß, Oliver
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:25 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz