delphitcxgrid

cxgrid highlight (or color) changed cell on form closequery


On closequery of the form I have :

if MessageDlg('Close program ?',
          mtConfirmation, [mbYes,mbCancel],0) <> mrYes then CanClose := False
else if DataModule2.mytable.State in [dsEdit,dsInsert] then
               if MessageDlg('Save changes ?', mtConfirmation,
                    [mbYes,mbNo],0) = mrYes then DataModule2.mytable.Post;

Is there a way I can highlight (or color) a changed cell in cxgrid when I trigger my onclosequery event ?

I don't need to know what was changed but just to know which cell was changed so the user can see it so he can easily decide weather to save the changes or not.


Solution

  • It is simple to get the cxGrid to draw a cell (or row) highlighted in some way using the cxGrid1DBTableView1CustomDrawCell event. And by having a flag that indicates that the OnCloseQuery event is in progress, you can restrict its action to inside that event.

    Update The code I originally posted with this answer could not successfully mark more than one cell in the current grid row as changed. The updated code below can do this however; note the comments in the two procedures.

    type
      TForm1 = class(TForm)
        [...]
      public
        QueryingClose : Boolean;
      end;
    
    procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      try
        QueryingClose := True;
        //{cxGrid1.Invalidate{True);  Do NOT call Invalidate, because it causes the
        //  grid's repainting logic to operate in a way which effectively makes it
        //  impossible to mark more that one cell in the current data row as changed
        ShowMessage('Close?');
      finally
        QueryingClose := False;
      end;
    end;
    
    procedure TForm1.cxGrid1DBTableView1CustomDrawCell(Sender:
        TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo:
        TcxGridTableDataCellViewInfo; var ADone: Boolean);
    var
      Field : TField;
      MarkCell : Boolean;
      S1,
      S2 : String;
      EC : TcxGridTableEditingController;
    begin
      if QueryingClose  and
        (TcxGridDBTableView(Sender).DataController.DataSet.State in[dsEdit, dsInsert]) then begin
        Field := TcxGridDBColumn(AViewInfo.Item).DataBinding.Field;
        S1 := VarToStr(Field.OldValue);
    
        //  When this event is called, the user may be in the middle of editing a cell's contents
        //  So, the purpose of the following lines is to close the inplace editor being used to do
        //  this amd post the chamged value back to the TField associated with the cell
        EC :=  TcxGridDBTableView(Sender).Controller.EditingController;
        if EC.IsEditing then
          EC.HideEdit(True);
    
        S2 := VarToStr(Field.Value);
        MarkCell := S1 <> S2;
        if MarkCell then
          ACanvas.Brush.Color := clLime;
      end;
    end;
    

    For this to work, your TDataSet-descendant type must support correctly returning the original contents of the fields on their OldValue property; TClientDataSet, which I've used to write/test this code certainly does this but I've no idea what actual TDataSet type you're using.

    Hopefully, it should be apparent that you could use these two procedures to build a list of TFields that have changed values, including the FieldName OldValue, and Value.