Delphi and Lazarus
Trekking and Events
Blog and Forum
Čeština English
Main menu
Delphi and Lazarus
Top downloads
KGrid (23598x)
KControls Component Suite (18675x)
KHexEditor (5278x)
KIcon (2584x)
CAN Event Manager (456x)

KControls Component Suite

KControls is a freeware distribution, a flagship of tkweb. It contains all of my published components for Delphi and Lazarus. All controls have been written with the aim to become both cross-IDE compatible (Delphi/C++Builder VCL and Lazarus LCL) and cross-platform compatible in Lazarus. There are some exceptions to this scheme, see below.

Components included
TKGrid - powerfull control for working with table data, replacement for TStringGrid and TDrawGrid - full compatibility and lot of new features
TKDBGrid - control for working with database tables, possible replacement for TDBGrid
TKMemo - native replacement for TMemo/TRichEdit - written from scratch, great features, full RTF support etc.
TKHexEditor - another useful control for binary file editing
TKIcon - powerfull component for working with icons and cursors (files *.ico and *.cur, works only on Windows)
TKPrintPreview - control for displaying print preview, it is part of KControls built in printing capabilities, every visual control supports printing and previewing
TKPrintPreviewDialog - nonvisual component - dialog - for an easy print preview implementation
TKPrintSetupDialog - nonvisual component - dialog - for an easy implementation of printing preferences
TKCustomControl - a base for your visual controls, for which you want to implement e.g. printing and previewing capabilities in Delphi or Lazarus (just 2 short functions to write).
TKNumberEdit - edit control to input numbers in various formats
TKFileNameEdit - edit control to input file names
TKLinkLabel - label to show clickable link
TKGradientLabel - label with gradient background
TKLog - component for event logging
TKPercentProgressBar - custom drawn progress bar which shows actual percentage of the progress
TKBrowseFolderDialog - wrapper for the standard Windows API browse for folder dialog (works only on Windows)
TKBitBtn - like TBitBtn - draws PNG and alpha channel correctly in Delphi, has WordWrap property, works in Lazarus as well
TKColorButton - just another button to pick color
TKPageControl - page control written from scratch with custom painted tab panel, has tab icons and close button icon


KControls is provided free on 'as is' basis, with complete source code. However, it is licensed software. More information about license can be found in source file headers.

All controls support Delphi and Lazarus IDEs fully. But there are some exceptions: TKIcon and TKBrowseFolderDialog work only on Windows and printing and previewing might not work in some widgetsets in Lazarus.

Note about cross-platform development in Delphi: I strongly disagree with the way Embarcadero took with the FMX library to allow cross-platform development, so FMX will never be supported. As Lazarus has become very good IDE, in many aspects better than Delphi, I recommend you try it if you need cross platform features.


If you want to donate for further development of KControls just think about building your own photovoltaics and using the WATTrouter device produced by our company. You will save lots of energy and it will be the best donation to me you can make!

Screenshots (click the images to enlarge)

KControls components (Windows Vista)KControls components (Windows XP/GTK2runtine)
KMemo rich text editor showing the KMemo manual.KMemo rich text editor showing more complex sample RTF document.

Repository - development versions

You may now download newest development version at bitbucket. Please download and try this version if something is not working in the official release listed below.

Downloading KControls

Important note: When installing the packages in Delphi XE2 and later you must add "Vcl;Vcl.Imaging" to Unit Scope Names in Delphi Options/Library! Otherwise the packages won't compile!

