RichMemo/ru

From Free Pascal wiki
Jump to navigationJump to search

English (en) polski (pl) русский (ru)

RichMemo macosx screenshot. Thanks to Dominique Louis

RichMemo - это пакет, который включает компонент для замены компонента Delphi TRichEdit. Он разработан кросс-платформенным способом, поэтому его реализация возможна для следующих платформ: Win32, MacOSX и Linux. Поскольку кроссплатформенность является основной целью, нативный API RichMemo может быть расширен, чтобы сделать его совместимым с Delphi RichEdit.

Его основными характеристиками являются:

  • Подсветка текста
  • Системная поддержка редактирования Юникода

Планируется: (исправления приветствуются)

  • Добавление изображений в текст
  • Встраивание элементов управления LCL?

Загружаемый файл содержит компонент, установочный пакет и демонстрационное приложение, которое иллюстрирует возможности компонента, а также некоторые инструменты для оценки диаграммы в данной системе.

Пожалуйста, добавляйте ваши багрепорты/функции в Lazarus CCR багтрекера Lazarus.


Лицензия

Автор: Дмитрий 'скалогрыз' Бояринцев

modified LGPL (так же, как FPC RTL и Lazarus LCL). Вы можете связаться с автором, если измененный LGPL не работает с вашим проектом лицензирования.

Загрузка

Последний транк доступен здесь: https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/richmemo


Прим.перев.: Существует также форк данного компонента на гитхабе от Andreas Toth aka mrandreastoth.

Change Log

  • Version 1.0.0 22th Jun 2009
  • Version 0.8.0 Jun 2009

Зависимости / Системные требования

  • Lazarus 1.0.0

Статус: выпущен.

Установка

  • Скачайте исходники пакета
  • Установите пакет в Lazarus и пересоберите его
  • TRichMemo добавится в закладку 'Common Controls'.

RichMemoPalette.PNG

TRichMemo

Параметры шрифта

Параметры шрифта обычно представлены записью TFontParams. Тип используется для описания атрибутов шрифта rich. Некоторые атрибуты выходят за рамки класса TFont, поэтому необходим дополнительный тип. Однако большинство типов данных, связанных с TFont, используются повторно (т.е. TFontStyles).

  • Name - название шрифта (семейство).
  • Size - размер шрифта в пунктах (передача отрицательного значения может привести к неожиданным результатам).
  • Color - цвет шрифта.
  • Style - стили шрифта, включая полужирный, курсив, зачеркнутый, подчеркивание.
  • HasBkClr - логический флаг, если текст для должен иметь цвет фона (если true, поле BkColor используется, в противном случае BkColor игнорируется). Прозрачность не поддерживается.
  • BkColor - цвет фона (или подсветка) для текста.
  • VScriptPos - вертикальная настройка текста
    richmemo Subsuper.png
    .
    • vpNormal - нет особой позиции.
    • vpSubscript - текст - нижний индекс.
    • vpSuperscript - текст - верхний индекс.
Фактическое вертикальное смещение индексов верх/низ зависит от реализации ОС и в настоящее время не может контролироваться.

Вы можете присвоить FontParams из структуры TFont. Для этого вам нужно использовать функцию GetFontParams(afont: TFont). Обратите внимание, что для большинства элементов управления LCL для TFont установлены значения по умолчанию. Это не фактические значения, а скорее указание на то, что следует использовать шрифт по умолчанию для элемента управления (аналогично crDefault для TColor).

Функция GetFontParams разрешает имя шрифта по умолчанию и возвращает фактическое имя семейства шрифтов.

Методы

SetTextAttributes

procedure SetTextAttributes(TextStart, TextLen: Integer; AFont: TFont);
  • TextStart : Integer - первый символ, который будет изменен
  • TextLen : Integer - количество символов для изменения
  • AFont : TFont - шрифт, который должен быть применен к части текста
