![]() |
Numerische Eingabe in Stinggrid validieren
Hallo!
Da ich da selbst jetzt 'ne halbe Ewigkeit danach gesucht habe, hier mal eine Lösung. Unter Lazarus haben die meisten anderen Lösungen leider nicht so richtig funktioniert. Die ersten beiden Bedingungen waren kein Problem, nur das '-' am Anfang war für mich ziemlich kniffelig (zumindest unter Lazarus). Vieleicht hilft der Code-Schnipsel ja einem Andern weniger als 2 Tage zu suchen... Gruß, Oliver
Delphi-Quellcode:
// Validates a Float-only input in a Cell of a TStringGrid
procedure TMyForm.MyGridKeyPress(Sender : TObject; var Key : char); var CellText:Widestring; selStart : integer; cellRow, cellCol : integer; begin cellRow:= (sender as TStringGrid).Row; cellCol:= (sender as TStringGrid).Col; CellText:= (sender as TStringGrid).Cells[cellCol,cellRow]; selStart:= TStringCellEditor(TStringGrid(Sender).Editor).SelStart ; // exessive Typecasting to access SelStart if not (Key in [#8, '0'..'9', '-', DecimalSeparator]) then Key := #0 else if ((Key = DecimalSeparator) or (Key = '-')) and (Pos(Key, CellText) > 0) then Key := #0 else if (Key = '-') and (selStart <> 0) then Key := #0; end; Der Volständigkeit halber hier noch die TEdit Lösung (die die meisten sicher schon kennen):
Delphi-Quellcode:
procedure TMyForm.MyEditKeyPress(Sender : TObject; var Key : char);
begin if not (Key in [#8, '0'..'9', '-', DecimalSeparator]) then Key := #0 else if ((Key = DecimalSeparator) or (Key = '-')) and (Pos(Key, (Sender as TEdit).Text) > 0) then Key := #0 else if (Key = '-') and ((Sender as TEdit).SelStart <> 0) then Key := #0; end; |
AW: Numerische Eingabe in Stinggrid validieren
Find ich gut, dass du das postest.
Ich würde mich über Kommentare im Quelltext sehr freuen. ;) |
AW: Numerische Eingabe in Stinggrid validieren
Ganz guter Kandidat wäre z.B. die magische 8. Die sollte man als benannte Konstante rausziehen. Denn dann muss niemand nachschlagen, was denn die 8 in einer ASCII-Tabelle ist (ich musste es grade).
|
AW: Numerische Eingabe in Stinggrid validieren
Gibts denn in Lazarus nicht wie in Delphi so vordefinierte Konstante ala VK_Back usw?
|
AW: Numerische Eingabe in Stinggrid validieren
Hallo nochmal!
Es ging mir ja eigentlich nur um die Besonderheit im TStringGrid. Die andere TEdit-Lösung findet sich recht schnell durch g**geln... und ich dachte eigentlich, das wäre schon recht klar soweit... Sicher gibts auch Konstanten in Lazarus. Ich denke aber fast, zum Verständniss ist der ASCII-code einfacher... Naja, hier noch mal die TEdit-Version mit Kommentaren:
Delphi-Quellcode:
procedure TMyForm.MyEditKeyPress(Sender : TObject; var Key : char);
begin if not (Key in [#8, '0'..'9', '-', DecimalSeparator]) then Key := #0 // #0 = empty Char/nullCharacter // only Keys 0-9(numeric), #8= Backspace, '-' and DecimalSeperator allowed else if ((Key = DecimalSeparator) or (Key = '-')) and (Pos(Key, (Sender as TEdit).Text) > 0) then Key := #0 // #0 = empty Char/nullCharacter // '-' and DecimalSeperator are only allowed once in the String-Input else if (Key = '-') and ((Sender as TEdit).SelStart <> 0) then Key := #0; // #0 = empty Char/nullCharacter // '-' is only allowed as first Character // SelStart is the Caret(Text-Curser) Position end; Den Typecast zur Veranschaulichung mal anders geschrieben: (ungetestet)
Delphi-Quellcode:
.
.. selStart:= TStringCellEditor(TStringGrid(Sender).Editor).SelStart ; // (((Sender as TStringGrid).Editor) as TStringCellEditor).SelStart .. . Gruß, Oliver |
AW: Numerische Eingabe in Stinggrid validieren
Zitat:
Delphi-Quellcode:
procedure TMyForm.MyEditKeyPress(Sender : TObject; var Key : char);
const KEY_NONE = #0; KEY_BACKSPACE = #8; begin if not (Key in [KEY_BACKSPACE, '0'..'9', '-', DecimalSeparator]) then Key := KEY_NONE else if ((Key = DecimalSeparator) or (Key = '-')) and (Pos(Key, (Sender as TEdit).Text) > 0) then Key := KEY_NONE else if (Key = '-') and ((Sender as TEdit).SelStart <> 0) then Key := KEY_NONE; // '-' is only allowed as first Character // SelStart is the Caret(Text-Curser) Position end; |
AW: Numerische Eingabe in Stinggrid validieren
Wenn ein Teil des Textes aktuell ausgewählt ist, wird er komplett durch das eingegebene Zeichen ersetzt.
Für Vorzeichen und Dezimalseperator muss man den Text also vor der Prüfung kürzen (SelStart, SelLength). |
AW: Numerische Eingabe in Stinggrid validieren
Hallo Blub!
Das würde ich noch nicht mal als "Fehler" ansehen, denn wenn die Zahl oder ein Teil davon markiert/ausgewählt ist, möchte ich es auch mit was anderem ersetzen. ( meine Meinung) Da wäre doch eher noch an anderer Stelle abzufangen, das z.b. im StringGrid beim weiter schalten zwischen den Zellen NICHT automatisch markiert wird. Gruß, Oliver [EDIT] OK, habs ausprobiert, wenn nur ein Teil markiert ist, geht's nicht mit dem Vorzeichen :-( insofern hast du recht, das man das evtl. noch anpassen sollte [/EDIT] |
AW: Numerische Eingabe in Stinggrid validieren
Das seh ich nicht so, denn die Zeichen werden ja nicht per Code gesetzt, sondern lediglich ggf. entwertet. Wenn der Anwender also einen Teil des Textes markiert, soll dieser ja wohl mit dem eingegebenen Zeichen überschrieben werden. Oder hab ich Dich jetzt falsch verstanden?
|
AW: Numerische Eingabe in Stinggrid validieren
Hallo zusammen!
Ich habe die Lösung noch ein wenig angepaßt, so daß jetzt auch die Eingabe von Vorzeichen bzw. DecimalSeparator bei markiertem Text funktioniert. Erst das TStringGrid:
Delphi-Quellcode:
// Validates a Float-only input in a Cell of a TStringGrid
procedure TMyForm.MyGridKeyPress(Sender : TObject; var Key : char); const KEY_NONE = #0; // empty Char/nullCharacter KEY_BACKSPACE = #8; var CellText:Widestring; selStart : integer; cellRow, cellCol : integer; DecSeparator: char; begin DecSeparator:= DefaultFormatSettings.DecimalSeparator; // the StandAlone Symbol "DecimalSeparator" is deprecated // If selection is not empty, first delete this selection, then do the rest if TStringCellEditor(TStringGrid(Sender).Editor).SelLength > 0 then TStringCellEditor(TStringGrid(Sender).Editor).SelText:= ''; cellRow:= (sender as TStringGrid).Row; cellCol:= (sender as TStringGrid).Col; CellText:= (sender as TStringGrid).Cells[cellCol,cellRow]; selStart:= TStringCellEditor(TStringGrid(Sender).Editor).SelStart ; // exessive Typecasting to access SelStart // only Keys 0-9(numeric), #8= Backspace, '-' and DecimalSeperator allowed if not (Key in [KEY_BACKSPACE, '0'..'9', '-', DecSeparator]) then Key := KEY_NONE // '-' and DecimalSeperator are only allowed once in the String-Input else if ((Key = DecSeparator) or (Key = '-')) and (Pos(Key, CellText) > 0) then Key := KEY_NONE // '-' is only allowed as first Character / SelStart is the Caret(Text-Curser) Position else if (Key = '-') and (selStart <> 0) then Key := KEY_NONE end; und Hier das Tedit:
Delphi-Quellcode:
Gruß, Oliver
// Validates a Float-only input in a TEdit
procedure TMyForm.MyEditKeyPress(Sender : TObject; var Key : char); const KEY_NONE = #0; // empty Char/nullCharacter KEY_BACKSPACE = #8; var DecSeparator: Char; begin DecSeparator:= DefaultFormatSettings.DecimalSeparator; // the StandAlone Symbol "DecimalSeparator" is deprecated // If selection is not empty, first delete this selection, then do the rest if (Sender as TEdit).SelLength > 0 then (Sender as TEdit).SelText:= ''; // only Keys 0-9(numeric), #8= Backspace, '-' and DecimalSeperator allowed if not (Key in [KEY_BACKSPACE, '0'..'9', '-', DecSeparator]) then Key := KEY_NONE // '-' and DecimalSeperator are only allowed once in the String-Input else if ((Key = DecSeparator) or (Key = '-')) and (Pos(Key, (Sender as TEdit).Text) > 0) then Key := KEY_NONE // '-' is only allowed as first Character / SelStart is the Caret(Text-Curser) Position else if (Key = '-') and ((Sender as TEdit).SelStart <> 0) then Key := KEY_NONE end; |
AW: Numerische Eingabe in Stinggrid validieren
Per CopyPaste kannst du allerdings noch immer irgendwas in die Zelle bekommen.
Und wenn du in der Zelle
Delphi-Quellcode:
stehen hast und vor das
-12
Delphi-Quellcode:
gehst, dann kannst du wieder
-
Delphi-Quellcode:
drücken und bekommst
-
Delphi-Quellcode:
.
--12
Und diese Eingabe
Delphi-Quellcode:
ist auch möglich :)
12,,,,,45
|
AW: Numerische Eingabe in Stinggrid validieren
Die einzige zuverlässige Art ist die Verwendung eines
![]() Wenn ja, dann wird der aktuelle Wert in das Memento übernommen, wenn nein, dann wird der Wert aus dem Memento wiederhergestellt.
Delphi-Quellcode:
Und hier ein kleines Beispiel mit 3 Edits (Integer, Float, Frei)
unit EditGuardian;
interface uses System.Generics.Collections, System.Classes, System.SysUtils, Vcl.StdCtrls; type TEditMemento = class( TPersistent ) private FSelStart: Integer; FSelLength: Integer; FText: string; procedure AssignFromCustomEdit( ASource: TCustomEdit ); procedure AssignToCustomEdit( ADest: TCustomEdit ); procedure AssignToEditMemento( ADest: TEditMemento ); protected procedure AssignTo( Dest: TPersistent ); override; public procedure Assign( Source: TPersistent ); override; end; TEditGuardian = class private FEdit: TCustomEdit; FMemento: TEditMemento; FValidator: TPredicate<string>; public constructor Create( AEdit: TCustomEdit; AValidator: TPredicate<string> ); destructor Destroy; override; procedure Validate; end; implementation { TEditMemento } procedure TEditMemento.Assign( Source: TPersistent ); begin if Source is TCustomEdit then AssignFromCustomEdit( Source as TCustomEdit ) else inherited; end; procedure TEditMemento.AssignFromCustomEdit( ASource: TCustomEdit ); begin Self.FText := ASource.Text; Self.FSelStart := ASource.SelStart; Self.FSelLength := ASource.SelLength; end; procedure TEditMemento.AssignTo( Dest: TPersistent ); begin if Dest is TCustomEdit then AssignToCustomEdit( Dest as TCustomEdit ) else if Dest is TEditMemento then AssignToEditMemento( Dest as TEditMemento ) else inherited; end; procedure TEditMemento.AssignToCustomEdit( ADest: TCustomEdit ); begin ADest.Text := Self.FText; ADest.SelStart := Self.FSelStart; ADest.SelLength := Self.FSelLength; end; procedure TEditMemento.AssignToEditMemento( ADest: TEditMemento ); begin ADest.FText := Self.FText; ADest.FSelStart := Self.FSelStart; ADest.FSelLength := Self.FSelLength; end; { TEditGuardian } constructor TEditGuardian.Create( AEdit: TCustomEdit; AValidator: TPredicate<string> ); begin inherited Create; if not Assigned( AEdit ) then raise EArgumentNilException.Create( 'AEdit' ); if not Assigned( AValidator ) then raise EArgumentNilException.Create( 'AValidator' ); FEdit := AEdit; FMemento := TEditMemento.Create; FValidator := AValidator; Validate; end; destructor TEditGuardian.Destroy; begin FMemento.Free; inherited; end; procedure TEditGuardian.Validate; begin if ( FEdit.Text = '' ) or FValidator( FEdit.Text ) then FMemento.Assign( FEdit ) else FEdit.Assign( FMemento ); end; end.
Delphi-Quellcode:
Und wie man sieht ist es völlig unerheblich welche Taste auch immer gedrückt wurde, oder auf welchem Weg der Wert es in das Edit-Control geschafft haben könnte. Passt der Wert nicht, wird einfach der alte Zustand wiederhergestellt.
unit FormMain;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.Generics.Collections, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.AppEvnts, EditGuardian; type TMainForm = class( TForm ) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; ApplicationEvents1: TApplicationEvents; procedure ApplicationEvents1Idle( Sender: TObject; var Done: Boolean ); private FGuardians: TList<TEditGuardian>; procedure CheckGuardians; public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; var MainForm: TMainForm; implementation {$R *.dfm} procedure TMainForm.AfterConstruction; begin inherited; FGuardians := TObjectList<TEditGuardian>.Create; // Integer Edit FGuardians.Add( TEditGuardian.Create( Edit1, function( AValue: string ): Boolean var LValue: Integer; begin Result := TryStrToInt( AValue, LValue ); end ) ); // FloatEdit FGuardians.Add( TEditGuardian.Create( Edit2, function( AValue: string ): Boolean var LValue: Extended; begin Result := TryStrToFloat( AValue, LValue ); end ) ); end; procedure TMainForm.ApplicationEvents1Idle( Sender: TObject; var Done: Boolean ); begin CheckGuardians; end; procedure TMainForm.BeforeDestruction; begin inherited; FGuardians.Free; end; procedure TMainForm.CheckGuardians; var LGuardian: TEditGuardian; begin for LGuardian in FGuardians do LGuardian.Validate; end; end. Drops gelutscht :mrgreen: PS Wer jetzt anmerken möchte, dass man dort keine negativen Zahlen eingeben kann, weil ein einfaches
Delphi-Quellcode:
einfach geschluckt wird, der passt entweder den Validator an, oder viel besser erstellt sich eine eigene
-
Delphi-Quellcode:
und berücksichtigt dort diese Eingabe und nimmt diese in den Validator mit auf. Denn irgendwann will man den Wert aus dem Edit wieder auslesen und dann benutzt man einfach diesen
TryStrToMyValue
Delphi-Quellcode:
.
TryStrToMyValue
|
AW: Numerische Eingabe in Stinggrid validieren
Zitat:
Mit dem CopyPaste hast du allerdings recht! Gruß, Oliver |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz