Delphi

Un editor numerico data-aware su misura per la VCL

calendar_today personTeam EGSOFT schedule5 min di lettura
info

Disclaimer: le informazioni pubblicate in questa sezione hanno finalità di pura divulgazione tecnica. EG Software S.r.l. non si assume alcuna responsabilità per un utilizzo improprio dei contenuti, né per eventuali danni diretti o indiretti derivanti dalla loro applicazione, e non garantisce l'aggiornamento, l'accuratezza o la completezza delle informazioni riportate. Prima di utilizzare in produzione codice o procedure qui descritte, verificane sempre l'adeguatezza al proprio contesto.

La VCL mette a disposizione tanti controlli pronti, ma capita spesso di aver bisogno di un editor numerico data-aware con vincoli propri: cifre decimali configurabili, valori minimo e massimo, e magari un piccolo bottone di supporto. Costruire un componente su misura, derivato da TPanel, è più semplice di quanto sembri e permette di riusarlo identico in tutti i form del progetto.

La struttura: un TPanel come contenitore

L'idea è creare una classe che eredita da TPanel e che, al proprio interno, ospita un TDBEdit (per restare collegato a un TDataSource) e un piccolo TSpeedButton di servizio:

unit EGNumericEdit;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, Forms,
  StdCtrls, ExtCtrls, Buttons, DB, DBCtrls;

type
  TDBNumericEdit = class(TPanel)
  private
    FEdit: TDBEdit;
    FButton: TSpeedButton;
    FDataSource: TDataSource;
    FDataField: string;
    FDecimalPlaces: Integer;
    FAllowDecimals: Boolean;
    FMinValue, FMaxValue: Double;

    procedure SetDataSource(const Value: TDataSource);
    procedure SetDataField(const Value: string);
    procedure EditKeyPress(Sender: TObject; var Key: Char);
    procedure EditExit(Sender: TObject);
    function GetValue: Double;
    procedure SetValue(const Value: Double);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Value: Double read GetValue write SetValue;
  published
    property DataSource: TDataSource read FDataSource write SetDataSource;
    property DataField: string read FDataField write SetDataField;
    property DecimalPlaces: Integer read FDecimalPlaces write FDecimalPlaces default 2;
    property AllowDecimals: Boolean read FAllowDecimals write FAllowDecimals default True;
    property MinValue: Double read FMinValue write FMinValue;
    property MaxValue: Double read FMaxValue write FMaxValue;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('EG Controls', [TDBNumericEdit]);
end;

I sotto-componenti (FEdit e FButton) vengono creati nel costruttore e agganciati con Parent := Self, mentre il posizionamento è gestito sovrascrivendo Resize, così il componente si ridimensiona correttamente quando viene ancorato o ridimensionato nell'IDE.

Validare l'input carattere per carattere

Il controllo più utile di questo tipo di editor è quello sull'evento OnKeyPress: si filtrano i tasti non numerici, si permette il separatore decimale una sola volta e si consente il segno meno solo in prima posizione:

procedure TDBNumericEdit.EditKeyPress(Sender: TObject; var Key: Char);
var
  SeparatoreDecimale: Char;
begin
  SeparatoreDecimale := FormatSettings.DecimalSeparator;

  if not CharInSet(Key, ['0'..'9', #8]) then
  begin
    if (Key = '.') or (Key = ',') then
    begin
      if not FAllowDecimals or (Pos(SeparatoreDecimale, FEdit.Text) > 0) then
        Key := #0
      else
        Key := SeparatoreDecimale;
    end
    else if not ((Key = '-') and (FEdit.SelStart = 0) and (Pos('-', FEdit.Text) = 0)) then
      Key := #0;
  end;
end;

Uscendo dal campo (OnExit) si applica anche il controllo sul range, riportando il valore entro MinValue e MaxValue se necessario: una validazione "morbida" che evita all'utente di dover correggere manualmente un valore fuori scala.

Un bottone di supporto opzionale

Il codice originale da cui è tratto questo componente include anche una piccola calcolatrice popup, creata a runtime e mostrata in modale quando si preme il bottone accanto all'edit. È una soluzione pratica per un dialogo ausiliario "usa e getta", ma se nel tuo progetto preferisci restare fedele alla convenzione "tutto a design time", conviene trasformarla in una vera form disegnata nell'IDE con il proprio .dfm e invocata con ShowModal: il comportamento resta identico, ma la form diventa modificabile visivamente come qualsiasi altra.

Il vantaggio di impacchettare tutto in un componente registrato con RegisterComponents è che, una volta compilato in un package, TDBNumericEdit compare nella Tool Palette esattamente come i controlli nativi: lo trascini su un form, lo colleghi a un TDataSource e hai già editor, validazione e range check pronti.

Altri articoli su Delphi grid_viewTutte le tematiche
Scrivici su WhatsApp