copy current col to a new current col

General TRichView support forum. Please post your questions here
j&b

Post by j&b »

Hello Sergey,
many thanks.

Your procedure runs very fine.
But only in the same table. But I want to copy to another table too.

For this reason I splitted your procedure in 2 procedures:
- in a copying procedure (SpalteKopierenClick) and
- in a pasting procedure (SpalteEinfuegenClick)

My splitted procedure work.

So I can copy the 2. column of Table and/or pasting in the 5. column.
Only one little thing is wrong ;-):

The 2. procedure copies either all cell-contents of source-col into each cell of dest-col
or only the last cell-content of source-col into each cell of dest-col.

No wonder. You selects a cell and write her immediately into the dest-cell of the same rveTable then you freed Stream1(.free) and creates stream1 new (stream1:= TMemoryStream.create). Stream1 contains only the contents of one cell.

Can you correct my mistake ?

Jürgen

Code: Select all

procedure TForm1.SpalteKopierenClick(Sender: TObject);
var r: integer;
    UnusedColor: TColor; 
    oldps, oldts:TRVFReaderStyleMode; 
begin
  if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
    ShowMessage('Tabelle hat nicht den Focus.'); 
    exit; 
  end; 
  rveTable.GetEditedCell(r, rveTspalte);  
  { private:  
      rveTspalte: integer;
      rveTable: TRVTableItemInfo;
      stream1: TMemoryStream;
  }

  UnusedColor := clNone; 
  oldps := memo.RVFParaStylesReadMode; 
  oldts := memo.RVFTextStylesReadMode; 
  memo.RVFParaStylesReadMode := rvf_sIgnore; 
  memo.RVFTextStylesReadMode := rvf_sIgnore; 
  SendMessage(memo.Handle, WM_SETREDRAW, 0, 0); 
  try 
   
    stream1.Clear; //--> all cell-contents of source-col shall copied to each cell of selected dest-col
   
    for r := 0 to rveTable.Rows.Count-1 do 
      if rveTable.Cells[r, rveTspalte]<>nil then begin
        
        //stream1.clear;  //only the cell-content of last source-col shall copied to each cell of selected dest-col
        
        rveTable.Cells[r, rveTspalte].GetRVData.SaveRVFToStream(Stream1, False, UnusedColor, nil, nil); 
      end;  
  finally 
    memo.RVFParaStylesReadMode := oldps; 
    memo.RVFTextStylesReadMode := oldts; 
    SendMessage(memo.Handle, WM_SETREDRAW, 1, 0); 
    if memo.InplaceEditor<>nil then memo.InplaceEditor.Invalidate;
    //while memo.InplaceEditor<>nil do memo.InplaceEditor.Invalidate;  //loop without exit
  end; 
end;


procedure TForm1.SpalteEinfuegenClick(Sender: TObject);
var r, rveTspalte2: integer;
begin
  if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
    ShowMessage('Tabelle hat nicht den Focus.'); 
    exit; 
  end; 
  rveTable.GetEditedCell(r,rveTSpalte2);

  SendMessage(memo.Handle, WM_SETREDRAW, 0, 0); 
  try 
    for r := 0 to rveTable.Rows.Count-1 do 
      if rveTable.Cells[r, rveTspalte2]<>nil then begin 
        Stream1.Position := 0; 
        rveTable.Cells[r, rveTspalte2].Edit; 
        memo.TopLevelEditor.SelectAll; 
        memo.TopLevelEditor.InsertRVFFromStreamEd(Stream1); 
      end;  
  finally 
    SendMessage(memo.Handle, WM_SETREDRAW, 1, 0); 
  end; 
  if table1.state in [dsEdit, dsInsert] then table1.post;
end;
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Your procedure saves the first cell to the stream, then clears the stream and saves the second cell, and so on. So, of course, only the last cell remains in the stream.

Is it necessary to implement it as two procedures?
It would be simpler to make a procedure
procedure CopyTableColumnEd(rv: TCustomRichViewEdit; SourceTable, DestTable: TRVTableItemInfo; SourceCol, DestCol: Integer);
copying the SourceCol-th column of SourceTable to the DestCol column of DestTable.
j&b

Post by j&b »

