Возник вопрос по RichEdit:
Есть в нем метод сохранить в файл. При установке PlainText = false; все сохраняется с форматированием.
Но есть необходимость сохранять не все, а только выделенный фрагмент текста.
И вот тут я наткнулся на то что RichEdit->SelText дает AnsiString который форматирование то и не поддерживает.
т.е. мне нужно что то такое чтобы его поддерживало, но кроме richEdit более ничего нет. А создавать еще один чтобы через ClipBoard переносить данные не кажется оптимальным.
Есть ли выход или направление куда двигаться ?
richEdit, сохранить выделенное в rtf
Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду
- Naeel Maqsudov
- Сообщения: 2570
- Зарегистрирован: 20 фев 2004, 19:17
- Откуда: Moscow, Russia
- Контактная информация:
Двигаться в подобных ситуациях надо в следующем направлении:
1)
Вызвать сохранение в файл и выполнить под отладчиком по шагам.
Тогда Вы увидите, что сохранение выполняется методом
procedure TRichEditStrings.SaveToStream(Stream: TStream);
который описан в ComCtrls.pas
А конкретно командой
SendMessage(RichEdit.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
2)
Пойти на msdn и почитать про сообщение EM_STREAMOUT. Эврика! Оказывается TextType=SF_RTF, а мог бы быть SF_RTF+SFF_SELECTION и тогда произошло бы сохранение выделенного фрагмента!
3)
Выдираете из ComCtrls.pas код VCL и переписываете его по-своему (добавляя "+SFF_SELECTION" в нужном месте)
4)
получается что-то типа:
[syntax=Delphi]
function StreamSave(dwCookie: Longint; pbBuff: PByte;
cb: Longint; var pcb: Longint): Longint; stdcall;
var
StreamInfo: PRichEditStreamInfo;
begin
Result := NoError;
StreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
try
pcb := 0;
if StreamInfo^.Converter <> nil then
pcb := StreamInfo^.Converter.ConvertWriteStream(StreamInfo^.Stream, PChar(pbBuff), cb);
except
Result := 2;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
EditStream: TEditStream;
TextType: Longint;
StreamInfo: TRichEditStreamInfo;
Converter: TConversion;
begin
StreamInfo.Stream := TFileStream.Create('c:\0.rtf', fmCreate);
StreamInfo.Converter := RichEdit1.DefaultConverter.Create;
try
with EditStream do
begin
dwCookie := LongInt(Pointer(@StreamInfo));
pfnCallBack := @StreamSave;
dwError := 0;
end;
TextType := SF_RTF + SFF_SELECTION;
SendMessage(RichEdit1.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
if EditStream.dwError <> 0 then
raise EOutOfResources.Create('Ошибка сохранения');
finally
StreamInfo.Converter.Free;
StreamInfo.Stream.Free;
end;
end;
[/syntax]
1)
Вызвать сохранение в файл и выполнить под отладчиком по шагам.
Тогда Вы увидите, что сохранение выполняется методом
procedure TRichEditStrings.SaveToStream(Stream: TStream);
который описан в ComCtrls.pas
А конкретно командой
SendMessage(RichEdit.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
2)
Пойти на msdn и почитать про сообщение EM_STREAMOUT. Эврика! Оказывается TextType=SF_RTF, а мог бы быть SF_RTF+SFF_SELECTION и тогда произошло бы сохранение выделенного фрагмента!
3)
Выдираете из ComCtrls.pas код VCL и переписываете его по-своему (добавляя "+SFF_SELECTION" в нужном месте)
4)
получается что-то типа:
[syntax=Delphi]
function StreamSave(dwCookie: Longint; pbBuff: PByte;
cb: Longint; var pcb: Longint): Longint; stdcall;
var
StreamInfo: PRichEditStreamInfo;
begin
Result := NoError;
StreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
try
pcb := 0;
if StreamInfo^.Converter <> nil then
pcb := StreamInfo^.Converter.ConvertWriteStream(StreamInfo^.Stream, PChar(pbBuff), cb);
except
Result := 2;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
EditStream: TEditStream;
TextType: Longint;
StreamInfo: TRichEditStreamInfo;
Converter: TConversion;
begin
StreamInfo.Stream := TFileStream.Create('c:\0.rtf', fmCreate);
StreamInfo.Converter := RichEdit1.DefaultConverter.Create;
try
with EditStream do
begin
dwCookie := LongInt(Pointer(@StreamInfo));
pfnCallBack := @StreamSave;
dwError := 0;
end;
TextType := SF_RTF + SFF_SELECTION;
SendMessage(RichEdit1.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
if EditStream.dwError <> 0 then
raise EOutOfResources.Create('Ошибка сохранения');
finally
StreamInfo.Converter.Free;
StreamInfo.Stream.Free;
end;
end;
[/syntax]
Огромное Спасибо, Naeel Maqsudov.
В моем случае 1 пункт не проходит, пишу на С++ и все встроенные функции выполняются без возможности посмотреть. Так же я не смог найти описание TRichEditStrings.SaveToStream, т.е. в хедере она указана, но код её реализации скрыт.
Неделю назад я нашел вариант реализации на С но тогда не смог его понять...
хотя конечно в msdn заглянуть стоило, потому как
SendMessage(RichEdit.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
там был, и уверенность, что это ОНО, заставила бы разобраться.
Благодаря приведенному коду все получилось !
Единственая непонятка в данном случае это:
вероятно здесь происходит заполнение полей буфера и числа байт для записи функцией StreamSave, но в моем случае этого не происходило 
возможно это связано с тем что свойство DefaultConverter является указателем на TMetaClass, а в нашем случае нужен TConversion.
проблему я решил через
но хотелось бы понять причину 
В моем случае 1 пункт не проходит, пишу на С++ и все встроенные функции выполняются без возможности посмотреть. Так же я не смог найти описание TRichEditStrings.SaveToStream, т.е. в хедере она указана, но код её реализации скрыт.
Неделю назад я нашел вариант реализации на С но тогда не смог его понять...
хотя конечно в msdn заглянуть стоило, потому как
SendMessage(RichEdit.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
там был, и уверенность, что это ОНО, заставила бы разобраться.
Благодаря приведенному коду все получилось !

Единственая непонятка в данном случае это:
Код: Выделить всё
StreamInfo.Converter := RichEdit1.DefaultConverter.Create;

возможно это связано с тем что свойство DefaultConverter является указателем на TMetaClass, а в нашем случае нужен TConversion.
проблему я решил через
Код: Выделить всё
hFile = OpenFile(anFileName.c_str(), &of, OF_CREATE);
EditStream.dwCookie = (DWORD)hFile;

- Naeel Maqsudov
- Сообщения: 2570
- Зарегистрирован: 20 фев 2004, 19:17
- Откуда: Moscow, Russia
- Контактная информация:
Если все получилось, и работает, то забейте....
Это в Delphi, в VCL так сделано, что RichEdity через EM_STREAMOUT отдается не экземпляр обычного TStream засубклассенный стрим, могущей писать данные через конвертеры.
Ну, вроде как, если написать свой конвертер, то можно не только в RTF сохранять, а вообще в чем угодно.... VCL, блин...
Это в Delphi, в VCL так сделано, что RichEdity через EM_STREAMOUT отдается не экземпляр обычного TStream засубклассенный стрим, могущей писать данные через конвертеры.
Ну, вроде как, если написать свой конвертер, то можно не только в RTF сохранять, а вообще в чем угодно.... VCL, блин...