Page 1 of 1

Changing rveTable.cells content

Posted: Thu Nov 03, 2005 12:47 pm
by j&b
Hello,

I have a rveTable in a TDBRichViewEdit (vers.1.9.18.1) with

- rveTable.Cells[r,c].BestWidth := 200
- rveTable.Cells[r,c].BestHeight:= -(100 div rveTable.Rows[r].Count);
cells-content is intToStr(r)+' * '+intToStr(c)

Now I want to make all

- Cells higher
- and give them a new content ('*')

All ok.
But when I select another record and go back to the changing record,
new content is vanished (old Content is to see).

But when I click in the memo (after clicking Button1Click) and write a text, new content will stay after scrolling through table.

Jürgen

procedure TForm1.Button1Click(Sender: TObject);
var r,c, ItemNo, Offs: Integer;
begin
if not (memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
ShowMessage('Tabelle hat nicht den Focus.');
exit;
end;
// ? rveTable.OnCellEditing := OnCellEditing; <------ ?
for r := 0 to rveTable.Rows.Count-1 do
for c := 0 to rveTable.Rows[r].Count-1 do begin
rveTable.Cells[r,c].BestWidth := 25;
rveTable.Cells[r,c].BestHeight:= 25;
rveTable.Cells[r,c].clear; // <--------- ? look at next line
rveTable.Cells[r,c].AddNL('*',0,0); <--------- I overwrite old content
end;

memo.format;
end;

What's to do ?

Posted: Thu Nov 03, 2005 3:14 pm
by Sergey Tkachenko
- rveTable.Cells[r,c].BestWidth := 200
- rveTable.Cells[r,c].BestHeight:= -(100 div rveTable.Rows[r].Count);
BestHeight does not support negative values, they will be ignored. Only BestWidth treats them as %.
By the way, rveTable.Rows[r].Count is a number of columns, not rows.

As for the question. The problem occurs because you use non-editing methods, they do not inform table that the document was modified, so changes are not saved.
Add the following:
1)
if not memo.CanChange then exit;
before making modifications
2) memo.Change
after.
Also, you need to call memo.ClearUndo, because using non-editing operations damages undo and redo buffers.
Also, check if Cells[r,c]<>nil, otherwise your application will crash if the table has merged cells.

But if you need to implement a editing operation, which can be undone/redone by the user, you need to use another approach: only editing-style methods must be used (no Clear, no AddNL, no direct assignment to BestWidth/BestHeight!)

Code: Select all

if not (memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin 
  ShowMessage('Tabelle hat nicht den Focus.'); 
  exit; 
end;
if not memo.CanChange then
  exit;
ItemNo := rveTable.GetMyItemNo;
rve.BeginUndoGroup(rvutModifyItem);
rve.SetUndoGroupMode(True);
rve.BeginItemModify(ItemNo, Data);
for r := 0 to rveTable.Rows.Count-1 do 
  for c := 0 to rveTable.Rows[r].Count-1 do 
    if rveTable.Cells[r,c]<>nil then begin 
      rveTable.SetCellBestWidth(25, r, c);
      rveTable.SetCellBestHeight(25, r, c);    
  end;
rve.EndItemModify(ItemNo, Data);
rve.SetUndoGroupMode(False);
rve.Change;
for r := 0 to rveTable.Rows.Count-1 do 
  for c := 0 to rveTable.Rows[r].Count-1 do 
    if rveTable.Cells[r,c]<>nil then begin 
      rveTable.EditCell(r,c);
      rve.TopLevelEditor.SelectAll; // the cell is edited, so rve.TopLevelEditor is a cell inplace editor
      rve.InsertText('*');
    end;

Posted: Fri Nov 04, 2005 5:56 am
by j&b
Thank you, Sergey

Nice that you comment your code.

The 2. code
//memo.color:=clBtnFace;
for r := 0 to rveTable.Rows.Count-1 do
for c := 0 to rveTable.Rows[r].Count-1 do
if rveTable.Cells[r,c]<>nil then begin
rveTable.EditCell(r,c);
rve.TopLevelEditor.SelectAll; // the cell is edited, so rve.TopLevelEditor is a cell inplace editor
rve.InsertText('*');
end;
//memo.color:=clWhite; //crHourGlass + crDefault doesn't go

is very slow.

Because .crHourGlass and .crDefault doesn't go I change memo.color. Now user know if changing is ready

Posted: Fri Nov 04, 2005 1:58 pm
by Sergey Tkachenko
Yes, it is slow, because it creates inplace editors for all cells one by one.
You can speed it up and remove flickering by forbidding redrawing:

SendMessage(rve.Handle, WM_SETREDRAW, 0, 0);
try
<indert that code here>
finally
SendMessage(rve.Handle, WM_SETREDRAW, 1, 0);
rve.Invalidate;
end;

Posted: Fri Nov 04, 2005 7:52 pm
by Rob
Please add DisableUpdate and EnableUpdate to do the SendMessage. This would allow for 'stacking' disabled updates.

Ergo:

DisableUpdates:
- Check if a disbaled-counter equals zero. If it does, send the message to disable actual updates.
- Increase a counter

EnableUpdates:
- Decrease the counter if it is > 0, the if it reaches 0, send the message to enable redrawing and call Invalidate;

Posted: Fri Nov 04, 2005 8:55 pm
by Sergey Tkachenko
It would be too complex to implement. I mean, disabling the update of internal data representing formatting. Redrawing does not occur usually, because Invalidate does not repaint the window itself. This case is an exception, because it involves creating of inplace table editors.

And I think that this case is atypical. It's rarely required to make massive changes in the document as an editing command (that can be undone/redone). There is a set of non-editing methods for fast document generation and modification.

Posted: Fri Nov 04, 2005 9:01 pm
by Rob
Not too complicated:

Code: Select all

  TCustomRichView = class(TRVScroller)
  private
    { Private declarations }
    FUpdatesLock: Integer;
    FCursor: TCursor;
...

  public
    procedure DisableUpdates;
    procedure EnableUpdates;

...

  end;

...

implementation

...


procedure TCustomRichView.DisableUpdates;
begin
  if (FUpdatesLock = 0) and HandleAllocated then
    SendMessage(Handle, WM_SETREDRAW, 0, 0);
  Inc(FUpdatesLock);
end;

procedure TCustomRichView.EnableUpdates;
begin
  Dec(FUpdatesLock);
  if FUpdatesLock > 0 then Exit;
  if HandleAllocated then
  begin
    SendMessage(Handle, WM_SETREDRAW, 1, 0);
    Invalidate;
  end;
  FUpdatesLock := 0;
end;

...

I understand this may be 'too complicated to add', but I would be happy to use them as helper methods. Nice to have, I mean.