Hello Sergey,

thank you for your quick answer.

User click in one col of table1. Then he choose another table clicks in a col.
I have tried it with

CopyTableColumnEd(rve: TCustomRichViewEdit; rveTable,rveTable2: TRVTableItemInfo; SourceCol, DestCol: Integer);

I get the same result. I can only copy a col of the 2. table to another col of the same table

I believe that I know the mistake.
I only get the col-no of table1 and table2.
In CopyTableColumnEd procedure rveTable is the same as rveTable2. Correct ?


Code: Select all

procedure TForm1.SpalteKopierenClick(Sender: TObject);
  var r: integer;
begin
  if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
    ShowMessage('Tabelle hat nicht den Focus.'); 
    exit; 
  end; 
  rveTable.GetEditedCell(r, rveTspalte);
end;

procedure TForm1.SpalteEinfuegenClick(Sender: TObject);
var r, rveTspalte2: integer;
begin
  if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
    ShowMessage('Tabelle hat nicht den Focus.'); 
    exit; 
  end; 
  rveTable2.GetEditedCell(r,rveTSpalte2);
  CopyTableColumnEd(memo, rveTable,rveTable2, rveTspalte,rveTspalte2);
end;

procedure TForm1.CopyTableColumnEd(rve: TCustomRichViewEdit; rveTable,rveTable2: TRVTableItemInfo; SourceCol, DestCol: Integer); 
var r: Integer; 
    UnusedColor: TColor; 
    oldps, oldts:TRVFReaderStyleMode; 
begin 
  UnusedColor := clNone; 
  oldps := rve.RVFParaStylesReadMode; 
  oldts := rve.RVFTextStylesReadMode; 
  rve.RVFParaStylesReadMode := rvf_sIgnore; 
  rve.RVFTextStylesReadMode := rvf_sIgnore; 
  SendMessage(rve.Handle, WM_SETREDRAW, 0, 0); 
  try 
    for r := 0 to rveTable.Rows.Count-1 do 
      if (rveTable.Cells[r, SourceCol]<>nil) and (rveTable2.Cells[r, DestCol]<>nil) then begin 
        stream1.Clear;
        rveTable.Cells[r, SourceCol].GetRVData.SaveRVFToStream(Stream1, False, UnusedColor, nil, nil); 
        Stream1.Position := 0; 
        rveTable2.Cells[r, DestCol].Edit; 
        rve.TopLevelEditor.SelectAll; 
        rve.TopLevelEditor.InsertRVFFromStreamEd(Stream1); 
      end; 
  finally 
    rve.RVFParaStylesReadMode := oldps; 
    rve.RVFTextStylesReadMode := oldts; 
    SendMessage(rve.Handle, WM_SETREDRAW, 1, 0); 
    while rve<>nil do begin 
      rve.Invalidate; 
      rve := TCustomRichViewEdit(rve.InplaceEditor); 
    end; 
  end; 
  if table1.state in [dsEdit, dsInsert] then table1.post;
end;
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

There is a misprint in your code. In both procedures, you call GetCurrentItemEx for rveTable, instead of calling it for rveTable and rveTable2.

Otherwise your code is ok, but several problems are possible:
1) Even if the table is active, it's not necessary that it has an edited cell. There are may be multicell selection or caret after/before the table.
Solution: check the result of GetEditedCell and display an error message if it is nil.

2) User may delete columns of rveTable before clicking SpalteEinfuegen.
Solution: in CopyTableColumnEd, check

Code: Select all

if rveTable.Rows[0].Count<=SourceCol then begin
  <display error>
  exit;
end;
3) Tables may have different number of rows.
Solution: the cycle for r := 0 to rveTable.Rows.Count-1 do must be not to rveTable.Rows.Count-1 but to min(rveTable.Rows.Count, rveTable2.Rows.Count)-1.

4) User may delete rveTable before clicking SpalteEinfuegen.
Solution: process OnItemAction event, and if the ItemAction parameter is equal to rviaMovingToUndoList or rviaDestroying, assign rveTable := 0.
In SpalteEinfuegenClick, check:

Code: Select all

if rveTable=nil then begin
    <display error message: the source table is not specified>
   exit;
  end;
Post Reply