FileVersionNumber of
Available for:Changes
kcontrols_1.7.zip1.76009Delphi 7+,Lazarus 1.2.2+, C++Builder 2007+support for RAD Studio XE8, major work on TKMemo which is already usable, bugfixes...
kcontrols_1.6.zip1.62672Delphi 6+,Lazarus 1.2.2+, C++Builder 2007+support for RAD Studio XE6, Columns property in TKDBGrid, bugfixes...
kcontrols_1.5.zip1.5361Delphi 6+,Lazarus 1.2.2+, C++Builder 2007+new components TKMemo, TKBitBtn, TKColorButton, some bugfixes...
kcontrols_1.4.zip1.41010Delphi 6+, Lazarus 0.9.29(SVN#21827)+, C++Builder 2007+support for RAD Studio XE3-XE5, new components etc.
kcontrols_1.3.zip1.32724Delphi 6+, Lazarus 0.9.29(SVN#21827)+, C++Builder 2007+support for RAD Studio XE2
kcontrols_1.2.zip1.23093Delphi 6+, Lazarus 0.9.29(SVN#21827)+, C++Builder 2007+cumulative update (KGrid 1.7, KHexEditor 1.5, KIcon 2.2)
kcontrols_1.1.zip1.11098Delphi 6+, Lazarus 0.9.29(SVN#21827)+, C++Builder 2007+cumulative update (KGrid 1.6, KHexEditor 1.4, KIcon 2.1)
kcontrols_1.0.zip1.01708Delphi 6+,Lazarus 0.9.29(SVN#21827)+initial release (KGrid 1.5, KHexEditor 1.4, KIcon 1.9)

If you have a question you may ask below and I will probably answer it, after some time.


Home | Software | Delphi and Lazarus | Trekking, travelling | Sport | Blog

Search in comments: 
inserted: 2017-07-25 13:07:55   Reply...
From: Davo
Hi Folks, I'm back ....
I am trying to change the style of text in a TKMemo.
I have tried KMemo1.SelectionTextStyle.Font.Style but it changes the whole block where the end of the selection is. If selection spans blocks, the first part is unchanged.

Am I misunderstanding just how this function works or is it not implemented yet ?
I assume this operation must break up existing blocks so is quite complicated.

Functions like ClearSelection and SelText behave as I'd expect, work on exactly
what is selected.
inserted: 2017-07-25 00:08:44   Reply...
From: wes
I had trouble compiling in Delphi 2010, getting error in KFunctions.GetFormatSettings on the line Result := TFormatSettings.Create.

In Delphi2010 SysUtils.TFormatSettings is a record not a class.

Changing the define from COMPILER12_UP to COMPILER15_UP solved the problem for me.
inserted: 2017-07-24 20:10:09   Reply...
From: inferno
One more question - how to disable completely any cell/row highlight? I need to prevent user for any selection - the behavior should be like like settings CanSelet:=false in OnSelectCell event. But even if I did it for all cells, there is still visible highlight of the last selected cell/row.
inserted: 2017-07-24 11:13:52   Reply...
From: см
Is there a way to set a font for a TKmemoTable?
Neither TKmemoTable, nor TKMemoTableCell have a .TextStyle property.
inserted: 2017-07-24 13:54:15   Reply...
From: tk
No, you have to traverse all text blocks in all cells and change the font for them.
inserted: 2017-07-24 14:40:30   Reply...
From: см
I did

if stFontTable<>stFontCommon then
  if aMemoTable.Rows[Row].Cells[Column].Blocks.Count>0
     then for BlockIndex:=0 to aMemoTable.Rows[Row].Cells[Column].Blocks.Count-1 do
       if aMemoTable.Rows[Row].Cells[Column].Blocks[BlockIndex] is TKMemoTextBlock
         then TKMemoTextBlock(aMemoTable.Rows[Row].Cells[Column].Blocks[BlockIndex]).TextStyle.Font:=stFontTable;
inserted: 2017-07-21 18:59:50   Reply...
From: inferno
I'm trying to use TKGrid with checkboxes which are aligned center. This is done like in the KGrid demo by setting in the OnDrawCell event for columns with checkboxes:

KGrid1.CellPainter.CheckBoxHAlign := halCenter;

This works well until user clicks on the checkbox and then it appears on the left side of the cell instead of changing its state only in the center position. After editing checkbos comes back to its initial center position.

Please let me know how to fix this behavior. Thanks.
inserted: 2017-07-24 13:52:46   Reply...
From: tk
CellPainter.CheckBoxHAlign only controls painting of the checkbox frame. If you want to center your inplace editor (here certainly a TCheckBox you've created in OnEditorCreate), you have to use OnEditorResize event and center it there within the cell rectangle manually.
inserted: 2017-07-24 19:44:59   Reply...
From: inferno
I found this event before asking but I can't determine the size of the checkbox there. I now use something like this:

Inc(ARect.Left, Round(Abs((ARect.Width-16)/2)));

(16 is fixed checkbox width) but maybe you know some cleaner solution?

inserted: 2017-07-17 14:12:37   Reply...
From: Davo
Hi, more questions I'm afraid.

I'd like to read the content from KMemo (so I can write out a file thats not RFT). Seems to me that data is stored in (eg) KMemo1.Blocks and we read each block by looking at Kmemo1.Blocks.Items[x] which is a TKMemoBlock and has a property 'Text' and sure enough that has the text in it. But it does not have a TextStyle property to tell me what that text looks like.

I sort of expected it to be TKMemoTextBlock, that does have a TextStyle property. Or am I thinking about this the wrong way ?

How should I determine the style (font size etc) of a block of text in KMemo ?

inserted: 2017-07-18 11:42:19   Reply...
From: tk
Do as CM said. Traverse all blocks and cast them to TKMemoTextBlock if they can be. TKMemoHyperlink descends from TKMemoTextBlock so you need to cast hyperlinks only if you need to access their URL properties.
If you use tables or or other nested structures you will need to traverse the blocks in individual cells and describe the table in a specific way you need. The same for more complex structures such as nested tables or floating text fields etc.
inserted: 2017-07-18 11:17:19   Reply...
From: см
I am not sure that I get you right, but if I do:
There is a variaty of block types in TKMemo, so you have to cast the block to a TKMemoTextBox. This way the compiler and IDE would know, what it is.
Something like this:
  if (TKMemo.Blocks[index] is TKMemoTextBlock)
     then ... TKMemoTextBlock(TKMemo.Blocks[index]).TextStyle...

I am not sure, maybe you should extend it to
  if (TKMemo.Blocks[index] is TKMemoTextBlock) or (TKMemo.Blocks[index] is TKMemoHyperlink)
     then ... TKMemoTextBlock(TKMemo.Blocks[index]).TextStyle...

or to
   try ... TKMemoTextBlock(TKMemo.Blocks[index]).TextStyle...


inserted: 2017-07-18 14:09:08   Reply...
From: Davo
OK (he says doubtfully). I tried casting -
FS := TKmemoTextBlock(KMemo1.Blocks[i]).TextStyle.Font.Size;
And, indeed, it worked as you suggest. Wow, thanks !
But I really don't understand why !

The kmemo.pas (line 1860 of 12K !) says KMemo1.Blocks is TKMemoBlocks. I'm surprised it can be cast to TKMemoTextBlock but even so, where did the TextStyle info come from ?

I got a lot to learn .....

Thanks very much both of you.
inserted: 2017-07-17 13:46:32   Reply...
From: Ondrej
Can you help me please? I need change row background color by value of column value in this row.
I test this from demo:
procedure TForm1.KDBGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  R: TRect; State: TKGridDrawState);
     KDBGrid1.Cell[ACol, ARow].ApplyDrawProperties;
     if State * [gdFixed, gdSelected] = [] then
          if KDBGrid1.DataSource.DataSet.FieldByName('ID').AsInteger mod 2 = 0 then
             KDBGrid1.CellPainter.Canvas.Brush.Color := KDBGrid1.Color

This change complet grid color background if i change selected row.
I am sorry for my English
inserted: 2017-07-18 11:34:14   Reply...
From: tk
I am sure your KDBGrid1.DataSource.DataSet.FieldByName('ID').AsInteger is constant for each row. Try:
if ARow mod 2 = 0 then
inserted: 2017-07-14 01:50:22   Reply...
From: Davo
Hello, just tried to build the bitbucket version of KControls. Ubuntu, Lazarus 1.8RC2

However, following error message -

kgrids.pas(2942,15) Error: There is no method in an ancestor class to be overridden: "DoAutoAdjustLayout(const TLayoutAdjustmentPolicy;const Double;const Double;const Boolean);"

inserted: 2017-07-14 15:46:42   Reply...
From: см
I had the same problem in Laz 1.8RC2.
I opened kgrids.pas.
Then I removed „Override‟ from line 2943 (or whatever):
  const AXProportion, AYProportion: Double; const AScale0Fonts: Boolean); override;

I have no idea if I should, since I do not use KGrids, it is not a problem for me.
inserted: 2017-07-15 11:37:50   Reply...
From: Davo
Thanks CM, yep, tried that, after all, the method does not exist in TKControls so override is wrong. But I found that only exposed another problem, the compiler complaining that the implementation number of parameters does not match the declaration. But it does (4) ??? Can only assume there is something else more subtle happening and the compiler is guessing as to what it is.

Sigh ...
inserted: 2017-07-16 19:11:11   Reply...
From: tk
See here:
I was perhaps too hasty introducting this because Lazarus devs were hasty with that development as well IMO. The method appeared in Lazarus trunk 1.7 for a short while and then disappeared again. Then it appeared again when LCL version was set to 1.8. But I don't know if these changes were synchronous and if your RC already supports this. Please comment out this method if you have trouble with compiling, or adapt the ifdef. Or update Lazarus.
inserted: 2017-07-17 11:11:31   Reply...
From: Davo
OK, I commented out the TKCustomGrid's DoAutoAdjustLayout and it built fine. Updated Lazarus to 1.8RC3, same results. Developers say that RC3 will be pretty much what 1.8 looks like.

I'm quite happy with 1.7 KControls right now so I'll leave that active.

Thanks for your help.

inserted: 2017-07-18 11:49:08   Reply...
From: tk
If you update to FPC/Lazarus trunks (eg. with fpcupdeluxe) then it will work fine (I mean latest KControls repository snapshot). I've never used release candidates, some time ago I've used last stable 1.6.4 but now I need both trunks because they contain important fixes. I really recommend using fpcupdeluxe, it is now already a very mature installer for FPC & Lazarus & cross compilers.
inserted: 2017-07-14 01:41:25   Reply...
From: Davo
Tried installing current KControls on Ubuntu running Lazarus 1.8RC2.
However, seems UTF8Copy() has now been dropped. It was present but deprecated in 1.6. See -

I cannot even find the FPC docs for UTF8Copy() anymore, sure I could recently but maybe my search engine is a bit tired today !

inserted: 2017-07-14 15:48:47   Reply...
From: см
UTF8Copy is now located in LazUTF8.
Try to add LazUTF8 in the uses section of your code.
inserted: 2017-07-15 14:09:50   Reply...
From: Davo
Indeed CM, adding LazUTF8 to uses in KMemo and then KMemoRTF helps. But then we need UTF8UpperCase() in KFunctions and it does not help there. In fact, UTF8UpperCase() is defined in LazUTF8.pas so I am unsure why not.
Think I'll go to bed .....
inserted: 2017-07-16 11:03:02   Reply...
From: Davo
OK, its cool, my silly. Where tk has called UTF8UpperCase() in KFunctions, he has prepened the OLD unit name, LCLProc, so no amount of 'uses' clauses will change that.
So, in two places in KFunctions, LCLProc.UTF8UpperCase() needs to become just UTF8UpperCase(). And it all builds nicely, installs and runs !
Thanks tk, this is one serious component !

inserted: 2017-07-16 19:16:06   Reply...
From: tk
In the bitbucket repository this has been already fixed long ago.
inserted: 2017-07-05 15:02:09   Reply...
From: Alex

in KMemo, how do I watch for selection/caret changes? I'm trying to update ToolButtons etc. without constant polling (the Demo takes 100% of one of my CPU cores with constant Action.OnUpdate calls). Is there something like an OnSelectionChange event?

I was Hooking into Memo.Blocks.OnUpdate, which works if I keep a reference to the old value - however, the caret disappears...

What is the correct way to do this?

Thank you very much for this great component!

inserted: 2017-07-11 11:31:06   Reply...
From: tk
Through actions as it is shown in the kmemoeditor demo. It works for me wo problems in Lazarus or Delphi XE (CPU time = 0 when idle) when eg. kmemo_manual.rtf or other docs I test with are loaded into the memo (I always test with latest version from bitbucket).

Constant Action.OnUpdate calls must have a reason. You will have to figure it out yourself.
inserted: 2017-07-05 15:42:20   Reply...
From: Alex
In reply to my own question...

It turned out to be simple to add, my OnSelectionChange-event is called in TKCustomMemo.Select(). However, I'm still wondering if it's the correct way to do this...
inserted: 2017-07-03 21:59:36   Reply...
From: Frank
4 Q's
1) How do I evaluate if there is any text in the KMemo textbox?
2) Can I use PrintPreview control and write my own data to the control and not have to use the Grid or kmemo controsl??
3) And is there a manual on the printpreview?
4) Do have more documentation on using Kmemo than the rtf manual in the package. I need to know more of the properties the KMemo supports.
inserted: 2017-07-11 11:18:46   Reply...
From: tk
1. if KMemo1.Text <> '' then ...
2. You have to write your own TKCustomControl descendant which is not trivial task. If you are a beginner, forget about that. If not, you have to figure it out yourself.
3. Only what's described in KControls.chm or the comments.
4. Only what's described in KControls.chm or the comments. This doc is not yet completed.
inserted: 2017-07-04 11:44:24   Reply...
From: см
A1: if len(KMemo1.Text)>0 then ...
A4: You can try the examples bundled with the component. IFAIR there are some examples with print preview.
inserted: 2017-07-04 17:41:14   Reply...
From: см
Ooops- Length(...)
inserted: 2017-07-04 11:55:54   Reply...
From: Frank
Thanks for replying... but 'len' is not found, so it doesn't work.
And if you look at the examples, there is no code to show how to manually create your own preview using the PreviewControl... you can only hook it up to the KMemo and it does it automatically.
inserted: 2017-07-04 01:07:48   Reply...
From: Frank
Q 5...
Also, using the Kmemo and printpreview... how do I turn off the "fit to page" in code??
inserted: 2017-07-11 11:21:15   Reply...
From: tk
KMemo1.PageSetup.Options := KMemo1.PageSetup.Options - [poFitToPage];
inserted: 2017-06-29 17:24:22   Reply...
From: см
I am running the code below.
But it occurs that after selecting the text KMemo1.SelectedBlock returns nill.
Is it expected to be this way? And is it possible to determine the block to which the selected text belongs (or at least some of its characters, since they may belong to separate blocks)?