procedure SetTextAttributes(TextStart, TextLen: Integer; const TextParams: TFontParams);
  • TextStart : Integer - первый символ, который будет изменен
  • TextLen : Integer - количество символов для изменения
  • TextParams : TFontParams - параметры шрифта, которые будут установлены

Методы SetTextureAttributes изменяют указанный стиль текстового диапазона. Параметры шрифта передаются в обоих методах, параметром AFont (объект LCL TFont) или TFontParams (объявлено в RichMemo)

Установка атрибутов текста не меняет текущий выбор. Если необходимо изменить стиль выделенного в данный момент текста, вам следует выбрать SelStart и SelLength в качестве значений текстового диапазона:

RichMemo1.SetTextAttributes(RichMemo1.SelStart, RichMemo1.SelLength, FontDialog1.Font);

GetTextAttributes

function GetTextAttributes(TextStart: Integer; var TextParams: TFontParams): Boolean; virtual;
  • TextStart : Integer - позиция символа для запроса параметров шрифта
  • var TextParams : TFontParams - выходное значение, заполненное атрибутами символа шрифта. Если метод завершается неудачно и возвращает false, значения поля записи будут неопределенными.

Заполняет параметры шрифта символа в позиции TextStart. Метод возвращает True, если TextStart является действительной позицией символа, и False в противном случае.

GetStyleRange

function GetStyleRange(CharPos: Integer; var RangeStart, RangeLen: Integer): Boolean; virtual;

Возвращает диапазон символов с одинаковыми параметрами шрифта, т.е. все символы в диапазоне имеют одинаковые имя, размер, цвет и стили шрифта.

  • CharPos : Integer - символ, который принадлежит диапазону стилей. Позиция не обязательно быть в начале диапазона стилей. Она может быть в середине конца диапазона стилей. Первая позиция символа возвращается параметром RangeStart.
  • var RangeStart : Integer - первый символ в диапазоне
  • var RangeLen : Integer - количество символов в диапазоне

Метод возвращает true в случае успеха. Метод возвращает false, если CharPos имеет неправильное значение - больше доступных символов или какая-либо другая ошибка.

CharAtPos

function CharAtPos(x,y: Integer): Integer; virtual;

Возвращает смещение символа от нулевой позиции (не позиция UTF8). Возвращает -1 в случае неудачи.

  • x, y - точка в клиентской области элемента управления RichMemo.

Метод знает о состоянии прокрутки элемента управления. Таким образом, два вызова CharAtPos(0,0) могут возвращать разные значения, если между вызовами изменяется позиция прокрутки. Смотрите "examples/hittest" для [получения] примера использования.

Если указанные x,y будут вне содержимого RichMemo, возвращаемое значение [будет] неопределенным. [Поведение] остается [на усмотрение] набора виджетов, который либо возвращает -1, либо закрывает доступный символ.

SetRangeColor

procedure SetRangeColor(TextStart, TextLength: Integer; FontColor: TColor);

Метод устанавливает цвет символов в указанном диапазоне для FontColor. Другие параметры шрифта (имя, размер, стили) остаются без изменений.

  • TextStart: Integer - первый символ в диапазоне
  • TextLength: Integer - количество символов в диапазоне
  • FontColor: TColor - цвет, который должен быть установлен

SetRangeParams

    procedure SetRangeParams(TextStart, TextLength: Integer; ModifyMask: TTextModifyMask;
      const fnt: TFontParams; AddFontStyle, RemoveFontStyle: TFontStyles); overload;

