DesignKit is a Lazarus package that provides a set of visual and non‑visual components to enhance application UI design.
All components are installed on the Common Controls tab of the component palette.
- Lazarus (tested with 4.8) / Free Pascal Compiler 3.2.2 or newer.
- LCL – included with Lazarus.
- IDEIntf – included with Lazarus.
- RichMemoPackage – a fork of the original
TRichMemocomponent (available in plainlib). - Helpers – common utility units used by the spell‑checker (available in plainlib).
- Toolkit – general‑purpose utility classes (available in plainlib).
- RichKit – additional rich‑text utilities (available in plainlib).
- Windows 8 or later is required only for the native
WinSpellCheckerbackend. The HunSpell backend works on all platforms (Windows, Linux, macOS) and does not need any OS‑specific API.
TSpellChecker is a non‑visual component that adds spell‑checking capabilities to a TRichMemo control. It supports both the native Windows Spell Checker (on Windows) and Hunspell (cross‑platform), with background checking, real‑time debounced updates, cancellation, and an automatic context menu with suggestions.
- Background spell checking with cancellation support.
- Debounced real‑time checking (configurable delay).
- Automatic application of error underlines (with
AutoApply). - Built‑in context menu with spelling suggestions (replaces the word when a suggestion is chosen).
- Integration with an external
PopupMenu– suggestions can be placed directly in the menu or inside a submenu. - Supports Windows Spell Checker (
seWindows) and Hunspell (seHunspell). - For Hunspell: loads dictionaries from files, streams, or automatically downloads them from a URL (LibreOffice dictionaries repository).
- Chunked background checking of very large documents with incremental drawing of underlines, so errors appear at the top of the document while the rest is still being checked.
- Option to check only the visible portion of the RichMemo (
CheckVisibleOnly), with automatic re-check on scroll or text change. Works together withChunkedCheck. - The chunked pass starts from the currently visible area, so the user sees fresh results where he is looking even when the document is scrolled far from the beginning.
- Events:
OnSpellCheckComplete(reports error count),OnContextPopup(allows custom handling).
| Property | Default | Description |
|---|---|---|
RichMemo |
nil |
The TRichMemo control to be spell‑checked. |
Language |
'' |
BCP‑47 language tag (e.g. 'en-US', 'ru-RU'). |
Enabled |
True |
Enables/disables spell checking. |
Options |
[scoSpelling] |
Set of TSpellCheckOptions (scoSpelling, scoComprehensive – Windows only). |
AddEmptySuggestions |
True |
Include errors even if no suggestions are available. |
RealTime |
False |
Automatically check after text changes (with debounce). |
CheckDelay |
1000 |
Debounce delay in milliseconds for real‑time checks. |
AutoApply |
True |
Automatically apply underlines after a check completes. |
AutoContextMenu |
True |
Automatically handle OnContextPopup to show suggestion menu. |
PopupMenu |
nil |
An external TPopupMenu to integrate suggestions into (if nil, uses default behaviour). |
SubMenu |
False |
If True, suggestions are placed in a submenu. |
SubMenuCaption |
'Suggestions' |
Caption of the submenu when SubMenu is True. |
SubMenuIndex |
0 |
Index where suggestions (or submenu) are inserted in PopupMenu. |
Engine |
seWindows |
Spell engine: seWindows or seHunspell. |
DicPath |
'' |
Directory for Hunspell dictionaries (absolute or relative to the application). |
DicUrl |
'https://raw.githubusercontent.com/plainlib/dictionaries/main/{plaindict}' |
URL template for downloading dictionaries. Placeholders: {dict} (language code + .aff/.dic), {plaindict} (flat dictionary name), {libredict} (LibreOffice internal path), {wooormdict} (Wooorm dictionary path). |
ChunkedCheck |
False |
When True, large texts are checked in chunks and underlines are drawn incrementally while the background pass is still running. The pass starts from the currently visible area, then covers the text above and below. |
ChunkSize |
16384 |
Size of a single chunk in bytes (used when ChunkedCheck is True). The real chunk is extended to the next whitespace, so a word is never split in half. Minimum 256 at runtime, no minimum in the designer. |
CheckVisibleOnly |
False |
When True, only the text currently visible in the RichMemo is checked. A polling timer re-runs the check whenever the visible range changes (scroll, resize, or text change), so the rest of the document is never touched. Can be combined with ChunkedCheck. |
| Event | Description |
|---|---|
OnSpellCheckComplete |
Fired after a check finishes (and after underlines are applied, if AutoApply is True). Provides the number of errors found. |
OnContextPopup |
Called before the component’s built‑in context menu handling. Set Handled to True to prevent the component from showing its menu. |
- Place a
TSpellCheckeron a form. - Assign its
RichMemoproperty to aTRichMemocontrol. - Set the
Languageproperty (e.g.'en-US'). - Optionally set
RealTime := Trueto enable live checking. - At runtime, the component will automatically check the text and underline errors. Right‑click on a misspelled word to see suggestions.
Example for Hunspell with automatic download:
var
Spell: TSpellChecker;
begin
Spell := TSpellChecker.Create(Self);
Spell.RichMemo := RichMemo1;
Spell.Language := 'ru-RU';
Spell.Engine := seHunspell;
Spell.DicPath := '.\dictionaries'; // local folder
Spell.DicUrl := 'https://raw.githubusercontent.com/LibreOffice/dictionaries/master/{libredict}';
Spell.RealTime := True;
Spell.CheckDelay := 800;
Spell.AutoApply := True;
Spell.ChunkedCheck := True;
Spell.ChunkSize := 8192; // Roughly 2 to 4 pages
end;If you want to use a custom PopupMenu with suggestions inserted directly:
Spell.PopupMenu := MyPopupMenu;
Spell.SubMenu := False; // suggestions appear directly in the menu
Spell.SubMenuIndex := 2; // insert after the second itemBy default the component checks the entire text in one background pass and applies all underlines at once. This is fine for short and medium documents, but on very large texts the user has to wait until the whole pass is finished before any error is highlighted.
Enable ChunkedCheck to split the text into pieces and draw underlines incrementally:
Spell.ChunkedCheck := True;
Spell.ChunkSize := 16384; // roughly 4 to 5 pages of Latin textHow it works:
- The text is split at whitespace boundaries, so words are never cut in half. A chunk may be larger than
ChunkSizeif no whitespace is found within a reasonable distance. - As soon as the first chunk is processed, its errors are drawn. The user sees results at the top of the document while the rest is still being checked.
- The pass starts from the area currently visible in the memo, then covers the text above it and finally the text below it. This way, if the user has scrolled to the middle of a long document, fresh underlines appear where he is looking first.
- Existing underlines from the previous run are kept on screen during the pass and replaced atomically in a single operation at the end. This avoids flicker.
- Total work stays linear in the number of errors: each chunk draws only its own newly found errors, and the final replace redraws everything once.
Suggested chunk sizes:
| Language family | Recommended ChunkSize |
Approximate size |
|---|---|---|
| Latin (English, etc.) | 16384 – 32768 | 4 to 8 pages |
| Cyrillic (Russian) | 8192 – 16384 | 2 to 4 pages |
| Any, "instant" feel | 2048 | half a page or less |
The property is ignored when ChunkedCheck is False or when the text is shorter than ChunkSize.
During design time the minimum ChunkSize is relaxed to 1 so the behaviour can be tested word by word. At runtime the minimum is 256 to avoid pathological fragmentation.
On very large documents even the chunked pass may spend time on parts the user is not looking at. Enable CheckVisibleOnly to restrict checking to the text that is currently visible in the RichMemo:
Spell.CheckVisibleOnly := True;How it works:
- The component polls the visible range every 200 ms. When the range changes (scroll, resize, or text change), the check is re-run for the new range only.
- The visible range is extended to whole-word boundaries on both ends, so a word that is only partially visible is checked in full and never misreported as a fragment.
- Only the visible portion is checked in each pass, so the result appears much faster on long documents. Errors outside the visible range are not highlighted until they are scrolled into view.
- The mode can be combined with
ChunkedCheck. If the visible range is larger thanChunkSize, it is still split into chunks and drawn incrementally.
When to use:
- Large documents (many pages) where checking the whole text in the background would be wasteful.
- Read-only or preview-style controls where the user mostly scrolls through the text.
When not to use:
- Short texts where checking everything at once is already fast enough and the user expects the whole document to be highlighted.
The property has no effect while Enabled is False.
TFormGrip is a visual control that draws a size grip in a selected corner
of its parent (a form or a panel) and resizes that parent when the grip is
dragged. It behaves like the grip found in a StatusBar, but can be placed
in any corner and styled freely.
The component does not hook or override any events of its parent. All mouse
handling, painting, and resizing are performed inside the control itself, so
the parent form's own OnPaint, OnMouseDown, OnMouseMove, OnMouseUp,
and OnResize handlers remain untouched.
- Works with any
TWinControlparent, not only with forms. - Grip can be placed in any of the four corners of the parent.
- The control automatically snaps to the chosen corner and cannot be moved away from it; resizing or repositioning the parent keeps the grip in place.
- Multiple grip drawing styles: dots (triangular arrangement), lines, grid, or solid triangle.
- Background can either follow the parent colour (
ParentColor = True, the default) or use its ownColor. - Two independent offsets, named after the CSS box model:
GripMarginmoves the whole control away from the parent corner, whileGripPaddinginsets the drawn pattern inside the control. - Resizing respects configurable minimum parent width and height.
- Double buffered painting with
csOpaque, so the grip redraws cleanly during parent resize without flicker or black artefacts. - In design time the grip is drawn but does not resize the parent.
| Property | Default | Description |
|---|---|---|
Visible |
True |
Shows or hides the grip. |
ShowGrip |
True |
Controls drawing of the grip pattern. |
GripCorner |
gcBottomRight |
Corner of the parent: gcBottomRight, gcBottomLeft, gcTopRight, or gcTopLeft. |
GripMargin |
0 |
Outer offset - distance between the control and the parent's corner (in pixels). |
GripPadding |
2 |
Inner offset - distance between the control's edge and the drawn pattern (in pixels). |
GripColor |
clActiveBorder |
Colour used to draw the grip pattern. |
GripStyle |
gsDots |
Drawing style: gsDots, gsLines, gsGrid, or gsSolid. |
DotSize |
2 |
Size of the dots (for gsDots and gsGrid). |
DotSpacing |
3 |
Distance between dots. |
MinParentWidth |
100 |
Minimum parent width allowed during resizing. |
MinParentHeight |
100 |
Minimum parent height allowed during resizing. |
ParentColor |
True |
When True, background follows Parent.Color; otherwise uses Color. |
Color |
clBtnFace |
Background colour used when ParentColor is False. |
Width, Height |
16, 16 |
Size of the grip control in pixels. |
- Drop a
TFormGripcomponent from the Common Controls palette onto a form or a panel. - Choose the desired corner using
GripCornerand adjust the remaining properties in the Object Inspector. - At runtime the grip appears in the selected corner and resizes its parent when dragged.
Example code to create and configure TFormGrip at runtime:
var
Grip: TFormGrip;
begin
Grip := TFormGrip.Create(Self); // Self is the parent control
Grip.Parent := Self;
Grip.GripCorner := gcBottomRight;
Grip.GripStyle := gsLines;
Grip.GripColor := clGray;
Grip.GripMargin := 0;
Grip.GripPadding := 3;
Grip.Width := 16;
Grip.Height := 16;
end;The component is split into two classes following the standard Lazarus convention:
TCustomFormGrip- base class that implements all behaviour. Inherit from it to create custom variants with your own published properties.TFormGrip- ready-to-use component that publishes the most useful properties ofTCustomFormGripand of the inheritedTControl.
TFlatButton is a custom TSpeedButton descendant that always draws a flat, themed button (similar to toolbar buttons) and provides integrated tooltip support with extensive customisation.
- Always flat (inherited
Flatproperty is hidden and forced toTrue). - Uses the native theme (via
ThemeServices) for normal, hot, and pressed states. - Can optionally disable the pressed state drawing (
DrawPressed). - Allows vertical offset of the caption relative to the icon (
OffsetY). - Built‑in tooltip system with delay, size, colour, and auto‑hide duration.
- Tooltips are displayed using
TOneShotTooltipand automatically hide when the button is clicked or the tooltip is dismissed.
| Property | Default | Description |
|---|---|---|
DrawPressed |
True |
If False, the button never appears pressed (visual state is always normal or hot). |
OffsetY |
0 |
Vertical pixel offset for the caption relative to the centre of the icon (positive moves text down). |
Tooltip |
'' |
The tooltip text to display (translatable caption). |
TooltipDelay |
0 |
Delay in milliseconds before the tooltip appears after a click (0 = immediate). |
TooltipWidth |
0 |
Width of the tooltip window (0 = auto‑size). |
TooltipHeight |
0 |
Height of the tooltip window (0 = auto‑size). |
TooltipColor |
clDefault |
Background colour of the tooltip (clDefault uses system default). |
TooltipDuration |
0 |
Time in milliseconds after which the tooltip auto‑hides (0 = no auto‑hide). |
Place a TFlatButton on a form, set an Images or Glyph for the icon, adjust Caption, and configure the tooltip properties.
Example:
var
Btn: TFlatButton;
begin
Btn := TFlatButton.Create(Self);
Btn.Parent := Self;
Btn.Caption := 'Save';
Btn.ImageIndex := 0; // assume an ImageList assigned
Btn.Tooltip := 'Save the current document';
Btn.TooltipDelay := 500;
Btn.TooltipDuration := 3000;
Btn.OffsetY := 2; // move text slightly down
end;- Open the package file (
designkit.lpk) in Lazarus. - Click Use → Install.
- Rebuild the IDE.
The components will appear on the Common Controls tab of the component palette.
DesignKit Package © 2026 by Alexander Tverskoy
Licensed under the MIT License – see the individual source files for details.