procedure TForm1.SelSomeClick(Sender: TObject);
  if KMemo1.SelectedBlock = nil then ShowMessage('selblock is nill');
inserted: 2017-07-11 11:10:54   Reply...
From: tk
Please read the manual about SelectedBlock. There is a note about it already. It is possible to determine the block to which the selected text belongs. But you have to traverse all text blocks and inspect their SelLength properties.
inserted: 2017-07-11 11:38:54   Reply...
From: см
Thanks, I have just downloaded (latest repository), but in\tkweb-kcontrols-16a4d402ad9e\help\kmemo\manual\kmemo_manual.rtf the word „SelectedBlock‟ is not mentioned at all. Maybe latest manual is not uploaded? Or maybe you are talking about: „Attributes can also be read. In such case the attributes are returned, which correspond to caret position or selection end position in the innermost container.‟?
inserted: 2017-07-12 11:16:04   Reply...
From: tk
I meant KControls.chm file which is auto-generated from the comments in unit interface sections (I've used DiPasDoc for that). The file is not stored in the repository as it is binary file, it is only present in the official releases.
Maybe also info about SelectedBlock is not yet present in the chm file. So have a look into the code first, the comments above property/method declarations.
inserted: 2017-07-14 15:39:54   Reply...
From: см
Thanks, I will check the CHM file.
inserted: 2017-06-22 08:36:20   Reply...
From: см
I am executing the code below, trying to select a string occurring in a KMemo. It usually works, but it occurs that when the text is in a table containing merged cells things go wrong.
In the example below, I expect that „L4;C1‟ is selected, but instead the selected text is „L4;C2‟ which in located in the next column.
I have made compensation for the paragraphs (since it is two chars and they are considered as one). As far as I remember you mentioned that images are considered an extra char. Probably merged cells are also considered a char?
Could there be a way to select the found string?

The only idea I currently have is to count the number of paragraphs before the occurence, then find the position of the last paragraph before occurence of the text in the raw RTF and count images and merged cells within it (I could not find the text itself in the raw RTF, because it might be formatted).
But probably there is a more reliable and straightforward way?

procedure TForm1.cmdNestedTableClick(Sender: TObject);
   NestingTable: TKMemoTable;
   NestedTable: TKMemoTable;
   row, clm: integer;
   FoundPos, NLCount: integer;
   MergeSpan: TKCellSpan;
  KMemo1.Blocks.AddTextBlock ('');
  KMemo1.Blocks.AddTextBlock ('');

  for row:=0 to NestedTable.RowCount-1 do
    for clm:=0 to NestedTable.ColCount-1 do


    MyStream := TStringStream.Create('{\rtf1 Line1\par Line2\par Line3\par Line4\par');
    NestedTable.Cells[1, 1].Blocks.LoadFromRTFStream(MyStream);

  if FoundPos>0 then
      NLCount:=Occurs(LeftStr(KMemo1.Text,FoundPos),#13#10); //Counts the number of the new lince characters before the occurence of the string
inserted: 2017-06-22 20:47:46   Reply...
From: tk
Cannot compile the example:
Main.pas(678,16) Error: Identifier not found "Occurs".
inserted: 2017-06-23 07:12:14   Reply...
From: см
Sorry, here it is:

//Counts the number of occurrences of a „Separator‟ withing „Str‟.
function Occurs(str, separator: string): integer;
  i, nSep: integer;
  SeparatorLength: Integer;
  SeparatorLength := Length(separator);
  nSep := 0;
  for i := 1 to Length(str) do
  if MidStr (str,i,SeparatorLength) = separator then
  Result := nSep;
inserted: 2017-06-23 10:12:34   Reply...
From: tk
Do not touch cells that become invisible after merging, here Cells[0,4] and Cells[0,5]:

for row:=0 to NestedTable.RowCount-1 do
    for clm:=0 to NestedTable.ColCount-1 do
       if (clm <> 0) or not (row in [4,5]) then
       begin NestedTable.Cells[clm,row].Blocks.AddTextBlock('L'+IntToStr(row)+';'+'C'+IntToStr(clm));
inserted: 2017-06-23 10:31:48   Reply...
From: см
If I get you right, a merged cell results in 2 characters if NOT empty, otherwise it returns 0 chars.
I hope I will succeed to make this solution practibally applicable.
inserted: 2017-06-23 11:41:47   Reply...
From: см
Instead of your code I did:

if (clm = 0) or (row in [4,5]) then
  NestedTable[clm,row].blocks clear and the effect is the same.
I suppose it is FixEmptyBlocks (which I use in the full code) that adds paragraphs in my cells.

I still have an issue with 1 char offset (occurs sporadically) but I believe it is fixable.
inserted: 2017-06-23 13:34:29   Reply...
From: tk
Better do not touch them as I said. I tried blocks.clear+fixemptyblocks as well but there is some problem with them, maybe even some bug there.
inserted: 2017-06-23 14:32:25   Reply...
From: см
Thanks once again!
I will try to find a way to leave them intact.
If it matters, my case is rather „fixemptyblocks+blocks.clear‟ than „blocks.clear+fixemptyblocks‟, but I am still not sure.
inserted: 2017-06-29 10:44:25   Reply...
From: см
Just to mention that that there is no possible way for my example to work, because I have used
instead of
inserted: 2017-06-10 00:51:00   Reply...
From: LookinGood
Hi, just found KMemo and it is looking good, but I need to be able to move the Caret to the bottom of a logging file when new stuff is being added.

I looked through the Source and could not find anything. How do I move the Caret to the very bottom of the file so the user can see new stuff being logged?

I played a little with ScrollBy but can't seem to make it work for me. I am using Lazarus in Ubuntu, so this may well be a "feature" of one or both though.
inserted: 2017-06-11 11:23:46   Reply...
From: см
I cannot check right now, but I am pretty sure you can find what you need in kmemo1.ExecuteCommand(ecGoto... ) or in something similar starting with "ec".
inserted: 2017-06-12 06:44:29   Reply...
From: см
This should do: KMemo1.ExecuteCommand(ecEditorBottom);
inserted: 2017-06-06 10:31:41   Reply...
From: см
Hi TK,
I have added some highlighting functionality to TKMemo (still for a single area only).
There is still some problem in the cases when selection and highlight overlap.
Anyway, could I upload the modified source somewhere so you could see it and consider using it in TKMemo (after the issue with overlapping is solved)?
Or should I use some tool to create a patch?
inserted: 2017-06-15 15:19:11   Reply...
From: tk
1. Before making any patches, be sure to test the modifications as described in kcontrols_readme.txt, see INFO FOR CONTRIBUTORS. Test at least in Lazarus trunk (1.7 or newer) and Delphi XE or newer (you can use some evaluation version).
2. To generate patch, use TortoiseHg Workbench (select changeset, then right click, select Export and click Export patch).
3. Send patch to my email.
inserted: 2017-06-02 12:09:57   Reply...
From: см
Hi TK,
TKMemo has several items in the .Color property.
I have tried them and it occurs to me that only .SelTextFocused and .SelBkGndFocused have influence.
BKGnd has influence in the IDE, but the colour is „forgotten‟ when the application is run.
Are the other .Color values implemented?

Also, there is a small bug occurring in Lazarus:
When some lines are manually selected and after that KMemo1.Select(9,5); is executed, then:
  1. Colour of the current selection changes (quickly)
  2. Current selection is removed.
  3. New selection is shown with the colours displayed in the end of step 1.
Imho, step 1 shall not happen at all.
inserted: 2017-06-03 14:58:11   Reply...
From: см
Suddenly some or all of the above values became applicable. Maybe the IDE did not understand that these changes were made or it did not recomplile. I have added some spaces in the code, before making the previous post (to make the IDE recompile) so maybe there is something odd.
inserted: 2017-06-03 11:05:44   Reply...
From: tk
About colors:
Colors.BkGnd is used only if Background.Color is clNone. Use Background.Color, Colors.BkGnd is deprecated.
All Colors.Sel* members are used.
No Colors.Inactive* member is used yet, they are reserved. They were copied from TKHexEditor and maybe will be implemented later.

About selection:
Very probably not a bug. You probably pressed a button to call KMemo1.Select and this button stole focus from KMemo. Which in turn caused the selection color change from Colors.SelBkGndFocused to Colors.SelBkGnd.
inserted: 2017-06-03 15:13:54   Reply...
From: см
Thanks for the info.
Aboute selection- that is exactly what I was doing- pressing a key, so it is the case that you described.
inserted: 2017-05-25 13:56:59   Reply...
From: см
I am trying unsuccesful to change the font of a dynamically created TKMemo. My code is below. Font keeps staying unchanged.
Changing the font from the Lazarus IDE works fine.
Changing the font of a statically created TKMemo works (but only if it is done before .Blocks.Clear is executed).

What could have gone wrong?

procedure TForm1.DynamicClick(Sender: TObject);
  MyMemo: TKMemo;
  ShowMessage ('aaa');
inserted: 2017-05-28 10:11:28   Reply...
From: tk
KMemo1.TextStyle.Font.Name := 'Elephant';
inserted: 2017-05-29 08:08:21   Reply...
From: см
inserted: 2017-05-19 09:37:10   Reply...
From: MCS-programmer
The great StrinGgrid component (Kgrid) is missing only Aligment for cells, rows and columns, and you need to improve the handling of the "OnDrawCell" (sometimes is smudging) event, and the ".CommaText" event does not work.
inserted: 2017-05-25 10:11:51   Reply...
From: tk
If you mean alignment of text in cells then it is fully supported via TKGridCellPainter.HAlign property. Yes it must be explicitly specified in OnDrawCell but I don't think this is too difficult to use:

procedure TMainForm.KGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; R: TRect; State: TKGridDrawState);
  G: TKGrid;
  G := TKGrid(Sender);
  // align text right in second column
  if ACol = 1 then
    G.CellPainter.HAlign := halRight;
  G.CellPainter.Text := G.Cells[ACol, ARow];

CommaText? Why? It is a TStringList property.
inserted: 2017-05-25 12:17:12   Reply...
From: mcs-programmer
Thanks for your reply, Ok, after applying this code i have something like this:
Undeclared identifier: 'halRight'
Also, I would like to set the alignment for single cells rather than for only declared columns and rows. And not in OnDrawCell, because the database I create already has too many functions there, and the database is not displayed correctly then.
inserted: 2017-05-28 10:02:18   Reply...
From: tk
You can also use TKGridAttrTextCell. In this case no OnDrawCell is needed:

procedure TForm1.FormCreate(Sender: TObject);
KGrid1.CellClass := TKGridAttrTextCell;
TKGridAttrTextCell(KGrid1.Cell[1,2]).HAlign:= halRight;
TKGridAttrTextCell(KGrid1.Cell[3,5]).HAlign:= halRight;
inserted: 2017-05-25 13:41:12   Reply...
From: см
Did you try to add „KGraphics‟ in the Uses section for solving the „Undeclared identifier: 'halRight'‟ issue?
inserted: 2017-05-25 19:38:01   Reply...
From: mcs-programmer
Thanks, my mistake, I did not think about it :)
inserted: 2017-05-19 09:05:51   Reply...
From: mangakissa
Nice tool for FPC users. Finally an adult TDBGrid.