Метод изменяет параметры шрифта в указанном диапазоне.

  • TextStart - первый символ в диапазоне
  • TextLength - количество символов в диапазоне
  • ModifyMask - показывает, какие именно атрибуты шрифта должны быть обновлены. Маска принимает любую комбинацию из следующих значений:
    • tmm_Color - Цвет шрифта будет изменен (поле fnt.Color должно быть заполнено)
    • tmm_Name - имя шрифта будет изменено (поле fnt.Name должно быть заполнено)
    • tmm_Size - размер шрифта будет изменен (поле fnt.Size должно быть заполнено)
    • tmm_Styles - стили шрифта будут изменены в соответствии с параметрами AddFontStyle, RemoveFontStyle
    • tmm_BackColor - Цвет подсветки текста (фона) будет изменен. (поля fnt.HasBkClr и fnt.BkColor должны быть заполнены)
    • Отправка пустой маски приведет к возврату метода без внесения каких-либо изменений.
  • fnt - Параметры шрифта, которые будут использоваться, в зависимости от значений ModifyMask.
  • AddFontStyle - набор стилей, которые должны применяться к диапазону (используется только если tmm_Styles в ModifyMask, в противном случае игнорируется)
  • RemoveFontStyle - набор стилей шрифта должен быть удален из диапазона (используется только если tmm_Styles в ModifyMask, в противном случае игнорируется)


procedure SetRangeParams(TextStart, TextLength: Integer;
    ModifyMask: TTextModifyMask; const FontName: String; 
    FontSize: Integer; FontColor: TColor; 
    AddFontStyle, RemoveFontStyle: TFontStyles);

Перегруженная версия метода. Это просто оболочка вокруг параметра, использующая структуру TFontParams. Метод не поддерживает изменение цвета фона, вы должны использовать версию TFontParams

  • FontName - имя шрифта, которое должно быть установлено (используется только если tmm_Name в ModifyMask, в противном случае игнорируется)
  • FontColor - Цвет шрифта, который должен быть установлен (используется только если tmm_Color в ModifyMask, в противном случае игнорируется)

Например, если используется следующий код

  RichMemo1.SetRangeParams ( 
     RichMemo1.SelStart, RichMemo1.SelLength,
     [tmm_Styles, tmm_Color], // только изменение цвета и стиля
     '',  // имя шрифта - оно не используется, поэтому мы можем оставить его пустым
     0,  // размер шрифта - это размер шрифта, мы можем оставить его пустым
     clGreen, // сделать весь текст в выбранной области зеленым цветом
     [fsBold, fsItalic],  // добавление жирного и курсивного стилей
     []
  );

GetParaAlignment

Получает выравнивание абзаца

function GetParaAlignment(TextStart: Integer; var AAlign: TParaAlignment): Boolean;
  • TextStart - позиция символа, который принадлежит абзацу
  • AAlign - получение выравнивания абзаца.

Примечание:

  • Win32 - выравнивание по ширине не работает в Windows XP и более ранних версиях.
  • OSX - из-за ограничений Carbon, это не работает в Carbon, но работает для виджетов Cocoa.

SetParaAlignment

Устанавливает выравнивание абзаца

procedure SetParaAlignment(TextStart, TextLen: Integer; AAlign: TParaAlignment);

Примечание:

  • Win32 - выравнивание по ширине не работает в Windows XP и более ранних версиях.
  • OSX - из-за ограничений Carbon, это не работает в Carbon, но работает для виджетов Cocoa. Также необходимо, чтобы правильное выравнивание было загружено из файла RTF.

GetParaMetric

Возвращает отступ метрики абзаца для данного абзаца

richmemo parametric.PNG
  • FirstLine - смещение для первой строки (в пунктах) абзаца от начала элемента управления [(т.н. "красная строка")]
  • TailIndent - смещение для каждой строки (в пунктах), за исключением первой строки, абзаца от конца элемента управления
  • HeadIndent - смещение для каждой строки (в пунктах) абзаца от начала элемента управления
  • SpaceBefore - дополнительное место перед абзацем (в пунктах)
  • SpaceAfter - дополнительное место после абзаца (в пунктах)
  • LineSpacing - коэффициент, используемый для расчета межстрочного интервала между строками в абзаце. Коэффициент применяется к размеру шрифта (самый высокий в строке), а не к высоте строки. Таким образом, это соответствует свойству CSS line-height. Обратите внимание, что нормальный межстрочный интервал равен 1,2. То есть шрифт размером 12 пт, фактический межстрочный интервал (равный 1,2) приведет к высоте строки 14 пт.
    • не поддерживается в WinXP или более ранних версиях
    • в большинстве систем не будет разрешено, если для межстрочного интервала установлено значение меньше 1,2. Значение будет проигнорировано, и оно по умолчанию будет равно 1,2

