Page 1 of 2
copy current col to a new current col
Posted: Sat Nov 05, 2005 6:49 am
by j&b
Hello,
can someone tell me how I can get the content of one rveTable.cell.
I want to copy the content of current col to a new current col.
my idea:
procedure TForm1.SpaltenInhaltKopierenClick(Sender: TObject);
var r,c,tSpalte: integer;
begin
try
rveTable.GetEditedCell(r,tSpalte);
strl1.Clear; //TStringList
memo.Color:=clBtnFace;
Application.ProcessMessages;
SendMessage(rve.Handle, WM_SETREDRAW, 0, 0);
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
// if c=tSpalte then strl1.add(???);
end;
finally
SendMessage(rve.Handle, WM_SETREDRAW, 1, 0);
memo.color:=clWhite;
end;
end;
procedure TForm1.SpaltenInhaltEinfuegenClick(Sender: TObject);
var r,c,tSpalte: integer;
begin
try
rveTable.GetEditedCell(r,tSpalte);
strl1.Clear;
memo.Color:=clBtnFace;
Application.ProcessMessages;
SendMessage(rve.Handle, WM_SETREDRAW, 0, 0);
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
if c=tSpalte then begin
rveTable.EditCell(r,c);
memo.TopLevelEditor.SelectAll;
memo.InsertText(strl1.lines[r]);
end;
end;
finally
SendMessage(rve.Handle, WM_SETREDRAW, 1, 0);
rve.Invalidate;
memo.color:=clWhite;
end;
end;
Posted: Sat Nov 05, 2005 1:01 pm
by Michel
I think you may want to go along the lines of
SourceCell.SaveRVFToStream()
DestinationCell.LoadRVFFromStream()
The thread "Cell Streaming does not save Styles" in this forum has slightly more stuff on this subject. E.g., WhateverCell in the pseudo-code-like example above may need to be a more involved "beast" (RVData or the like).
Michel
Posted: Sat Nov 05, 2005 2:30 pm
by j&b
Thank you, but I don't understand your hints because I'm a beginner.
Can you answer my question
if c=tSpalte then strl1.add(content of cell);
(instead of a StringList I can take a delphi-richedit, so that content doesn't loose his attributes),
too ?
It would be nice, if you would write your hint in more detail (I'm a beginner
)
PS: Naturally it must be called 'memo.InsertText(strl1.strings[r])' instead of strl1.lines[r];
Posted: Sat Nov 05, 2005 6:53 pm
by Michel
Thank you, but I don't understand your hints because I'm a beginner.
Oh, sorry. That was not apparent from the cell-iteration code you presented!
(instead of a StringList I can take a delphi-richedit, so that content doesn't loose his attributes)
That was more or less what I meant. Basically, to save the contents of a cell to some temporary/intermediate storage location/object, you must use a stream (a cell can contain
much more than just lines of text, e.g., an entire document with more tables inside). However, you can't use a Delphi TRichEdit as that intermediate storage, that's for sure.
I can offer small pieces of C++ code as an example of what I meant. You'll have to adapt it to your needs.
Code: Select all
TMemoryStream *MS = new TMemoryStream; // You'll need a stream to transfer cell contents
TRVTableCellData *Cell = Table->Cells[0][0]; // Get somehow to the cell of interest
Cell->SaveRVFToStream(MS, false, clNone, NULL, NULL); // Save it to the stream
TCustomRVData *CRVD = Cell->GetRVData(); // This is an alternative to the above
CRVD->SaveRVFToStream(MS, false, clNone, NULL, NULL);
TRVTableInplaceRVData *CED = (TRVTableInplaceRVData *)Cell->Edit(); // Another alternative
CED->SaveRVFToStream(MS, false, clNone, NULL, NULL);
There are even more alternative ways to save the cell's contents to a stream, but any of the above should do the job within the same RichView control.
Now, get somehow to the destination cell Dest and with it:
Code: Select all
MS->Position = 0; // "Rewind" the stream
Dest->LoadRVFFromStream(MS, <...>); // "Stream in" the saved source cell contents
The only problem is that I don't remember if there are some additional parameters after MS, so you may need to replace
<...> by something like
DummyTColorVariable, NULL, NULL.
I hope this is starting to make sense. To reiterate, stop thinking of RichView in terms of lists of strings or lines and such. I find it much more useful to think of it as a tree of RVData objects organized into a hierarchy of tables and cells containing more of the same.
Hope this helps,
Michel
Posted: Sat Nov 05, 2005 9:26 pm
by Sergey Tkachenko
Thanks again, Michel
Some comments about copying to the stream:
Code: Select all
// c++
TRVTableCellData *Cell = Table->Cells[0][0];
Cell->SaveRVFToStream(MS, false, clNone, NULL, NULL);
// pascal
var Cell: TRVTableCellData;
Cell := Table.Cells[0,0];
Cell.SaveRVFToStream(MS, False, clNone, nil, nil);
The code above will work only if the cell is not edited.
It will fail if the cell is edited
Code: Select all
// c++
TCustomRVData *CRVD = Cell->GetRVData();
CRVD->SaveRVFToStream(MS, false, clNone, NULL, NULL);
// pascal
var CRVD: TCustomRVData;
CRVD := Table.Cells[0,0].GetRVData;
CRVD.SaveRVFToStream(MS, False, clNone, nil, nil);
This is the best method. Will work in all cases, and it is fast.
Code: Select all
//c++
TRVTableInplaceRVData *CED = (TRVTableInplaceRVData *)Cell->Edit(); CED->SaveRVFToStream(MS, false, clNone, NULL, NULL);
// pascal
var CED: TCustomRVFormattedData;
CED := Table.Cells[0,0].Edit;
CED.SaveRVFToStream(MS, False, clNone, nil, nil);
This method works, but it creates cell inplace editor for the cell, and it is not necessary and relatively slow.
Posted: Sat Nov 05, 2005 9:40 pm
by Sergey Tkachenko
Now about writing from stream to the cell.
There are two ways
1) First, using LoadRVFFromStream.
This method cannot be undone/redone and damages undo buffers (as viewer-style method), so call RichViewEdit1.ClearUndo after calling it.
Cell loading does not support styles, so we must turn off style reading from RVF wile loading.
Code: Select all
var oldps, oldts:TRVFReaderStyleMode;
oldps := RichViewEdit1.RVFParaStylesReadMode;
oldts := RichViewEdit1.RVFTextStylesReadMode;
RichViewEdit1.RVFParaStylesReadMode := rvf_sIgnore;
RichViewEdit1.RVFTextStylesReadMode := rvf_sIgnore;
MS.Position := 0;
DestCell.GetRVData.LoadRVFFromStream(MS, <...>);
RichViewEdit1.RVFParaStylesReadMode := oldps;
RichViewEdit1.RVFTextStylesReadMode := oldts;
RichViewEdit1 is TDBRichViewEdit, call RichViewEdit1.CanChange before and RichViewEdit1.Change after the operation.
2) Preferred method for editor:
Code: Select all
DestCell.Edit;
RichViewEdit1.TopLevelEditor.SelectAll;
RichViewEdit1.TopLevelEditor.InsertRVFFromStreamEd(MS);
PS: Do not forget to call MS.Free after loading
PPS: Tables already have methods for copying multicell range, but loading it currently has some limitations which will be removed in one of next updates.
Posted: Sun Nov 06, 2005 7:39 am
by Guest
Hello,
you are on another level than I.
Is it therefore not more simply for you to show the correct solution, because people will ask you again if there is an error or they have missunderstand you ?
procedure TForm1.SpalteKopierenClick(Sender: TObject);
var oldps, oldts:TRVFReaderStyleMode;
destCell: TRVTableCellData;
begin
if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
ShowMessage('Tabelle hat nicht den Focus.');
exit;
end;
//if (not memo.CanChange) then exit; //s.o.
oldps := memo.RVFParaStylesReadMode;
oldts := memo.RVFTextStylesReadMode;
memo.RVFParaStylesReadMode := rvf_sIgnore;
memo.RVFTextStylesReadMode := rvf_sIgnore;
stream1.Position := 0;
//DestCell.GetRVData.LoadRVFFromStream(Stream1, < whatever I write, I get an error >); <<--------------------
{function LoadRVFFromStream(Stream: TStream; var Color: TColor;
Background: TRVBackground; Layout: TRVLayoutInfo):Boolean;}
memo.RVFParaStylesReadMode := oldps;
memo.RVFTextStylesReadMode := oldts;
memo.Change;
end;
procedure TForm1.SpalteEinfuegenClick(Sender: TObject);
var destCell: TRVTableCellData;
begin
if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
ShowMessage('Tabelle hat nicht den Focus.');
exit;
end;
// because of error in procedure TForm1.SpalteKopierenClick
DestCell.Edit;
memo.TopLevelEditor.SelectAll;
memo.TopLevelEditor.InsertRVFFromStreamEd(Stream1);
//Stream1 created and free in form1.activate and form1.close
end;
Posted: Sun Nov 06, 2005 2:07 pm
by Michel
I can only fluently write in C++, and it may not be of much help, so I'll leave the challenge up to Sergey!
The point you seem to be missing though is that the code snippets we have suggested are just that - the most crucial
pieces that are supposed to be integrated into your original code from your first post.
In the last code you posted you were obviously missing
DestCell := rveTable.Cells[r, c];
or similar. But this and all that stuff needs to go into your original functions - where you do somehow get the r and c of interest.
Sorry if I can't offer a complete solution.
Michel
Posted: Sun Nov 06, 2005 6:05 pm
by j&b
Hello Michel,
I am happy that you (or other people) give me a hint so that I further can go on at my work (if I could convert the hints). Often it is so that one only gets some code, which can't be used in lack of experience or knowledge.
In this case you/Sergey use a shortened call (DestCell.GetRVData.LoadRVFFromStream(MS, <...>)).
I looked up for the parameters in RVData.pas
(function LoadRVFFromStream(Stream: TStream; var Color: TColor;
Background: TRVBackground; Layout: TRVLayoutInfo):Boolean
and tried it with them. The result is an error.
In addition that I am not sure if I set the code correctly in my program I think that often it is better for both sides (and the inexperienced readers of the question) that helper give an executable code (with call).
Here I would thank expressly Sergey for his many helps and I hope that he doesn't understand my inquiring as beef.
Jürgen
Posted: Sun Nov 06, 2005 8:48 pm
by Michel
Hey there!
I haven't tried it, but I think that call should go something like this:
Code: Select all
var DummyColor: TColor;
LoadRVFFromStream(MS, DummyColor, nil, nil);
If that's not what you have tried, try this. If it still gives you trouble, let us know what the exact results/problems are (e.g., when you say "error" - what is it?). Perhaps once you have hit the proverbial "brick wall" it'd be time for you to re-post your latest code (so that Sergey could take a look
).
All this stuff takes a little time to wrap one's head around, so don't give up. Good luck!
Michel
Posted: Sun Nov 06, 2005 9:57 pm
by Sergey Tkachenko
Copying the column SourceCol to the column DestCol.
Code: Select all
procedure CopyTableColumn(rv: TCustomRichView; table: TRVTableItemInfo;
SourceCol, DestCol: Integer);
var r: Integer;
Stream: TMemoryStream;
UnusedColor: TColor;
oldps, oldts:TRVFReaderStyleMode;
begin
if SourceCol=DestCol then
exit;
UnusedColor := clNone;
oldps := rv.RVFParaStylesReadMode;
oldts := rv.RVFTextStylesReadMode;
rv.RVFParaStylesReadMode := rvf_sIgnore;
rv.RVFTextStylesReadMode := rvf_sIgnore;
try
for r := 0 to table.Rows.Count-1 do
if (table.Cells[r, SourceCol]<>nil) and
(table.Cells[r, DestCol]<>nil) then begin
Stream := TMemoryStream.Create;
try
table.Cells[r, SourceCol].GetRVData.SaveRVFToStream(Stream,
False, UnusedColor, nil, nil);
Stream.Position := 0;
table.Cells[r, DestCol].GetRVData.LoadRVFFromStream(Stream,
UnusedColor, nil, nil);
finally
Stream.Free;
end;
end;
finally
rv.RVFParaStylesReadMode := oldps;
rv.RVFTextStylesReadMode := oldts;
end;
end;
This method works for all RichViews, not only for the editors.
It cannot be undone/redone.
Example of call (I assume that you already assigned table variable):
Code: Select all
CopyTableColumn(RichViewEdit1, table, 0, 1);
RichViewEdit1.ClearUndo;
RichViewEdit1.Format;
Example of call for DBRichViewEdit:
Code: Select all
if DBRichViewEdit1.CanChange then begin
CopyTableColumn(DBRichViewEdit1, table, 0, 1);
DBRichViewEdit1.ClearUndo;
DBRichViewEdit1.Change;
DBRichViewEdit1.Format;
Posted: Sun Nov 06, 2005 10:03 pm
by Sergey Tkachenko
This method can be called only for editors, and it can be undone/redone by the user.
Code: Select all
procedure CopyTableColumnEd(rv: TCustomRichViewEdit; table: TRVTableItemInfo;
SourceCol, DestCol: Integer);
var r: Integer;
Stream: TMemoryStream;
UnusedColor: TColor;
oldps, oldts:TRVFReaderStyleMode;
begin
if SourceCol=DestCol then
exit;
UnusedColor := clNone;
oldps := rv.RVFParaStylesReadMode;
oldts := rv.RVFTextStylesReadMode;
rv.RVFParaStylesReadMode := rvf_sIgnore;
rv.RVFTextStylesReadMode := rvf_sIgnore;
SendMessage(rv.Handle, WM_SETREDRAW, 0, 0);
try
for r := 0 to table.Rows.Count-1 do
if (table.Cells[r, SourceCol]<>nil) and
(table.Cells[r, DestCol]<>nil) then begin
Stream := TMemoryStream.Create;
try
table.Cells[r, SourceCol].GetRVData.SaveRVFToStream(Stream,
False, UnusedColor, nil, nil);
Stream.Position := 0;
table.Cells[r, DestCol].Edit;
rv.TopLevelEditor.SelectAll;
rv.TopLevelEditor.InsertRVFFromStreamEd(Stream);
finally
Stream.Free;
end;
end;
finally
rv.RVFParaStylesReadMode := oldps;
rv.RVFTextStylesReadMode := oldts;
SendMessage(rv.Handle, WM_SETREDRAW, 1, 0);
while rv<>nil do begin
rv.Invalidate;
rv := TCustomRichViewEdit(rv.InplaceEditor);
end;
end;
end;
Calling is the same for DBRichViewEdit and RichViewEdit:
Code: Select all
CopyTableColumn(RichViewEdit1, table, 0, 1);
Since editing-style method is used (InsertText), CanChange+Change+ClearUndo+Format are not required.
PS: Modifying RVFParaStylesReadMode and RVFTextStylesReadMode is not required in this method, but makes loading faster a bit.
Posted: Sun Nov 06, 2005 10:20 pm
by Michel
You never sleep, Sergey, do you?
Just a little question for my own understanding: why is it necessary (especially in this example) to set
RVF*StylesReadMode := rvf_sIgnore? Here's why I'm asking:
A) As we have discussed earlier in the "Cell Streaming does not save Styles" thread, SaveRVFToStream() doesn't appear to be saving any styles to the stream, so there should be nothing to ignore, and
B) The saving/loading operations are obviously within the same RichView, so "incoming" styles (if any) would be the same ones we already have, so we can't get any problems with styles "overlapping" or missing.
I suspect that I am overlooking some subtle (or not) problem, so I would greatly appreciate it if you could explain this.
Thanks!
Michel
Posted: Mon Nov 07, 2005 9:51 am
by Sergey Tkachenko
Well, really, if RVF does not contain styles, it's not necessary to set modes to ignore.
In the second example, it is not necessary because editor.InsertRVFFromStreamEd supports styles. But... In the ignore mode, the i-th style in RVF is mapped to the i-th style of document. In the merge mode, the component first tries to find the existing style equal to the style from RVF. If all styles are unique (which is normal), the i-th style will be mapped to the i-th style. But if, for some reason, they are not unique, it will be mapped to another style (visually the same, though). Exception: list styles are mapped to the same list styles when copying from the same document (it's not necessary for numbering to be unique). So, the ignore mode has 2 benefits: it is faster, and it guarantees the exact copy of the original.
Posted: Mon Nov 07, 2005 12:38 pm
by Michel
Thanks, Sergey, for a very clear explanation! That was pretty much my understanding from reading the Help, and that's why I got a bit surprised when you seemed to have insisted on forcing the ignore mode.
Thanks again,
Michel