Will KControls support Delphi D10.x in VCL mode?
inserted: 2017-05-25 09:45:44   Reply...
From: tk
In the repository Delphi D10.x support has been added long time ago.
inserted: 2017-05-12 01:09:49   Reply...
From: DanishMale

first of all thx for a great pack of components I am a happy user of your work THUMPS UP!!!!

Only got one tiny problem... How do I set a Fieldname at runtime in a KDBGRid ?

inserted: 2017-05-12 02:06:25   Reply...
From: DanishMale

forgot to say that I hav etried your solutions

TKDBGridCol(DBGrid1.Columns.Items[0]).FieldName := TEST_QUERY.Fields[ACol].FieldName;

TKDBGridCol(DBGrid1.Columns.Items[ACol]).FieldName := TEST_QUERY.Fields[ACol].FieldName;

both do not what is excepted :/
inserted: 2017-05-14 11:06:24   Reply...
From: tk
This is correct so maybe there is another problem. Design time setting works?
inserted: 2017-05-09 11:07:15   Reply...
From: Randell
How can I change thee default configuration for paper type to A4 rather than letter? I looked at the code but did not see configuration.
inserted: 2017-05-14 10:58:31   Reply...
From: tk
Normally in printer configuration dialog. It depends on used printer, not all printers can handle A4 format.
inserted: 2017-05-04 09:55:23   Reply...
From: см
I have tried the code below and and it occurs that KMemo1.SelLength returns negative values (for example, it returns -5 instead of 5). Is that the expected behaviour or is it a bug?