Примечание

  • Параметры абзаца RichEdit указываются в пикселях, а не в точках, поэтому вам нужно либо преобразовать эти размеры самостоятельно, либо использовать метод RichMemoHelper.
  • обозначение смещений «влево»/«вправо» исключено, чтобы избежать путаницы для RTL.
function GetParaMetric(TextStart: Integer; var AMetric: TParaMetric): Boolean;

SetParaMetric

Устанавливает метрики абзаца

procedure SetParaMetric(TextStart, TextLen: Integer; const AMetric: TParaMetric);

Рекомендуется использовать функцию InitParaMetric для инициализации структуры TParaMetric. В противном случае обнуление структуры равно ее размеру (т.е. достаточно FillChar(m, sizeof(TParaMetric), 0). Если значения TParaMetric получены из вызова GetParaMetric, то структура считается правильно инициализированной).

GetParaRange

Returns character range for a paragraph. The paragraph is identified by a character.

  function GetParaRange(CharOfs: Integer; var ParaRange: TParaRange): Boolean; 
  function GetParaRange(CharOfs: Integer; var TextStart, TextLength: Integer): Boolean;

CharOfs - is a character that belongs to a paragraph which range is returned. TParaRange - is a structure that returns 3 fields

  • start - the first character in the paragraph
  • lengthNoBr - the length of the paragraph, excluding the line break character
  • length - the length of the paragrpah, including the line break, if present the last line in the control doesn't contain a line break character, thus length = lengthNoBr value.

SetParaTabs

Sets the set of tab stops to paragraphs in the specified length.

  procedure SetParaTabs(TextStart, TextLen: Integer; const AStopList: TTabStopList);
  • TextStart
  • TextLen
  • AStopList - the structure that contains an array of tab stops.
    • Count - specifies the number of initialized elements.
    • Tabs - array contains the description of each tab stop, consisting of an Offset and Alignment.
      • Offset - the tab point offset in points (from the left side of the control)
      • Align - the alignment of the tab stop (tabLeft - default one, tabCenter, tabRight, tabDecimal).

Notes

Renamefest
Prior to r4140 TTabAlignment enum values were taLeft, taCenter, taRight, taDecimal,but it did collide with Classes.TAlignment declarations. Thus the suffix was changed.
win32
allows no more that 32 tabs
gtk2
only tabLeft align is supported
carbon
not implemented

GetParaTabs

Gets the tab stops array. If no specific tabs were specified (widget default tab stops) AStopList count would be set to 0.

 function GetParaTabs(CharOfs: Integer; var AStopList: TTabStopList): Boolean;

SetRangeParaParams

Sets paragraph metrics selectively

 procedure SetRangeParaParams(TextStart, TextLength: Integer; ModifyMask: TParaModifyMask; const ParaMetric: TParaMetric);
  • TextStart - the character of the the first paragraph to apply the style too
  • TextLength - the number of characters that paragraph properties should be modified
  • ModifyMask - masks the identifies what para metric should be set for each paragraph within TextStart..TextLength block. Other characters will be left unmodified. Members of the set are
    • pmm_FirstLine - changes the first line indentation. FirstLine field of ParaMetric must be initialized
    • pmm_HeadIndent - changes the heading paragraph indentation. HeadIndent field of ParaMetric must be initialized
    • pmm_TailIndent - changes the trail paragraph indentation. TailIndent field of ParaMetric must be initialized
    • pmm_SpaceBefore - changes the space preceding . SpaceBefore field of ParaMetric must be initialized
    • pmm_SpaceAfter - changes the space after (below) the paragraph. SpaceAfter field of ParaMetric must be initialized
    • pmm_LineSpacing - line spacing within paragraph. LineSpace field of ParaMetric must be initialized
  • ParaMetric - the structure containing the values to be set. Only fields specified by ModifyMask should be initialized

