Skeez
Skeez is an animated list view component for Delphi (Win32, Win64) based on Graphics32 and a native FireMonkey component.
The package includes derived components: filesystem browser, picture list viewer and audio file list viewer.
Features:
- Animated list view (add, refresh, delete, move)
- Support for multi-line text with expandable height
- Hot track, hint, scroll to/select item on keypress, edit item's caption
- Re-draw existing item (partially) with optional animation
- Multi-column mode
- Grouping option
- Custom sort the list
- Built-in animations: XY, Zoom, FadeIn, or implement custom animation with an event
- User interface DPI scaling support (simple as TSkeez.Scale := 2 that is 200%)
- Filesystem browser with full support for virtual objects (PIDLs) and shell change notifications
- Picture (thumbnail) list viewer class, uses FreeImage.dll for loading many formats of picture files and displays their EXIF information if available
- Audio (tag) list viewer class with support for all the current audio tag standards
- Fully customizable display with support for variable item height within the same list
- FMX version supports any kind and number of sub-controls for items, like checkboxes, radio buttons or comboboxes etc.
- The derived classes support browsing the file system or items can be added manually
- Multi threaded derived classes
New from version 1.4.82.222: Android compatibility, use FMX.Skeez as a list view component on Android. Tutorial for Android is included in the package.
When building for Android, additional features are available:
- Scroll the list vertically with gestures up & down, slow movement scrolls only by movement amount, quick movement scrolls half of the visible screen by default (configurable)
- Swipe delete items with horizontal gesture (animated, configurable)
The audio list view component uses Tags Library, the used Delphi tagging libraries are also available separately:
ID3v1 and ID3v2 tagging unit: ID3v2 Library
MP4 tagging unit: MP4 Tag Library
APEv2 tagging unit: APEv2 Library
Ogg Vorbis and Opus tagging unit: Ogg Vorbis and Opus Tag Library
Flac tagging unit: Flac Tag Library
WMA tagging unit: WMA Tag Library
WAV tagging unit: WAV Tag Library
If you have any question, please write to: 3delite@3delite.hu
Skeez in shareware and commercial software?
The component comes with full source code and can be evaluated freely. If you like it and decide to use it in a freeware, shareware or commercial (or any other money making - advertising, in app. selling, etc.) product one of the licenses is needed.
Requirements
Delphi 2009 and above with Graphics32. There is a Delphi 7 version of the basic TSkeez class in the package too.
The filesystem and it's derived classes require Windows Vista or above.
The FireMonkey version (beta) is completely based on FireMonkey, no Graphics32 is needed at all.
Limitations in the current beta version:
- 'BackgroundColor' is enabled by default, if you want to use styles disable {$DEFINE USEBACKGROUND} in FMX.Skeez.pas.
- Drag & drop support for TSkeezFilesystem class (Windows only) supports only dropping items into the component area (and supports dropping into folders too) and droping within the same Skeez component, but dropping files and folders from Skeez to other apps does not work. It seems maybe Delphi FMX implementation is not complete, the DragObject.FileNames variable is populated properly (I think) but other app windows show a no-no for accept. FMX.Skeez.pas line 1870. Suggestions are welcome!
- TSkeezFilesystem and derived classes TSkeezAudios and TSkeezPicures class requires FreeImage.dll (FMX.TBitmap is no thread safe it seems, and graphic processing is needed in worker threads for a smooth animation in the main thread).
Installation
If Graphics32 is not already installed, it's recommended to install it - although it's not needed to install it for Skeez to compile, it's enough to have the Graphics32 units on the search path. But Graphics32 is a great component you might want to decide to use it.
Extract the .zip archives ('bass24.zip', 'graphics32-code-2197-trunk.zip' and 'KleverComponents.zip') from where you installed/extracted Skeez files to a folder.
Create a new package, menu: File/New/Package - Delphi, save it with a new name, menu: File/Save Project As.... for example 'PackageSkeez.bpl'. On the upper-right corner of the Delphi window right mouse click on the package name you saved as, and click on 'Add' from the pop-up menu and add 'Skeez.pas', 'SkeezFilesystem.pas', 'SkeezPictures.pas' and optionally 'SkeezAudios.pas' and 'MultiThread2.pas' and 'Skeez.dcr' for the icon.
Add the directories to the tagging libraries ('..\Delphi\Tagging Libraries\APEv2 Library\' etc.) and all required .pas files to the search path too - Menu: Project/Options, select 'Delphi compiler', in the upper part of the window select 'All configuration', below click on 'Search path' and add the paths where you installed/extracted Skeez.
Right mouse click again on the package name and select 'Build', if successfull, again right mouse click and select 'Install'.
Note: If you get a package build error, comment out '{$DEFINE COMDRAGDROP}' in SkeezFilesystem.pas when building the package. If the build is successfull save the package and enable this compiler directive again - it should work for a real build.
If everything went smooth the components will show up on the '3delite' tab.
To be able to build the tutorials create a new package, as described above, and this time add 'rkShellPath.pas' and 'rkPathViewer.pas' to the package and use a different package name for example 'Packagerk.bpl'.
Build and install it too.
If everything went smooth the components will show up on the 'rmklever' tab.
To install the FireMonkey version do the same as described above, add 'FMX.Skeez.pas', 'FMX.SkeezFilesystem.pas', 'FMX.SkeezPictures.pas' and optionally 'FMX.SkeezAudios.pas' and 'MultiThread2.pas' and 'FMX.Skeez.dcr' (for the icon) to the new package, just create a different package name.
Note that it's not yet supported to install both VCL and FMX versions, so choose only one version.
Properties and methods
Published properties
- AllowEdit: Enable possibility of editing the first text item of a Skeez item. Can be invoked from code with Skeez1.Edit(Index) or with middle mouse button clicking on an item. Notification of an edit is available with the OnItemEdit() event.
- AllowHotTrack: Enable to mark the item below the mouse cursor. Use 'ItemHotTrackOptions' to specify the hot tracking colors and alpha value.
- AllowKeySelect: If True and the Skeez control has focus, pressing a key on the keyboard scrolls to and selects the first item which matches the character (first text item's first character). If another key is pressed in 2 seconds, the first 2 characters are searched.
- AllowMultiSelect: More than 1 item can be selected by holding down the Shift or Ctrl key and clicking with the left mouse button on items.
- AllowSelect: Enable to select the item with the mouse cursor and keyboard cursor keys. Use 'ItemSelectionOptions' to specify the selection colors and alpha value.
- AnimationExpandCollapseTime: Specify how long does an expand or collapse animation take when expanding multi-line texts.
- AnimationPictureTime: Specify the picture moving time in milliseconds.
- AnimationPictureX: Specify the pixel count from where the picture start to move.
- AnimationTextTime: Specify the text moving time in milliseconds.
- AnimationTextX: Specify the pixel count from where the text start to move.
- BackgroundColor: Specify the display's background color.
- HintHideTime: Specifies how long to display a hint. Implement OnItemHint() event to hide the hint.
- HintShowTime: Specifies how long the mouse cursor needs hovered above an item to pop-up a hint. Implement OnItemHint() event to show the hint.
- ItemAudioProperties / ItemFileProperties / ItemPictureProperties: Specify the properties of the items. 'ItemFileProperties' always specifies the file items' properties including when using the picture and audio lister. One of the important values is the 'ItemHeight' variable, which specifies the height of the items. Note that you can always specify a custom (item-by-item different) height when adding the TSkeezItems to the queue. File items and picture/audio items will have the same item width though. Use Icon/Picture/CoverArt to specify these pictures' dimensions on the display.
- ItemHotTrackOptions: Specify the hot track colors and alpha value ('AllowHotTrack' needs to be 'True').
- ItemSelectionOptions: Specify the selection colors and alpha value ('AllowSelection' needs to be 'True').
- ItemParseMode: Specifies how many items to parse for a single 'ParseInQueue' call. 'sipmOne' means one item on every call, which results linear animation, the items will move one by one with a delay how frequently 'ParseInQueue' is called. 'sipmAll' will process all items in the incomming queue, results faster displaying of the items but items will move together in parallel.
- MarginHorizontal: The padding (space) between the display's left side and the items. Also the margin on the right side of the display.
- MarginVertical: The padding (space) between the display's top and the items. Also the margin at the bottom of the display below the last item.
- MultiColumn: If 'MultiColumn' is True, items are drawn side-by-side if the display width is large enough for multiple columns. For example for 2 multi columns the needed space is HorizontalMargin * 2 + Item's total width for all the columns. Multi columns and item columns are 2 separate things. Columns specify an item's text and picture positions, while multi column specify to allow to draw the items horizontally side-by-side if enough space is available.
- MultiColumnCompact: Only has effect if 'MultiColumn' is True, items in one column are compacted vertically, that is every item appears right under the one above. If this flag is not set every item is lined up with the items on the left and on the right to it. Selecting items with cursor keys and methods 'MoveCursorUp' etc. selects the item explicitly to the left/right/above/below.
- MultiThreaded: For the derived components, this value specifies to use multi threading for loading of the icon/picture/cover art pictures. If this is 'False' these pictures will be parsed in the main thread, which means if the CPU is not powerfull enough the animation will be jerky, but linear. It is recommended to always use multi-threading, for your implementation too.
- OnlyFilesystem: When browsing folders display only file system items (folders and files).
- ItemSpacingX and ItemSpacingY: The empty space between items. Left most item appears only by the 'MarginHorizontal' value, top most items appear only by 'MarginVertical'. These values only specify space between items.
Events
- OnAddItem: Called when adding an item to the list, useful for adding any custom text and pictures when using the file system/picture/audio components. You can add a column (about it later) and add custom informatiom. For example:
with DisplayItem.AddText('My text') do begin
Position.X := 5;
Position.Y := 5;
ColumnIndex := 2;
end;
- OnCanAdd: Implement this event to filter what files are added to the list in case of the picture and audio component. Set 'Add' to False to not list the file.
- OnFileSelect: If the user double-clicks an item which is not a folder this event is called.
- OnFolderChange: Notification on going into a folder.
- OnGetAudioAttributes: For the audio component implement this event to display the audio file's attributes like sample rate, channel count, etc.
- OnItemCompare: When calling 'TSkeez.Sort' the items with the specified 'OnItemCompare' event will be sorted. Use the 'Item.Data' class to perform the comparison. This object will be for example 'TSkeezAudioData (Item.Data).FileName' for the audio lister class, 'TSkeezFileData(Item.Data).FileName' for the file system browser component, or the one you added to 'SkeezItem.Data' when adding the skeez items. You should inherit from these types when using the picture and audio component and add your fields to it - this way Skeez will still be able to use these objects like identifying whether it's a folder or a file.
- OnItemEdit: If AllowEdit is True, after editing an item's first text item when user presses Enter this event is called. Set 'Allow' to False te reject the modification.
- OnItemFree: Called when freeing an item. Implement clean-up of an item's 'Data' if needed.
- OnItemHint: This event is called when a hint needs to show (Show = True) or needs to hide (Show = False).
- OnItemHot: If 'AllowHotTrack' is True get notification when an item becomes hot.
- OnItemSelect: Happens when the user selects an item with mouse clicking on it, or with the cursor keys (not double-click, that is OnFileSelect).
- OnLayerDrawAfter / OnLayerDrawBefore: It's possible to draw on the TBitmap32 pictures that Skeez generates from TSkeezItems' text and picture lists with this event.
- OnNeedDataClass: To extend the standard description object for a file item implement this event. Inherit from default class, in case of the file system list component: 'TSkeezFileData', for the picture list: 'TSkeezPictureData' and for the audio list from 'TSkeezAudioData' and in this event create your class for the 'Data' parameter.
Example for 'TSkeezFilesystem':
type
TMyData = class(TSkeezFileData)
MyField: String;
end;
procedure TForm1.SkeezListNeedDataClass(Sender: TObject; PIDL: PItemIDList; FileName: string; var Data: TSkeezFileData);
begin
Data := TMyData.Create;
end;
Now this new data can be accessed from a TSkeezItem, with:
(Item.Data as TMyData).MyField
or everywhere when you get a 'TSkeezFileData' type object:
(FileData as TMyData).MyField
Groups
Set 'GroupView' to 'True' and add groups as needed. When adding items specify all items' 'GroupIndex' to the needed group.
The position of an item in a group depends on it's 'Index' variable. A higher 'Index' is after a lower one. But the items are 'randomly' in the 'Items' list - only their before-after order effects their position displayed within a group.
To owner draw the group header set 'GroupHeaderOwnerDraw' to 'True' and assign the 'OnGroupHeaderDraw' event. The event will receive the needed canvas width, set the canvas size to this width or a smaller size.
It's possible to draw icons or additional details on the group headers. When 'Caption' is set (changed) the header is automatically re-drawn - by the event if set.
The event should be fast as possible, when resizing the component group headers will be re-drawn on every size change.
Themes
Setting any of the built-in themes by code will override any settings set in Object Inspector.
Transparency option
The VCL version does not, but the FMX version does support transparent backgrounds.
For the VCL version a workaround is to assign a picture to 'Skeez1.Display':
Skeez1.Display.Bitmap.LoadFromFile('C:\Picture.bmp');
To adjust the background picture appearance use:
Skeez1.Display.ScaleMode := smStretch;
Check the 'ScaleMode' options for more modes.
If the rest of the window contains the same picture (offset from the set background) it will look like it's transparent.
To set the FMX version transparent, first comment out the '{$DEFINE USEBACKGROUND}' in 'FMX.Skeez.pas', for example add a '.' (dot) like '{.$DEFINE USEBACKGROUND}'.
Save the changes and in form view right-mouse-button click on the Skeez object and select 'Edit Custom Style...'. Select the large recntangle that represent the Skeez object and set in Object Inspector 'Fill.Color' to a trasparent value, like $44000000. Setting this to 'null' (or $00000000) will result a completely transparent background.
Set the 'Sides' values to False if the border is not needed, close the style designer, and also disable column header for the Skeez object in Object Inspector if not needed.
Tip: Setting the background (as written above) to some semi-transparent value and using a picture behind the Skeez object will probably look cool as the picture covered by the Skeez object will appear darker. If the picture ('TImage' - 'Shapes' tab) appears above the Skeez panel, right-mouse-button click on the image object and select 'Control/Send To Back'.
Don't forget to set the new style values for every platform (selectable above the style editor (top-center) when the style editor is opened)!
UI DPI scaling (Graphics32 version)
There are 2 scaling properties: 'FontScale' and 'ItemScale'.
It's advised to set the Delphi project's "Manifest/DPI awereness" to at least "System aware". In this case font size scaling is performed automatically by the project. But it is explicitly needed to adjust the 'ItemScale' property.
'ItemScale' property needs to be in sync with actual font size scale, but not with 'FontScale' in this case.
Te get the 'ItemScale' value eg.:
SkeezFilesystem1.ItemScale := Self.Monitor.PixelsPerInch / 96;
If the app. (process) is anaware of UI DPI scaling, both 'FontScale' and 'ItemScale' needs to be set to the same value.
Using the 'PIDL' functions
All PIDLs passed to methods are handled automatically by Skeez afterwards, there's no need to free them. But note that when the methods return they may already free them, if you need the PIDLs after calling the methods, please make a copy of them with ILClone() before calling the Skeez methods.
The only exception is ListFolder(), it clones the PIDL internally so the PIDL given in the parameter needs to be freed afterwards in your own code.
Using the OnCanAdd() event for SkeezFilesystem to filter files
To implement a file name pattern matching, implement the OnCanAdd() event eg.:
procedure TForm.SkeezListCanAdd(Sender: TObject; Item: PItemIDList; FileName: string; IsFolder: Boolean; var Add: Boolean);
begin
//* Always add folders
if IsFolder then begin
Add := True;
Exit;
end;
//* There is a wildcard pattern specified
Add := TPath.MatchesPattern(ExtractFileName(FileName), '*.jpg', False);
end;
Turning off animations
It is possible to turn off all animations and have the benefits of Skeez's item layouts.
Set all animation 'duration' values to '0'. If instant update is needed also use 'ParseInQueueAll' instead of 'ParseInQueue'.
Tips
- It is a good idea to prepare the item data in separate thread(s) with a lower priority then the main thread and use the main thread just for the UI.
Load the data in a thread and with Skeez1.InQueue.Add(SkeezItem) send it to Skeez. The main UI thread will process this in the main thread when ParseInQueue is called which results smooth animations.
One can easily implement multi threading with the included TMultiThread2 class (see the implementation in TSkeezFilesystem, TSkeezPictures or TSkeezAudios).
- To add custom text or pictures to an item, use the OnAddItem() event, for example:
with SkeezItem.AddText('My text') do begin
Font.Size := 10;
Position.X := 6;
Position.Y := 6;
ColumnIndex := 2;
end;
with SkeezItem.AddPicture(Bitmap32) do begin
Position.X := 4;
Position.Y := 6;
//* This will use the 'Position' values, else the picture will be centered in it's column
Align := paCustom;
end;
- By default 2 columns are created: first one for the icon/picture, second for the text. To add columns use:
var
Column: TSkeezColumn;
begin
//* Basic data
Column := TSkeezColumn.Create;
Column.Caption := 'Data';
Column.Width := 350;
Skeez1.Columns.Add(Column);
end;
- To update a text (or picture) of an existing item already in the list, send 'TSkeezItemText', 'TSkeezItemTextMultiLine' or 'TSkeezItemPicture' with 'InQueue.Add()'.
There are 2 options: if you specify 'Index := - 1' then the object will be added, if you specify an existing object 'Index > - 1' (and exists) the text/picture will be replaced. Parent and ParentGUID are always needed to identify which item is to be updated. If you work in thread NEVER access the 'Work.ParentSkeezItem' fields, it could be freed in the mean time if the user navigated to another folder/list, just use it as identification (the pointer and the GUID) for the item to be updated. Extract from SkeezPictures.pas - PictureLoaderThreadWorkerCallback():
//* Send the loaded picture to Skeez
SkeezItemPicture := TSkeezItemPicture.Create;
//* This needs to be a TSkeezItem which will be updated
SkeezItemPicture.Parent := Work.ParentSkeezItem;
//* This needs to be a TSkeezItem's GUID which will be updated
SkeezItemPicture.ParentGUID := Work.ParentSkeezItemGUID;
//* Use current ListingID, else this update will be
//* discarded (list changed in the mean time)
SkeezItemPicture.ListingID := Work.ListingID;
SkeezItemPicture.Bitmap := Picture; //* The new picture
Params.SkeezPictures.InQueue.Add(SkeezItemPicture);
//* Send the original dimensions text to Skeez
SkeezItemText := TSkeezItemText.Create;
SkeezItemText.Parent := Work.ParentSkeezItem;
SkeezItemText.ParentGUID := Work.ParentSkeezItemGUID;
SkeezItemText.ListingID := Work.ListingID;
//* The new text
SkeezItemText.Text := IntToStr(OriginalWidth) + ' x ' + IntToStr(OriginalHeight);
//* The 'TSkeezItemText' index in TSkeezItem.TextItems[Index] that you want to update
SkeezItemText.Index := 2;
//* This means the new text will be animated "in"
SkeezItemText.AnimState := asStarting;
Params.SkeezPictures.InQueue.Add(SkeezItemText);
- Columns and column header: There's a TSkeez.Columns[] TList which holds the columns, the order specifies the order in which the columns are displayed.
Each TColumn in this list has an 'Index' property which identifies the column, use this index in item's text and graphic items to specify in which column they appear. Make sure to not use the same 'Index' for multiple columns.
To display a column listed ascending/descending add a unicode "up arrow/down arrow" to it's caption: http://unicode-table.com/hu/sets/arrows-symbols/
When changing column stuff if there are problems call TSkeez.ColumnHeader.Update to re-draw the column headers.
Do not set the columns 'MinWidth' too low - it needs to be at least '...' characters' width or the code will go into and endless loop if that doesn't fit.
To use a background picture use:
Skeez1.Display.Bitmap.LoadFromFile('C:\Picture.bmp');
To adjust the background picture appearance use:
Skeez1.Display.ScaleMode := smStretch;
Check the 'ScaleMode' options for more modes.
- When using Delphi's VCL styles use the following code to adjust the colors on style change (TSkeezFilesystem example):
Uses
GR32,
Vcl.Themes,
Vcl.Styles;
procedure UpdateSkeezStyle(SkeezFilesystem: TSkeezFilesystem);
var
BackgroundColor: TColor;
ListerFontColor: TColor;
ColumnHeaderTopColor: TColor;
ColumnHeaderBottomColor: TColor;
ColumnHeaderFontColor: TColor;
ColumnHeaderBrightColor: TColor;
ColumnHeaderDarkColor: TColor;
LStyle: TCustomStyleServices;
Item: TSkeezItem;
i, k: Integer;
begin
//* Style enabled?
LStyle := StyleServices;
if LStyle.Enabled
AND (TStyleManager.ActiveStyle.Name <> 'Windows')
then begin
//* Get the current style's colors
ColumnHeaderTopColor := LStyle.GetStyleColor(scGenericGradientBase);
ColumnHeaderBottomColor := LStyle.GetStyleColor(scGenericGradientEnd);
ColumnHeaderBrightColor := ColumnHeaderTopColor;
ColumnHeaderDarkColor := ColumnHeaderBottomColor;
ColumnHeaderFontColor := LStyle.GetStyleFontColor(sfHeaderSectionTextNormal);
BackgroundColor := TStyleManager.ActiveStyle.GetStyleColor(scListView);
ListerFontColor := TStyleManager.ActiveStyle.GetSystemColor(clWindowText);
end else begin
//* Set your default Windows style colors here (white theme used here)
BackgroundColor := clWindow;
ListerFontColor := clWindowText;
ColumnHeaderTopColor := WinColor($FFFDFDFD);
ColumnHeaderBottomColor := WinColor($FFBBBBBB);
ColumnHeaderBrightColor := clWhite;
ColumnHeaderDarkColor := WinColor($FFAAAAAA);
ColumnHeaderFontColor := clWindowText;
end;
//* Set background color
SkeezFilesystem.BackgroundColor := Color32(BackgroundColor);
//* Set item text colors
SkeezFilesystem.ItemFileProperties.FileName.Font.Color := ListerFontColor;
SkeezFilesystem.ItemFileProperties.Size.Font.Color := ListerFontColor;
SkeezFilesystem.ItemFileProperties.DateTime.Font.Color := ListerFontColor;
SkeezFilesystem.ItemFileProperties.Description.Font.Color := ListerFontColor;
//* Column header
SkeezFilesystem.ColumnHeader.TopColor := Color32(ColumnHeaderTopColor);
SkeezFilesystem.ColumnHeader.BottomColor := Color32(ColumnHeaderBottomColor);
SkeezFilesystem.ColumnHeader.BrightColor := Color32(ColumnHeaderBrightColor);
SkeezFilesystem.ColumnHeader.DarkColor := Color32(ColumnHeaderDarkColor);
SkeezFilesystem.ColumnHeader.Font.Color := ColumnHeaderFontColor;
SkeezFilesystem.DrawColumnHeaders;
//* Redraw all items with new font color
if SkeezFilesystem.Items.Count > 0 then begin
for i := 0 to SkeezFilesystem.Items.Count - 1 do begin
Item := SkeezFilesystem.Items[i];
for k := 0 to Item.TextItems.Count - 1 do begin
Item.TextItems[k].Font.Color := ListerFontColor;
end;
for k := 0 to Item.TextMultiLineItems.Count - 1 do begin
Item.TextMultiLineItems[k].Font.Color := ListerFontColor;
end;
Item.ReDraw;
end;
end;
end;
- It's possible to modify the multi-line text expander/collapser icons by changing the SkeezIcons.res file. Using XN Resource Editor it's simple to edit the .res file, just use transparent PNG images and the same resource name for them. Or assign the pictures 'IconArrowDown', 'IconArrowUp', 'IconArrowDownHot' and 'IconArrowUpHot'.
- Skeez supports scaling the whole display with a helper property: 'Scale'. Values is 1.0 by default which is 100%. To double the display use 2.0 for both values.
Note that column widths are not resized because one might save/load the column widths manually.
To use the Windows' DPI scaling support you can use the code:
Skeez1.Scale := Screen.PixelsPerInch / 96;
Skeez1.ColumnHeader.Font.Size := Trunc(8 * Skeez1.ScaleText);
Picture items are also not resized automaticaly, as there is no copy of the pictures stored by Skeez. You have to give Skees pictures resized for your display.
- FireMonkey version supports any kind and number of sub-controls for items, like checkboxes, radio buttons or comboboxes as standard by FireMonkey.
There's a tutorial in the Skeez filesystem demo example on how to implement this.
- Aligning custom controls with the FireMonkey version: custom controls added are relative to item's top-left corner, if you are using columns and wish to adjust control positions when columns are resized implement the OnColumnResize event and re-position the controls within the event. Access the controls like this in the event (1 TCheckBox added as a custom control that is the 0 control index 'Container.Children[0]'):
for i := 0 to Skeez1.Items.Count - 1 do begin
(Skeez1.Items[i].Container.Children[0] as TCheckBox).Position.X := TheNewPositionX;
end;
Get all the column widths to the left with 'TheNewPositionX := TSkeez.GetColumnLeftSize(ColumnIndex)' that are to the left of the custom control column index.
Note that if using 'ContainerColumns' then all it's child controls are automatically resized if the child controls have Anchors = [..., akRight] specified.
- To have middle-mouse-button-click edit option for text fields that are empty a little trick is needed, specify these empty fields with empty strings like ' ' that are around that long as the field (or as long as the click detection is needed).
- Swipe delete on mobile: parameters for the funcionality are availbable in Object Inpsector under 'GestureOptions'.
Useful information
|