procedure TForm1.cmdTextPosClick(Sender: TObject);
  KMemo1.Blocks.AddTextBlock('Line 1');
  KMemo1.Blocks.AddTextBlock('Line 2');
  KMemo1.Blocks.AddTextBlock('Line 3');

procedure TForm1.KMemo1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  ShowMessage (KMemo1.SelText);
  ShowMessage (IntToStr(KMemo1.SelStart)+' ' +IntToStr(KMemo1.SelLength));
inserted: 2017-05-04 10:02:48   Reply...
From: см
Also, KMemo1.SelStart seems to return the position of the last selected character so it works as SelEnd, not as SelStart.
inserted: 2017-05-08 11:19:20   Reply...
From: tk
These values depend on where the selection begins and ends. To get absolute values, use RealSelLength, RealSelStart and RealSelEnd.
inserted: 2017-05-09 09:23:51   Reply...
From: см
Thanks for the info!
RealSel* behaves better.
But I have the following problem:

When using the aformentioned code to generate line 1 to 3 (2017-05-04 09:55:23) with the following code:

procedure TForm1.KMemo1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  writeln (MidStr(KMemo1.Text,KMemo1.RealSelStart,KMemo1.RealSelLength));

When I select „Line 1‟ everything is fine.
But when I select „Line 1‟ together with the first „Li‟ from the second line I get on the screen