LoadRichText

function LoadRichText(Source: TStream): Boolean; virtual;
  • Source: TStream - a stream to read richtext data from

The method loads RTF enocded data from the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false

The content of TRichMemo is completely replaced by the content on the source stream. Current text selection is reset.

SaveRichText

function SaveRichText(Dest: TStream): Boolean; virtual;
  • Source: TStream - a stream to read richtext data from

The method saves RTF enocded data to the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false

Current state of TRichMemo is unchanged after the method returns

Search

function Search(const ANiddle: string; Start, Len: Integer; const SearchOpt: TSearchOptions): Integer;
  • ANiddle: string - a text to search for
  • Start: Integer - a character position to start search from, if -1 or 0 search from the start
  • Len: Integer - length (in characters, not bytes) of the text to search for the niddle.
  • SearchOpt: TSearchOptions
    • soMatchCase - case sensitive search
    • soBackward - searching from the end of the document to the character identified by "Start" parameter
    • soWholeWord - searching for the whole word

The method returns the character position of the found sub-string. The position is suitable for use in SelStart property. However, might not be usable for the direct Copy operation, if Unicode characters are present in the code. Instead UTF8Copy should be used.

If the ANiddle was not found in the text, -1 is returned

function Search(const ANiddle: string; Start, Len: Integer; const SearchOpt: TSearchOptions;
  var TextStart, TextLength: Integer): Boolean;

(The method is introduced with r5115)

  • ANiddle: string - a text to search for
  • Start: Integer - a character position to start search from, if -1 or 0 search from the start
  • Len: Integer - length (in characters, not bytes) of the text to search for the niddle.
  • SearchOpt: TSearchOptions
    • soMatchCase - case sensitive search
    • soBackward - searching from the end of the document to the character identified by "Start" parameter
    • soWholeWord - searching for the whole word
  • (output) ATextStart - a position of the text found (in characters)
  • (output) ATextLength - length of the text found (in characters (cursor positions!))

The method returns the true if searched sub-string is found, false otherwise.

The returned ATextStart and ATextLength values are suitable for use in SelStart and SelLength properties.

Note: for complex scripts, the found text might be exactly the same as the sub-string searched. The search behavior (on complex scripts) is widgetset specific. Thus searching for the same string on different widgetsets (i.e. win32 or gtk2) might produce different results. If you need the same results and don't get them, please create a bug report.


If you need to extract the found text, you should use GetText() method (passing ATextStart and ATextLength values).

GetText, GetUText

    function GetText(TextStart, TextLength: Integer): String;
    function GetUText(TextStart, TextLength: Integer): UnicodeString;
  • TextStart: Integer - a character position to start extract from. (0 - is the first character in the text).
  • TextLength: Integer - length (in characters, not bytes) of the text to extract

GetText() returns UTF8 sub-string

GetUText() returns UTF16 sub-string

Current selection would not be affected by the operation. (If you see the selection affected, please report as an issue).

You should not consider the efficiency of either method. For example, WinAPI internally operates with UTF16 characters, thus GetUText() might be more efficient for it. While Gtk2 operates UTF8 and calling GetText() might be more efficient for it. Instead of thinking about underlying system, you should be considering the needs of your task.

Redo

    procedure Redo;

The method redos the last change undone previously.

You can always call CanRedo to check, if there're any actions can be redone.

properties

ZoomFactor

property ZoomFactor: double

Read/Write property. Controls zooming of the RichMemo content. 1.0 - is no-zoom. Less than < 1.0 - decrease zoom, more than 1.0 - increasing zooming. If 0 is set - value defaults to 1.0 zoom factor (no zoom).

HideSelection

property HideSelection: Boolean default false

Read/Write property. If True RichMemo selection is hidden if the control is not focused. If False, the selection is shown all the time.

CanRedo

