Search code examples
delphidelphi-5

Exceptions on DBGrid editing


I have implemented an editable DBGrid. If a field is not filled correctly an exception is thrown and a message is shown, for example:

'08:00::00' is not a valid time

How can I catch those exceptions so that I can show messages written by me instead of the automatically generated ones? I would be thankful for any help.


Solution

  • As @teran pointed in his comment, the exception is raised by the TDataSet (or one of it's components) that is bind to the TDBGrid, or by the DB engine itself.

    You can try to handle the TDataSet.OnPostError (see also OnUpdateError and OnEditError):

    TDataSet.OnPostError: Occurs when an application attempts to modify or insert a record and an exception is raised. Write an OnPostError event handler to handle exceptions that occur when an attempt to post a record fails.

    Note that you could always use Application.OnException global event handler to catch any EDBxxx exceptions in your application.


    EDIT: The EConvertError exception is raised before any actual data modifications, or any Post operation by the TDateTimeField field i.e.:

    0045af91 +085 Project1.exe SysUtils       StrToDateTime <- EConvertError
    004ab76a +042 Project1.exe Db             TDateTimeField.SetAsString
    004a9827 +007 Project1.exe Db             TField.SetText
    004a95d9 +029 Project1.exe Db             TField.SetEditText
    004d6448 +014 Project1.exe DBGrids        TCustomDBGrid.UpdateData
    004d087f +02b Project1.exe DBGrids        TGridDataLink.UpdateData
    004d599a +01a Project1.exe DBGrids        TCustomDBGrid.MoveCol
    

    StrToDateTime is throwing the exception inside TDateTimeField.SetAsString, not touching the data, and the TDataSet.OnxxxError event handlers will not be fired at all.

    So your choices are (test the application in release mode):

    1.Intercept and handle EConvertError via Application.OnException.
    2.Use TField.EditMask to restrict user input to a valid time format e.g. !90:00;1;_ or use inplace DateTimePicker editor inside your Grid. (and avoid catching this exception).
    3.Override TDateTimeField: use persistent fields with your TDataSet and create an inter-poser class as such:

    type
      TDateTimeField = class(Db.TDateTimeField)
      protected
        procedure SetAsString(const Value: string); override;
      end;
    
      TForm1 = class(TForm)
      ...
    
    procedure TDateTimeField.SetAsString(const Value: string);
    begin
      try
        inherited SetAsString(Value);
      except
        on E: EConvertError do
        begin
          ShowMessage(E.Message);
          Abort;
        end;
      end;
    end;