instead of

I also tried

procedure TForm1.cmdTextPosClick(Sender: TObject);
  KMemo1.Blocks.AddTextBlock('Line 1');
  KMemo1.Blocks.AddTextBlock('Line 2');
  KMemo1.Blocks.AddTextBlock('Line 3');
  ShowMessage (midstr(KMemo1.Text,0,6));
  ShowMessage (midstr(KMemo1.Text,0,7));
  ShowMessage (midstr(KMemo1.Text,0,8));
  ShowMessage (midstr(KMemo1.Text,0,9));

In this sample ShowMessage (midstr(KMemo1.Text,0,7)); and ShowMessage (midstr(KMemo1.Text,0,8)); display the same.
I found that RealSel* considers the NewLine as a single character, while it is most likely two charcters (#13#10). Maybe this is system dependent?

Or should I use something else instead of „Text‟ in „KMemo1.Text‟?
inserted: 2017-05-14 10:55:39   Reply...
From: tk
A paragraph mark is always taken as single selection entity. You should use SelText property to get selected text.
inserted: 2017-05-15 10:10:55   Reply...
From: см
I actually need to get the first several characters of the selected lines (which might not be completely selected).
So I was thinking to get the position of the selection, using .RealSelStart and to search back in KMemo1.Text for a #13#10 to find the beginnings of the lines.
What actually happens is that .RealSelStart considers paragraph mark as single character, while KMemo1.Text returns the paragraph as #13#10 and I cannot find where the selection is located within .Text.

What I could do is to use MidStr(StringReplace(KMemo1.Text,#13#10,#13,[rfReplaceAll, rfIgnoreCase]),KMemo1.RealSelStart,KMemo1.RealSelLength)); but it will actually take minutes.
I wonder if I could use KMemo1.ActiveBlocks.Text and if it would be faster?
Or should I use some other property instead of .Text?
Otherwise I cannot think of a possible practical usage of .RealSel*.

Also, since RTF is a MS format, I suppose that paragraph shall always be #13#10 (system independent).
inserted: 2017-05-15 16:26:11   Reply...
From: tk
StringReplace(KMemo1.Text,#13#10,#13,[rfReplaceAll, rfIgnoreCase]) should be fast, at least for reasonable long documents. If it isn't then there is something wrong with your document.

When replaced, the selection markers should match the text (provided there are no inline images etc. in the memo, which also take one selection position).

But you could also traverse lines of your document. Use KMemo1.ActiveBlocks.LineCount to get number of lines and KMemo1.ActiveBlocks.LineText to get text of each line.
Use KMemo1.ActiveBlocks.LineStartIndex and LineEndIndex to compare with KMemo1.RealSel* properties.
inserted: 2017-05-17 08:18:51   Reply...
From: см
Hi, thanks for the hints!

The following code for one of the cases:
    WriteLn('ActiveBlocks.LineCount= ' + IntToStr( KMemo1.ActiveBlocks.LineCount));
    WriteLn('StringLength= ' + IntToStr(Length(KMemo1.Text)));
    WriteLn('StringLengthAB= ' + IntToStr(Length(KMemo1.ActiveBlocks.Text)));
    WriteLn('Replacement started at ' + IntToStr(GetTickCount64));
    WriteLn('Replacement done at ' + IntToStr(GetTickCount64));

resulted in
    ActiveBlocks.LineCount= 0
    StringLength= 3991513
    StringLengthAB= 3991513
    Replacement started at 689619548
    Replacement done at 689699467 (79,919 seconds)

Considering that some of the documents are bigger, replacement will be really painful.
I have no clue why ActiveBlocks.LineCount returns 0. The entire document is displayed in a single table, maybe that causes the confusion.

If I understand you right, I cannot use „Use KMemo1.ActiveBlocks.LineStartIndex and LineEndIndex to compare with KMemo1.RealSel* properties.‟ without replacing new lines?
I will think for some workaround.
inserted: 2017-05-18 10:45:14   Reply...
From: tk
If the document has only one big table then you would need to traverse lines in individual cells. Instead of KMemo1.ActiveBlocks you would need to use YourTable.Cells[Column, Row].Blocks.

Getting KMemo1.Text should be fast though. Maybe StringReplace itself is slow for such a long string?

var S: string;
S := KMemo1.Text;

What line is slow?

I would need to see the document to say why KMemo1.ActiveBlocks.Linecount is zero. If the document has only one big table with mbpText position then it should be 1.
inserted: 2017-05-19 15:16:35   Reply...
From: см
S := KMemo1.Text; took 1,3 s.
StringReplace(S,#13#10,#13,[rfReplaceAll]); took 104,5 s

I wrote the code below and
   1. WriteLn (LazUTF8.UTF8Copy(... returns the selected contents, which seems okay.
   2. WriteLn ('linecount='+IntToStr (TKMemoTableCell(Block).Blocks.LineCount)); returns the number of selected lines if they belong to a SINGLE cell. If they belong to more than one cell it returns 1.
So it seems that .LineText is not applicable when multiple cells are selected. I am still not sure that method 1 won't be slow on bigger tables (my cells are not big).
I still have not made tests with bigger tables, I will feedback later.

What I noticed is that when I drag the mouse vertically, not only the cells of the same columns are selected, but also from the neighbouring columns.
When I drag the mouse horizontally, only cells of the same row are selected.
MS Word and Excel (I cannot check other similar apps) do not behave like this- when the mouse is dragged only vertically, only cells of the same column are selected.

procedure TForm1.KMemo1BlockClick(Sender: TObject; ABlock: TKMemoBlock; var Result: Boolean);
  Block: TKmemoBlock;
  S: string;
  LineIndex: integer;
  FirstLine, LastLine: string;
  Block := ABlock;
  while (Block <> nil) and not (Block is TKMemoTableCell) do
    Block := Block.ParentBlocks.Parent;
  if Block <> nil then
    WriteLn (LazUTF8.UTF8Copy(S,TKMemoTableCell(Block).Blocks.RealSelStart+1,TKMemoTableCell(Block).Blocks.RealSelLength));
    WriteLn ('linecount='+IntToStr (TKMemoTableCell(Block).Blocks.LineCount));
    if TKMemoTableCell(Block).Blocks.LineCount>0 then
       for LineIndex:=0 to TKMemoTableCell(Block).Blocks.LineCount-1 do
         if (TKMemoTableCell(Block).Blocks.RealSelStart>=TKMemoTableCell(Block).Blocks.LineStartIndex[LineIndex])
           and (TKMemoTableCell(Block).Blocks.RealSelStart<=TKMemoTableCell(Block).Blocks.LineEndIndex[LineIndex])
           then FirstLine:=TKMemoTableCell(Block).Blocks.LineText[LineIndex];
         if (TKMemoTableCell(Block).Blocks.RealSelEnd>=TKMemoTableCell(Block).Blocks.LineStartIndex[LineIndex])
           and (TKMemoTableCell(Block).Blocks.RealSelEnd<=TKMemoTableCell(Block).Blocks.LineEndIndex[LineIndex]) then
           end; //if
       end; //for
    end; //if
    WriteLn ('FirstLine=' + FirstLine);
    WriteLn ('LastLine=' + LastLine);
    Result := True;
inserted: 2017-05-19 15:29:26   Reply...
From: см
I forgot to mention, that s:=StringReplace(Block.Text,#13#10,#13 is not fine, new paragraph should be converted to #10 instead. Anyway, to evade suprices, the #10 should better be replaced back to #13#10.
Also, .LineText return the line with the NewLine chracters included. Should it be this way?
inserted: 2017-05-25 09:43:57   Reply...
From: tk
Everything is ok then. You maybe have to write your own, faster variant of StringReplace. Each cell is a container which has own blocks and lines. Table selection behaves only such way, no column only selection is possible.
inserted: 2017-05-25 13:48:50   Reply...
From: см
I have implemented it with .Blocks.Line*Index and Blocks.LineText[] and seems to work fine without replacing paragraph marks.
Selecting lines from different does seem to make sense (at least until now) for my application.
inserted: 2017-05-15 11:06:10   Reply...
From: см
It occurs that MidStr won't do at all. It returns number of bytes, not numbers of characters (so it won't work with unicode). I am searching a proper function and I will feed back later.
inserted: 2017-05-15 13:19:56   Reply...
From: см
I tried the code below (in Lazarus), now non-latin characters are handled properly, but #13 and #10 are still considered separate characters (which seems fine to me, since they have separate purpose). Maybe Delphi acts differently?

for i:=1 to Length(content) do
    WriteLn (crchar);
inserted: 2017-05-02 07:27:14   Reply...
From: Randell
I am installing KControls. I got 'Fatal:Cannot find KRes used by KGraphics of package KControlsLaz.' I am using Lazarus 1.6.0. Help
inserted: 2017-05-06 14:43:03   Reply...
From: Randell
Downloaded from Bitbucket and it had missing file. It installed and I have started playing with the controls.
inserted: 2017-05-08 11:15:44   Reply...
From: tk
Until now KRes.pas was missing in both packages but it always worked for me. Now I included it in kcontrolsbase.lpk.
inserted: 2017-04-28 00:16:34   Reply...
From: josh
Installed latest lazarus trunk (1.9)
Download kcontrols from bitbucket
I cannot install, errors out kgrids 2942 with
kgrids.pas(2942,15) Error: There is no method in an ancestor class to be overridden: "DoAutoAdjustLayout(const TLayoutAdjustmentPolicy;const Double;const Double;const Boolean);"

{$IF lcl_fullversion >= 1080000}
    procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
      const AXProportion, AYProportion: Double; const AScale0Fonts: Boolean); override;
inserted: 2017-04-28 11:53:13   Reply...
From: tk
It seems that Lazarus developers modified the ancestor class in the trunk. Simply delete that method or change the ifdef so that you can compile. I'll check it when I need to update Lazarus from trunk.
inserted: 2017-04-17 09:18:48   Reply...
From: CT

Is it possible to do grouping in KDBgrid ?

inserted: 2017-04-26 23:15:25   Reply...
From: tk
What is grouping?
inserted: 2017-04-05 15:37:53   Reply...
From: см
I cannot find a way to disable text wrapping for a text block or a table cell.
   TKMemoTextBlock.WrapMode is read only;
   TKMemoTextBlock.WordBreakStyle has no option NoBreak;
   TKMemoTextBlock.WordBreaks is read only;
Could there be a way to disable wrapping?
inserted: 2017-04-07 14:27:18   Reply...
From: tk
This is possible only for a whole paragraph, with TKMemoParagraph.ParaStyle.WordWrap.
inserted: 2017-04-07 15:05:38   Reply...
From: см
I just found that
disables wrapping (sample below). But according your explanation, is this the expected behaviour?

procedure TForm1.Button4Click(Sender: TObject);
  MyTable: TKMemoTable;
  MyBlock: TKMemoTextBlock;
   MyBlock:=MyTable.Cells[2,2].Blocks.AddTextBlock('asdfljlkslkdflksjdflkasjkldsj kldfsklajdskladkljdksjldjklsdakjlkjdlfkasjldkdjfljkasdjkldaskjldkjlsdajkldsajkldsjk;ldsajkl;dsakjl;sadjkl;daskjl;daskjl;adsfjk;lreiotoietyitetiuoetuietieiptuoiupoteiupofljkjfskfgsdjjfksd;jkfldj;,.m');
inserted: 2017-04-07 16:10:13   Reply...
From: см
And this disables wrapping for a cell of a table:

if aMemoTable.Rows[Row].Cells[Column].Blocks.Count>0 then
  for BlockIndex:=0 to aMemoTable.Rows[Row].Cells[Column].Blocks.Count-1 do
   if aMemoTable.Rows[Row].Cells[Column].Blocks[BlockIndex] is TKMemoTextBlock
then TKMemoTextBlock(aMemoTable.Rows[Row].Cells[Column].Blocks[BlockIndex]).WordBreakStyle:=wbsFirstWordChar;
inserted: 2017-04-26 23:14:55   Reply...
From: tk
Actually wbsFirstWordChar has not been tested yet.
I am pretty sure it now equals 'wbsNoBreak' because under normal circumstances the condition CharInSetEx(S[1], [cTAB] + Wordbreaks), now present in TKMemoTextBlock.GetWordBreakable, always returns False.

inserted: 2017-04-27 10:20:34   Reply...
From: см
Actually currently there is no parameter, named „wbsNoBreak‟ but IMHO, it would be useful.
inserted: 2017-04-04 13:39:12   Reply...
From: Ian
When we set EditorMode to False in TKGrid, if there is not text in the editor control then an exception is raised.

I have tracked the problem to GetControlText which is in KControls. Within this function is GetTextBuf. Before the line Value.GetTextBuf(...) I have added:
if Length(Result) > 0 then

This has stopped the exception.
inserted: 2017-04-04 21:21:40   Reply...
From: tk
Thanks, I will apply your patch in next commit.
inserted: 2017-04-05 11:47:34   Reply...
From: Ian
Glad I could contribute, even if in such a small way.

Thank you for such a great component.
inserted: 2017-03-30 16:47:55   Reply...
From: Sat1
Dobry den, existuje prosim nejaka moznost jak nastavit sirku sloupcu DBGridu v kodu? Klasicka moznost DBGrid1.Columns[i].Width neni.
Dale prosim o radu zda lze v sloupci zobrazit hodnoty v comboboxu, nebo listboxu.
Moc dekuji
inserted: 2017-03-31 14:18:11   Reply...
From: tk
Please speak English here so that others can read this thread.

1. In KDBGrid there is TKDBGrid.Columns[I].Extent (or classic TKDBGrid.ColWidths[I] instead of TDBGrid.Columns[i].Width.

2. You can show/edit cells in combobox or listbox with KDBGrid. You just have to create and use custom inplace editors for respective columns. Look at KGrid demo (event chain OnEditorCreate, OnEditorDataFromGrid, etc.) or maybe best at methods TKDBGrid.DefaultEditorCreate, TKDBGrid.DefaultEditorDataFromGrid etc.
inserted: 2017-03-27 14:37:15   Reply...
From: см
In Lazarus, I am trying to resize an image and then add it into a TKMemo with the code below. For some reason only an empty rectangle is shown.
Could it be me doing something wrong or there is a problem in TKMemo?
When I add the downscaled image to Image1: TImage; it is displayed just fine.

procedure TForm1.Button1Click(Sender: TObject);
  ImagePicture: TPicture;
  bmp: TBitmap;
  ImagePicture:= TPicture.Create;

    bmp := TBitmap.Create;
    bmp.Width := Round(ImagePicture.Width /4);
    bmp.Height:= Round(ImagePicture.Height/4);
    bmp.Canvas.StretchDraw(Rect(0,0, Round(ImagePicture.Width /4), Round(ImagePicture.Width /4)), ImagePicture.Graphic);
    bmp.SaveToFile ('c:\scaled_image.png'); //Downscaled image is stored to a file as expected

  Image1.Picture:= ImagePicture; //Downscaled image is displayed fine in Image1
  KMemo1.Blocks.AddTextBlock ('Image top');
  KMemo1.Blocks.AddImageBlock(ImagePicture); //An empty rectangle is added in KMemo1
  KMemo1.Blocks.AddTextBlock ('Image bottom');
inserted: 2017-03-31 14:05:11   Reply...
From: tk
TBitmap is not supported in KMemo. Convert the downscaled image to PNG and load it to KMemo.
inserted: 2017-04-04 16:34:48   Reply...
From: см
Thanks, I downscaled to PNG directly and it works.
inserted: 2017-03-25 10:09:03   Reply...
From: taazz
There is a small bug in the TKPageControl component in lazarus. A number of SigsegV exceptions are raise when ever a tabsheet is destroyed after it was placed inside a kpagecontrol. The problem comes form the TTabSheets class which is based on the TObjectlist which in turn has the OwnsObjects property set to true by default. Every a TKtabsheet is removed from the pagecontrol it is automatically destroyed and in most cases a second call free follows which raises the exceptions.
inserted: 2017-03-31 14:03:01   Reply...
From: tk
TKPagecontrol has not yet been fully finished and tested in Lazarus.
inserted: 2017-05-04 08:47:15   Reply...
From: valdir
I am trying to use TKPagecontrol from both KControls 1.7 stable and latest unstable from versions and the component is not working on Lazarus 1.6.4.

Should I use Lazarus 1.8 to overcome those erros?

inserted: 2017-05-18 10:50:08   Reply...
From: tk
You would need to fix TKPagecontrol to work with LCL. It is not ready for use in Lazarus yet. We've been using it only in Delphi so far, there it works fine.
Older comments
My account
Recently modified

KControls Component Suite

by: tk



by: tk



by: tk



by: tk


KGrid 1.3 released.

by: tk


Recently inserted


by: tk


Grouping of comments

by: tk



by: tk


My recent work on KMemo

by: tk


Update for RAD Studio XE2

by: tk