property CanRedo: Boolean

If True, there're actions in Undo queue that can be redone. If False, there are no actions in Undo queue that can be redone. Calling to Redo won't have any effect.

Rtf

property Rtf: String
RtfEditor.PNG

Read/Write property that allows to read or write Rich-Text Formatted (RTF) text to the whole control. The intent of the property is to have an ability to set Rich-Text in design time, however the property would work in run-time as well.

If then property value is an empty string then Lines property is used as a plain text to initialize control value in load-time.

Note: The property is available in TRichMemo class only, it's not available (or even implemented in anyway) in TCustomRichMemo class. It is recommended to use LoadRichText/SaveRichText in order to modify the content of the page, just because they could consume less memory, than copying the whole rich-text into the memory.

Cross-platform and Forward Compatibility Note: - currently the property is implemented based on the widgetset providede Rich-text read/write routines. It is very likely that in near future it would be changed to used RichMemo read/write RTF stream code only. The issue is with older systems might not support the latest version of RTF.

So right now, you might run into an issue, If you create a project in Gtk2 and save the richmemo is design time containing Unicode characters. Then if you try to load it on the XP machine and would use widgetset native loader, you might see characters missing or rendered improperly. Changing to the usage of RichMemo RTF loader/saver will prevent this issue from happening. Currently you can also avoid it by registering RichMemo loaders (call RegisterRTFLoader, RegisterRTFSaver procedures in project initialization, before any RichMemo is loaded)

events

OnSelectionChange

property OnSelectionChange: TNotifyEvent
TNotifyEvent = procedure (Sender: TObject) of object;

The event is fired whenever, selection is changed within RichMemo, either programmatically or due to the user action.

TRichEditForMemo

The class helper that implements RichEdit programmatic interface. The helper is declared at RichEditHelpers unit, so you have to add it to the uses section. Helpers are available in FPC 2.6.0 or later.

methods

FindText

Searches a given range in the text for a target string

properties

SelAttributes

Reads/Modifies character attributes of the current selection.

Paragraph

Reads/Modifies paragraph attributes of the current selection.

RichMemoUtils

The unit is introduced to add some useful OS-specific features for handling working with RichMemo

InsertImageFromFile

function InsertImageFromFile (const ARichMemo: TCustomRichMemo; APos: Integer;
    const FileNameUTF8: string;
    const AImgSize: TSize
): Boolean = nil;

Disclaimer: the function would insert an image file into RichMemo (if implemented by the widgetset) But in a very inefficient way. The image would be read again and the memory would be re-allocated for the image every time. So please, don't use it for smileys in your chat instant messaging. A better API (with data caching) is considered. (That's why this method is not part of TCustomRichMemo class).

  • APos - position in the text
  • AImgSize - size to be inserted in POINTS, not pixels!. If both cx and cy are 0, the image would not be resized at all. If only one cx, cy is zero results are undefined.

There's also an utility function InsertImageFromFileNoResize that calls InsertImageFromFile, passing size as 0.

An example of use

 procedure TForm1.Button1Click(Sender: TObject);
 begin
  // running a dialog to select a picture to insert
  if OpenDialog1.Execute then 
    // inserting the picture at the current RichMemo cursor position
    InsertImageFromFileNoResize(RichMemo1, RichMemo1.SelStart, OpenDialog1.FileName);
 end;

InsertStyledText,InsertColorStyledText,InsertFontText

The set of functions that simplify appending and replacing of styled text. The specified style of the text is applied on the insertion. The common rule for all functions, if InsPos (insertion position) is negative - the text is appended to the end. In order to insert the text in the beginning of the test InsPos should set to 0.

The inserted text is not forced to be on a new line or add a new line. You might want to add LineFeed character to TestUTF8 parameter, if you want the inserted text to cause a new line to be started.

procedure InsertStyledText(
  const ARichMemo: TCustomRichMemo; 
  const TextUTF8: String; 
  AStyle: TFontStyles;
  InsPos : Integer = -1 )

