1

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.

user763539
  • 3,509
  • 6
  • 44
  • 103
  • I think you may need to explain a bit more fully what you're trying to achieve. What if several columns in the same row have been changed? When you say "changed" do you mean to include changes already saved to the the dataset? Does your dataset do ApplyUpdates()s? – MartynA Jun 29 '16 at 10:50
  • Yes, I would like to highlight every cell in the entire row if it was changed.This is before post event so nothing is saved yet. The grid is in [dsEdit,dsInsert] mode.No, the database dos not call applyupdates. – user763539 Jun 29 '16 at 10:52
  • This is the situation when user modifies the table , forgets to post the changes and tries to close the form. So before he closes the form (and looses all modified data) it is nice to tell him that the changes he made to the table are not saved yet and show him (the cells) that were changed. Understand ? I was thinking perhaps about coloring the changed cell so its easily visible though highlight is ok too. – user763539 Jun 29 '16 at 11:01
  • I am not sure but I think the TMS ADVgrid had this functionality built in. If you changed a character in the row the grid would highlight it. Every change in the row was highlighted. very nice feature. – user763539 Jun 29 '16 at 11:10

1 Answers1

1

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.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • This does not highlight changed cells if you move from the changed cell to another cell. It only highlights the last visited cell in the row no matter if it was changed or no. – user763539 Jun 29 '16 at 12:05
  • Sorry, I was leaving the implementational details up to you. You asked "Is there a way I can highlight (or color) a changed cell" - my answer shows how to highlight/colour a cell specially during the `OnCloseQuery` event. Imo, it's up to you to determine whether a given cell is a candidate for special treatment of not. – MartynA Jun 29 '16 at 12:10
  • I'll try and add a concrete example of detecting that the value of the field associated with a given cell has changed a bit later on. – MartynA Jun 29 '16 at 12:21
  • looking forward to... Thanks ! – user763539 Jun 29 '16 at 12:23
  • See update. As ever, it's a bit of a performance navigating through a cxGrid's objects and properties! – MartynA Jun 29 '16 at 13:42
  • This new code works just like the previous one. Don't see the difference. – user763539 Jul 01 '16 at 00:48
  • Not sure I follow: In the original version of my code, the focused cell was marked because the dataset is in dsEdit/dsInsert state. So, the focused cell was marked regardless of whether its contents had been changed. With the updated code, it is only marked if its contents **have** been changed - see latest update for how to test and explanation. Marking **each** of the cells which have changed values would be a lot trickier, imo, and would require your dataset type to support accessing the original values in the fields. – MartynA Jul 01 '16 at 08:38
  • Disregard my comments on this answer - the updated version should do what I understand you to be asking for. – MartynA Jul 01 '16 at 19:41
  • got a nasty access violation on this one if I try and edit an empty cell and then try and leave....But, never mind...I am satisfied with the original code. Just added on close query : cxGrid1DBTableView1.Controller.FocusedRow.MakeVisible; incase the modified is out of focus. – user763539 Jul 02 '16 at 09:30
  • I can't provoke that AV, need exact steps to reproduce. – MartynA Jul 02 '16 at 10:27