delphi

How do I prevent users from entering values that exceed TSpinEdit.MaxValue?


I set the TSpinEdit.MaxValue to 100 but when the program runs, it lets the user enter values over 100 - when the number is entered manually (instead of using the spins). There is any way to limit the value to MaxValue without writing code?

The problem is that when the user enters a wrong value, this can result in a RageCheckError or something similar.

procedure TFrmMain.spnMaxFileSizeChange(Sender: TObject);
begin
 PlaylistCtrl.BigFileThresh:= spnMaxFileSize.Value * KB;
end;

This could be fixed with something like:

 if spnMaxFileSize.Value> spnMaxFileSize.MaxValue  
 then spnMaxFileSize.Value:= spnMaxFileSize.MaxValue;

...but I don't really want to manually add this line for each control on my form. All the fun of "visual programming" will be lost :)


Solution

  • Two possible solution:

    TYPE
     TMySpinEdit = class(TSpinEdit)   { Fixes the OnChange MinValue/MaxValue issue }
      private
       Timer: TTimer;
       FOnChanged: TNotifyEvent;
       procedure TimesUp(Sender: TObject);
      public
       constructor Create (AOwner: TComponent);override;
       destructor Destroy;override;
       procedure Change; override;
      published
       property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;
     end;
    
    constructor TMySpinEdit.Create(AOwner: TComponent);
    begin
     inherited;
     Timer:= TTimer.Create(Self);
     Timer.OnTimer:= TimesUp;
     Timer.Interval:= 2500; { allow user 2.5 seconds to enter a new correct value }
    end;
    
    destructor TMySpinEdit.Destroy;
    begin
     FreeAndNil(Timer);
     inherited;
    end;
    
    procedure TMySpinEdit.Change;
    begin
     Timer.Enabled:= FALSE;
     Timer.Enabled:= TRUE;
    end;
    
    procedure TMySpinEdit.TimesUp;
    begin
     Timer.Enabled:= FALSE;
     if (MaxValue<> 0) AND (Value> MaxValue) then Value:= MaxValue;
     if (MinValue<> 0) AND (Value< MinValue) then Value:= MinValue;
     if Assigned(FOnChanged) then FOnChanged(Self);
    end;
    

    Code not tested yet (to be compiled).


    The other solution would be:

    TYPE
     TMySpinEdit = class(TSpinEdit)
      public
       procedure Change; override;
     end;
    
    IMPLEMENTATION
    
    procedure TMySpinEdit .Change;
    begin
     if (Value > MaxValue) OR (Value < MinValue) then
      begin
        Color:= clRed;
        EXIT;  { Out of range value. Don't trigger the OnChange event. }
      end;
    
     Color:= clWindow;
     inherited;
    end;
    

    Update

    I wrote an extension for TSpinEdit. This control offers an extra event called OnChanged which is called 1200ms (See the Delay property) after the user entered the value.
    https://github.com/GabrielOnDelphi/Delphi-LightSaber/blob/main/cvSpinEditDelayed.pas