InsertStyledText inserts the styled text at the specified position.

procedure InsertColorStyledText(
  const ARichMemo: TCustomRichMemo; 
  const TextUTF8: String; 
  AColor: TColor; 
  AStyle: TFontStyles;
  InsPos : Integer = -1 )

InsertColorStyledText inserts the text with specified style and color at the specified position. to the end of the RichMemo

procedure InsertFontText(
  const ARichMemo: TCustomRichMemo; 
  const TextUTF8: String; 
  const prms: TFontParams;     
  InsPos : Integer = -1 )

InsertFontText inserts the text and applies specified FontParams to it.

You might want to create a class helper to implement these functions as methods for RichMemo. Beware, if you're using Delphi-compatibility helper - you might right into a conflict.

Installation

  • Get the latest version from SVN
  • Open the package, and install it, rebuilding the IDE
  • TRichMemo is added to 'Common Controls' component page.

Frequently Asked Questions

Using RichMemo in Shared Libraries

Issue #17412 If you need to use the component in a shared library, you might need to add -fPIC key to the compiler option of "the package" and the "project".

(Delphi) RichEdit-подобный интерфейс

Issue #14632 A typical problem is porting an existing code that's using RichEdit from Delphi. RichMemo interface doesn't match RichEdit in many ways. But there're two ways to handle that:

  • you can either create a sub-class from TCustomRichMemo (or RichMemo) and implement Delphi RichEdit methods;
  • you can use RichMemoHelpers unit (fpc 2.6.0 or later required) and use methods provided by class Helpers that should; Currently SelAttributes and Paragraph properties are implemented.
uses ... RichMemo, RichMemoHelpers;

TForm = class
  RichMemo1 : TRichMemo;
   
  // SelAttributes property is not available in the base class
  // but added by a helper defined at RichMemoHelpers unit
RichMemo1.SelAttributes.Name := 'Courier New';

Append mixed color text at the end of the RichMemo

If you just need simple coloring then here is an example that will each time add a new line with random color (tested on Windows):

  procedure TForm1.Button1Click(Sender: TObject);
  var
    i, j: integer;
    str: string;
  begin
    with Richmemo1 do
    begin
      str := 'Newline text';
      i := Length(Lines.Text) - Lines.Count; // cr as #10#13 is counted only once so subtract it once
      j := Length(str) + 1;                  // +1 to make the cr the same format
      Lines.Add(str);
      SetRangeColor(i, j, Round(random * $FFFFFF));
    end;
  end;
 Newline text
 NewLine text
 NewLine text

Alternative example for simple coloring (tested on Windows):

  procedure TForm1.Button2Click(Sender: TObject);
  begin
    with RichMemo1 do
    begin
      Lines.Add('Line in red');
      SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clRed);
  
      Lines.Add('Line in blue');
      SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clBlue);
  
      Lines.Add('Normal line.');
      Lines.Add('Normal line.');
  
      Lines.Add('Line in green ');
      SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clGreen);
    end;
  end;
 Line in red
 Line in blue
 Normal line.
 Normal line.
 Line in green

If you need mixed coloring then this is an example that will add a new line with several different colored words (tested on Windows):

procedure TForm1.Button3Click(Sender: TObject);
    procedure AddColorStr(s: string; const col: TColor = clBlack; const NewLine: boolean = true);
    begin
      with RichMemo1 do
      begin
        if NewLine then
        begin
          Lines.Add('');
          Lines.Delete(Lines.Count - 1); // avoid double line spacing
        end;

        SelStart  := Length(Text);
        SelText   := s;
        SelLength := Length(s);
        SetRangeColor(SelStart, SelLength, col);

        // deselect inserted string and position cursor at the end of the text
        SelStart  := Length(Text);
        SelText   := '';
      end;
    end;
  begin
    AddColorStr('Black, ');
    AddColorStr('Green, ', clGReen, false);
    AddColorStr('Blue, ', clBlue, false);
    AddColorStr('Red', clRed, false);
  end;
 Black, Green, Blue, Red
 Black, Green, Blue, Red
 Black, Green, Blue, Red

Markup Language Parsing

mlparse example

The native rich-edit controls do not support a markup-language parsing.

You'll need to write it yourself as shown in mlparse example

Что внутри

Матрица поддержки платформы

Values in the matrix are not expected to be static (except for "carbon" column), each system is planned to support all features declared by RichMemo.

Note that the table contains more features than published above. That means that the APIs are already available in RichMemo, but since they're unstable (on some platforms) it's considered "experimental" rather than promised.

Feature Win32 Gtk2 Qt Cocoa Carbon
Font color and style selection Yes Yes Yes Yes Yes
Font background color Yes Yes Yes Yes No
Subscript,Superscript Yes Yes No No No
GetStyleRange Yes Yes No Yes Yes
Paragraph Alignment Yes Yes Yes Yes Almost Impossible
Paragraph Metrics Yes Yes No Yes Almost Impossible
Paragraph Tabs Yes Yes No Yes No
Zoom Yes Incomplete No Yes No
Printing Yes No No No No
RTF Load/Save OS RichMemo No OS OS
Insertables Yes Yes No No No

Win32

RichMemo without Theme patch
RichMemo with Theme
  • RichEdit is used as system widgetset. The latest known .dll is loaded and initialized on start. Please note that RichEdit 1.0 would not support most of the features.
  • The internal wrapper of RichEditManager is provided in order to be compatible with Win 9x. However, it was never tried or tested. It's also expected that TOM object could be wrapped as one of the RichEditManager implementation. However, having the "manager" in place could be removed completely.
  • According to the internet, RichEdit control was not updated by Microsoft to support Theme drawing (since XP and up to Windows 8.1). Thus, RichEdit might always look like an old Win9x 3d-framed control. Based on the patch provided at the issue a way to override WM_NCPAINT method was introduced in r4153.

Win32RichMemo provides a global variable NCPaint. It's a handler of non-client area drawing. By default, it attempts to draw themed border (see Win32RichMemo.ThemedNCPaint for implementation). It provides good results on Windows XP themes, but later themes (where animations are used), the results are not so great and should be updated.

In order to let system do NCPaint only (i.e. LCL implementation is causing issues or new windows updated RichEdit to draw borders properly), you can change NCPaint value at runtime, resetting it to nil

uses
  RichMemo, ..{$ifdef WINDOWS}Win32RichMemo{$endif}

initialization
  {$ifdef WINDOWS}
  Win32RichMemo.NCPaint:=nil;
  {$endif}

You can also provide your own implementation of NCPaint. However, if you implement proper animated theme drawing, please provide patch.

The behavior is Windows implementation specific and should not (and will not be) part of RichMemo interface.

Gtk2

  • GtkTextView is used as system widgetset
  • Sub and Superscript are not supported natively, an extra code is implemented in gtk2richmemo in order to implement them.
  • Bulletin and numbered lists are emulated.

Gtk3

The APIs between Gtk2 and Gtk3 are not really different. The major difference is in painting. For Gtk3 Cairo canvas is heavily used. The only area it affects is "Internals". IF any one wants to contribute Gtk2 implementation - please create separate gtk3richmemoXXX units. No {$ifdefs} should be created in gtk2 units.

Cocoa

  • NSTextView is used for Cocoa as system widgetset
  • Not every font-family provides italic font. Thus even if you pass fsItalic as part of Style for a font, it might be ignored.

Qt

  • QTextEdit widget is used. Current C-mappings for Qt are missing a lot of RichText APIs, thus full implementation is currently impossible.
  • The following classes need to be mapped to C-functions:
    • QTextBlockFormatH needed for paragraphs alignments (such as paragraph indents, line spacing and tabs). QTextEdit only exposes paragraph alignment.
    • QTextCharFormatH needed for additional character formatting (i.e. vertical alignment, links support). QTextEdit only exposes font styles.

See also