Recent

Author Topic: Which Control/Component Can Load Images In Cells  (Read 1357 times)

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Which Control/Component Can Load Images In Cells
« on: October 30, 2024, 04:34:02 am »
I'm new to using Lazarus. I'm trying to figure out which component/control is capable of loading image icons, progressbars, buttons, etc., inside of the cells. For example, a control such as TListView or TDBGrid, etc.. Which one is capable of loading images in any random column or row when needed? I'm looking for something that can do what Delphi is doing in their grids and listviews. Can Lazarus do this as well? If so, which control should I use to load small image icons?

cdbc

  • Hero Member
  • *****
  • Posts: 1656
    • http://www.cdbc.dk
Re: Which Control/Component Can Load Images In Cells
« Reply #1 on: October 30, 2024, 05:15:49 am »
Hi
I'd say, off the bat, 'TListView' will do that, but there are others, that can be made to do it as well...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: Which Control/Component Can Load Images In Cells
« Reply #2 on: October 30, 2024, 05:45:44 am »
Yeah, I'm looking for something like this:

Handoko

  • Hero Member
  • *****
  • Posts: 5376
  • My goal: build my own game engine using Lazarus
Re: Which Control/Component Can Load Images In Cells
« Reply #3 on: October 30, 2024, 07:26:34 am »
I don't think there is any ready-made component that has those features. But Lazarus is very powerful, I don't see any problem to get the result you want.

For example, I 'improved' TScrollBox to store texts with features:
- Add, delete, remove, rename
- Icons that appear when mouse pointer is hovering on the line
- Checkbox to allow multiple selections
- Customizable popup

Thaddy

  • Hero Member
  • *****
  • Posts: 16178
  • Censorship about opinions does not belong here.
Re: Which Control/Component Can Load Images In Cells
« Reply #4 on: October 30, 2024, 08:52:54 am »
TDrawGrid....
If I smell bad code it usually is bad code and that includes my own code.

paweld

  • Hero Member
  • *****
  • Posts: 1268
Re: Which Control/Component Can Load Images In Cells
« Reply #5 on: October 30, 2024, 09:35:53 am »
Check out KGrid/KDBGrid from the KControls component package: https://wiki.freepascal.org/KControls
You can also use VirtualStringTree - it's in the standard lazarus installation under the name LazVirtualStringTree.
Best regards / Pozdrawiam
paweld

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11941
  • FPC developer.
Re: Which Control/Component Can Load Images In Cells
« Reply #6 on: October 30, 2024, 10:04:12 am »
I had the same problem long ago (and before Delphi had those components), and used virtual string tree/grid on Delphi.

I happened to try to port that to Lazarus a good month ago, and I noticed that the tcheckbox behaviour of Lazarus is different than Delphi and put it on ice for now. (e.g. lazarus has an onchange and Delphi not). Now I know that back then I had trouble getting Delphi to work too, so this is not 100% Lazarus fault,  it is a convoluted and sensitive problem with multiple levels of event (grid+ components)


AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: Which Control/Component Can Load Images In Cells
« Reply #7 on: October 30, 2024, 03:21:52 pm »
This looks like a very nice little example. So, what's the concept behind achieving this? Thanks.

I don't think there is any ready-made component that has those features. But Lazarus is very powerful, I don't see any problem to get the result you want.

For example, I 'improved' TScrollBox to store texts with features:
- Add, delete, remove, rename
- Icons that appear when mouse pointer is hovering on the line
- Checkbox to allow multiple selections
- Customizable popup

Handoko

  • Hero Member
  • *****
  • Posts: 5376
  • My goal: build my own game engine using Lazarus
Re: Which Control/Component Can Load Images In Cells
« Reply #8 on: October 30, 2024, 05:25:14 pm »
OOP is the key in this case.

I'm not saying Object Oriented Programming is the 'wonder drug' for solving many problems in programming. Actually, I now try to reduce my OOP usage and use more the traditional procedural approach. OOP is a double-edge sword, I started to see the disadvantages of using OOP. But OOP can be a very good solution in programming if you use it wisely. And Lazarus/Pascal has good support for OOP approach.

Actually I am not a programmer, I am a freelance web/graphics designer. All my work results need to be looking good. When I write programs, I want the user interface to looks good too. Lazarus has plenty of visual components, but I often need to customize them to get the visual result I want. Most or maybe all of Lazarus' visual components are written using OOP approach. So if you are good in OOP, it will be easy for you to 'extend' the components to reach the result you need.

That is not hard. But you really need to have the knowledge about it. I found out that most of Lazarus' components are well written that allow you to improve, subclass, customize its appearance easily. Not happy with their default appearances,  I 'played' and added a lot of visual features in TOpenGLControl, TStringGrid, TPageControl, TForm, TBitmap, etc.

The screenshot/video I showed you, actually is a component that consists of 3 classes:
- TIBToolBar
- TIBItem   <--- this is the main component, subclassed from TScrollBox
- TIBItemBox

The whole source code has 1110 lines of code. If you curious, here I can show the declaration part of the classes:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   TIBToolBar     = class;
  4.   TIBItem        = class;
  5.   TIBItemBox     = class;
  6.   TIBToolClicked = (itNone, itCheckBox, itArrowUp, itArrowDown);
  7.  
  8.   { TIBToolItem }
  9.  
  10.   TIBToolItem = class
  11.   private
  12.     FCanvas:  TCanvas;
  13.     FChecked: Boolean;
  14.     FIndex:   Integer;
  15.     FToolBar: TIBToolBar;
  16.     FVisible: Boolean;
  17.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; virtual;
  18.     procedure ClickShift(const aParent: TScrollBox); virtual;
  19.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); virtual;
  20.     procedure LineRel(const X, Y: LongInt);
  21.   public
  22.     constructor Create; virtual;
  23.     procedure DrawToolItem(const aBackgroundColor: TColor; const X: Integer);
  24.     function Width: Integer; virtual;
  25.   end;
  26.  
  27.   { TIBToolCheckBox }
  28.  
  29.   TIBToolCheckBox = class(TIBToolItem)
  30.   private
  31.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; override;
  32.     procedure ClickShift(const aParent: TScrollBox); override;
  33.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); override;
  34.   public
  35.     function Width: Integer; override;
  36.   end;
  37.  
  38.   { TIBToolArrowUp }
  39.  
  40.   TIBToolArrowUp = class(TIBToolItem)
  41.   private
  42.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; override;
  43.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); override;
  44.   public
  45.     constructor Create; override;
  46.     function Width: Integer; override;
  47.   end;
  48.  
  49.   { TIBToolArrowDown }
  50.  
  51.   TIBToolArrowDown = class(TIBToolItem)
  52.   private
  53.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; override;
  54.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); override;
  55.   public
  56.     constructor Create; override;
  57.     function Width: Integer; override;
  58.   end;
  59.  
  60.   { TIBToolBar }
  61.  
  62.   TIBToolBar = class(TFPObjectList)
  63.   private
  64.     FParent: TIBItem;
  65.     FPosX:   Integer;
  66.   public
  67.     constructor Create(const aParent: TIBItem; const X: Integer); overload;
  68.     procedure Add(const aToolItem: TIBToolItem);
  69.     procedure DrawToolBar(const aBackgroundColor: TColor; const MouseX: Integer);
  70.     procedure ShowTool(const anIndex: Integer; const aStatus: Boolean);
  71.   end;
  72.  
  73.   { TIBItem }
  74.  
  75.   TIBItem = class(TScrollBox)
  76.   const
  77.     FLeft = 70;
  78.   private
  79.     FColorHighLighted:   TColor;
  80.     FColorNormal:        TColor;
  81.     FContent:            shortstring unimplemented;
  82.     FDoubleClickTesting: Boolean;
  83.     FLastClick:          TDateTime;
  84.     FList:               TIBItemBox; // Parent's list
  85.     FToolBar:            TIBToolBar;
  86.     procedure DrawContent; virtual;
  87.     function IsMouseHovering: Boolean;
  88.     function IsMouseHoverToolItem(const anIndex, MouseX: Integer): Boolean;
  89.     function ItemHeight: Integer; virtual;
  90.     procedure EventAddClick(Sender: TObject);
  91.     procedure EventClick(Sender: TObject);
  92.     procedure EventDeleteClick(Sender: TObject);
  93.     procedure EventDblClick(Sender: TObject);
  94.     procedure EventEditClick(Sender: TObject);
  95.     procedure EventMouseEnter(Sender: TObject);
  96.     procedure EventMouseLeave(Sender: TObject);
  97.     procedure EventMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  98.   public
  99.     constructor Create; overload;
  100.     constructor Create(aOwner: TComponent; const S: string = '');
  101.     procedure Paint; override;
  102.     property Data: shortstring read FContent write FContent;
  103.   end;
  104.  
  105.   { TIBItemEmpty }
  106.  
  107.   TIBItemEmpty = class(TIBItem) // Used to pass @TIBItemBox to ItemBoxOf
  108.   public
  109.     constructor Create(aOwner: TComponent); override;
  110.   end;
  111.  
  112.   { TIBItemBox }
  113.  
  114.   TIBItemBoxEventEnum = (ieToolUp, ieToolDown, ieEdit, ieInsert,
  115.     ieAdd, ieDelete, ieDisconnect);
  116.   TIBItemBoxEvent = procedure(ItemBox: TIBItemBox; Index1, Index2: Integer;
  117.     Event: TIBItemBoxEventEnum) of object;
  118.  
  119.   TIBItemBox = class(TFPObjectList)
  120.   private
  121.     FHovering:        Integer;
  122.     FEvent:           TIBItemBoxEvent;
  123.     FMenuCaption:     array[1..10] of string;
  124.     FMenuEvent:       array[1..10] of TNotifyEvent;
  125.     FMenuCount:       Integer;
  126.     FScrollBox:       TScrollBox;
  127.     FTimerDelete:     TTimer; // Prevent deleting while manipulating item
  128.     FTimerDisconnect: TTimer;
  129.     procedure EventAddClick(Sender: TObject);
  130.     procedure EventMouseDown(Sender: TObject; Button: TMouseButton;
  131.       Shift: TShiftState; X, Y: Integer);
  132.     procedure EventResize(Sender: TObject);
  133.     procedure EventTimerDelete(Sender: TObject);
  134.     procedure EventTimerDisconnect(Sender: TObject);
  135.   public
  136.     constructor Create(const aScrollBox: TScrollBox);
  137.     procedure Add(const anItem: TIBItem);
  138.     procedure CheckedAdd;
  139.     procedure CheckedDelete;
  140.     function CheckedFirst: Integer;
  141.     function CheckedLast: Integer;
  142.     function Disconnect: Boolean;
  143.     function Hovering: Integer;
  144.     function isEmpty: Boolean;
  145.     procedure Migrate(const aSource: TIBItemBox; const anIndexFrom, anIndexTo: Integer);
  146.     function GetScrollBox: TScrollBox;
  147.     procedure Rename(const S: string);
  148.     procedure SetEventResponse(const anEvent: TIBItemBoxEvent);
  149.     procedure SetMenu(const aCaption: string; const anEvent: TNotifyEvent);
  150.   end;

When I managed to make TItemBox to work correctly, I was very happy about it. It now could have addable and customizable icons, color highlight when mouse hovering, and many cool features I wanted. But I abandoned the code. As I said, OOP has its own disadvantages. When the code grows bigger to a certain point, it will become too hard to maintain if you didn't plan it properly at the very beginning.



You are new in Lazarus. I understand you have doubt about what can be done using Lazarus. I can sure to tell you, Lazarus is very powerful. Most of the components can be easily subclassed and improved if you know how to do it. And the Pascal language itself, is not perfect, but very good.
« Last Edit: October 30, 2024, 05:46:25 pm by Handoko »

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: Which Control/Component Can Load Images In Cells
« Reply #9 on: October 30, 2024, 08:26:55 pm »
I'm looking for something that can do what Delphi is doing in their grids and listviews. Can Lazarus do this as well? If so, which control should I use to load small image icons?
This reads as if you are looking for a "super grid" which contains "all" features you can think of... Is that really necessary? The higher your requirements the smaller the chance that you will find a working existing solution somewhere, and vice versa. For example, when the grid in your "dbgrid2.jpg" screenshot, is enough then you can do everything in the TDrawGrid which comes with Lazarus - no special component needed. You'll have to do some programming, though... See attachment

Thaddy

  • Hero Member
  • *****
  • Posts: 16178
  • Censorship about opinions does not belong here.
Re: Which Control/Component Can Load Images In Cells
« Reply #10 on: October 30, 2024, 08:34:52 pm »
WTF is wrong with TDrawGrid? Is somebody looking for a more complex way? >:D >:D
If I smell bad code it usually is bad code and that includes my own code.

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: Which Control/Component Can Load Images In Cells
« Reply #11 on: October 30, 2024, 09:01:35 pm »
Wow! Thank you for your efforts! I will definitely consider using this language and these frameworks.
Also, what about in terms of cross-platform compatibility? How hard would it be to get a tool you built, or say, a TDrawGrid to become cross-compatible with an Android, iOS, MAC, Linux, etc.? Is it truly a "code once, deploy anywhere" or do you have to jump through multiple hoops difficult to fit through? Thanks again!


OOP is the key in this case.

I'm not saying Object Oriented Programming is the 'wonder drug' for solving many problems in programming. Actually, I now try to reduce my OOP usage and use more the traditional procedural approach. OOP is a double-edge sword, I started to see the disadvantages of using OOP. But OOP can be a very good solution in programming if you use it wisely. And Lazarus/Pascal has good support for OOP approach.

Actually I am not a programmer, I am a freelance web/graphics designer. All my work results need to be looking good. When I write programs, I want the user interface to looks good too. Lazarus has plenty of visual components, but I often need to customize them to get the visual result I want. Most or maybe all of Lazarus' visual components are written using OOP approach. So if you are good in OOP, it will be easy for you to 'extend' the components to reach the result you need.

That is not hard. But you really need to have the knowledge about it. I found out that most of Lazarus' components are well written that allow you to improve, subclass, customize its appearance easily. Not happy with their default appearances,  I 'played' and added a lot of visual features in TOpenGLControl, TStringGrid, TPageControl, TForm, TBitmap, etc.

The screenshot/video I showed you, actually is a component that consists of 3 classes:
- TIBToolBar
- TIBItem   <--- this is the main component, subclassed from TScrollBox
- TIBItemBox

The whole source code has 1110 lines of code. If you curious, here I can show the declaration part of the classes:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   TIBToolBar     = class;
  4.   TIBItem        = class;
  5.   TIBItemBox     = class;
  6.   TIBToolClicked = (itNone, itCheckBox, itArrowUp, itArrowDown);
  7.  
  8.   { TIBToolItem }
  9.  
  10.   TIBToolItem = class
  11.   private
  12.     FCanvas:  TCanvas;
  13.     FChecked: Boolean;
  14.     FIndex:   Integer;
  15.     FToolBar: TIBToolBar;
  16.     FVisible: Boolean;
  17.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; virtual;
  18.     procedure ClickShift(const aParent: TScrollBox); virtual;
  19.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); virtual;
  20.     procedure LineRel(const X, Y: LongInt);
  21.   public
  22.     constructor Create; virtual;
  23.     procedure DrawToolItem(const aBackgroundColor: TColor; const X: Integer);
  24.     function Width: Integer; virtual;
  25.   end;
  26.  
  27.   { TIBToolCheckBox }
  28.  
  29.   TIBToolCheckBox = class(TIBToolItem)
  30.   private
  31.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; override;
  32.     procedure ClickShift(const aParent: TScrollBox); override;
  33.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); override;
  34.   public
  35.     function Width: Integer; override;
  36.   end;
  37.  
  38.   { TIBToolArrowUp }
  39.  
  40.   TIBToolArrowUp = class(TIBToolItem)
  41.   private
  42.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; override;
  43.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); override;
  44.   public
  45.     constructor Create; override;
  46.     function Width: Integer; override;
  47.   end;
  48.  
  49.   { TIBToolArrowDown }
  50.  
  51.   TIBToolArrowDown = class(TIBToolItem)
  52.   private
  53.     function ClickNormal(const aParent: TScrollBox): TIBToolClicked; override;
  54.     procedure DoDraw(const aBackgroundColor: TColor; const X: Integer); override;
  55.   public
  56.     constructor Create; override;
  57.     function Width: Integer; override;
  58.   end;
  59.  
  60.   { TIBToolBar }
  61.  
  62.   TIBToolBar = class(TFPObjectList)
  63.   private
  64.     FParent: TIBItem;
  65.     FPosX:   Integer;
  66.   public
  67.     constructor Create(const aParent: TIBItem; const X: Integer); overload;
  68.     procedure Add(const aToolItem: TIBToolItem);
  69.     procedure DrawToolBar(const aBackgroundColor: TColor; const MouseX: Integer);
  70.     procedure ShowTool(const anIndex: Integer; const aStatus: Boolean);
  71.   end;
  72.  
  73.   { TIBItem }
  74.  
  75.   TIBItem = class(TScrollBox)
  76.   const
  77.     FLeft = 70;
  78.   private
  79.     FColorHighLighted:   TColor;
  80.     FColorNormal:        TColor;
  81.     FContent:            shortstring unimplemented;
  82.     FDoubleClickTesting: Boolean;
  83.     FLastClick:          TDateTime;
  84.     FList:               TIBItemBox; // Parent's list
  85.     FToolBar:            TIBToolBar;
  86.     procedure DrawContent; virtual;
  87.     function IsMouseHovering: Boolean;
  88.     function IsMouseHoverToolItem(const anIndex, MouseX: Integer): Boolean;
  89.     function ItemHeight: Integer; virtual;
  90.     procedure EventAddClick(Sender: TObject);
  91.     procedure EventClick(Sender: TObject);
  92.     procedure EventDeleteClick(Sender: TObject);
  93.     procedure EventDblClick(Sender: TObject);
  94.     procedure EventEditClick(Sender: TObject);
  95.     procedure EventMouseEnter(Sender: TObject);
  96.     procedure EventMouseLeave(Sender: TObject);
  97.     procedure EventMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  98.   public
  99.     constructor Create; overload;
  100.     constructor Create(aOwner: TComponent; const S: string = '');
  101.     procedure Paint; override;
  102.     property Data: shortstring read FContent write FContent;
  103.   end;
  104.  
  105.   { TIBItemEmpty }
  106.  
  107.   TIBItemEmpty = class(TIBItem) // Used to pass @TIBItemBox to ItemBoxOf
  108.   public
  109.     constructor Create(aOwner: TComponent); override;
  110.   end;
  111.  
  112.   { TIBItemBox }
  113.  
  114.   TIBItemBoxEventEnum = (ieToolUp, ieToolDown, ieEdit, ieInsert,
  115.     ieAdd, ieDelete, ieDisconnect);
  116.   TIBItemBoxEvent = procedure(ItemBox: TIBItemBox; Index1, Index2: Integer;
  117.     Event: TIBItemBoxEventEnum) of object;
  118.  
  119.   TIBItemBox = class(TFPObjectList)
  120.   private
  121.     FHovering:        Integer;
  122.     FEvent:           TIBItemBoxEvent;
  123.     FMenuCaption:     array[1..10] of string;
  124.     FMenuEvent:       array[1..10] of TNotifyEvent;
  125.     FMenuCount:       Integer;
  126.     FScrollBox:       TScrollBox;
  127.     FTimerDelete:     TTimer; // Prevent deleting while manipulating item
  128.     FTimerDisconnect: TTimer;
  129.     procedure EventAddClick(Sender: TObject);
  130.     procedure EventMouseDown(Sender: TObject; Button: TMouseButton;
  131.       Shift: TShiftState; X, Y: Integer);
  132.     procedure EventResize(Sender: TObject);
  133.     procedure EventTimerDelete(Sender: TObject);
  134.     procedure EventTimerDisconnect(Sender: TObject);
  135.   public
  136.     constructor Create(const aScrollBox: TScrollBox);
  137.     procedure Add(const anItem: TIBItem);
  138.     procedure CheckedAdd;
  139.     procedure CheckedDelete;
  140.     function CheckedFirst: Integer;
  141.     function CheckedLast: Integer;
  142.     function Disconnect: Boolean;
  143.     function Hovering: Integer;
  144.     function isEmpty: Boolean;
  145.     procedure Migrate(const aSource: TIBItemBox; const anIndexFrom, anIndexTo: Integer);
  146.     function GetScrollBox: TScrollBox;
  147.     procedure Rename(const S: string);
  148.     procedure SetEventResponse(const anEvent: TIBItemBoxEvent);
  149.     procedure SetMenu(const aCaption: string; const anEvent: TNotifyEvent);
  150.   end;

When I managed to make TItemBox to work correctly, I was very happy about it. It now could have addable and customizable icons, color highlight when mouse hovering, and many cool features I wanted. But I abandoned the code. As I said, OOP has its own disadvantages. When the code grows bigger to a certain point, it will become too hard to maintain if you didn't plan it properly at the very beginning.



You are new in Lazarus. I understand you have doubt about what can be done using Lazarus. I can sure to tell you, Lazarus is very powerful. Most of the components can be easily subclassed and improved if you know how to do it. And the Pascal language itself, is not perfect, but very good.
« Last Edit: October 30, 2024, 09:03:34 pm by AaronCatolico1 »

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: Which Control/Component Can Load Images In Cells
« Reply #12 on: October 30, 2024, 09:58:22 pm »
Wow! That looks really nice! Very impressive! I appreciate this. This looks like something im interested in. Please provide me with the sourcecode so i can study over it. Thanks again.


I'm looking for something that can do what Delphi is doing in their grids and listviews. Can Lazarus do this as well? If so, which control should I use to load small image icons?
This reads as if you are looking for a "super grid" which contains "all" features you can think of... Is that really necessary? The higher your requirements the smaller the chance that you will find a working existing solution somewhere, and vice versa. For example, when the grid in your "dbgrid2.jpg" screenshot, is enough then you can do everything in the TDrawGrid which comes with Lazarus - no special component needed. You'll have to do some programming, though... See attachment

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: Which Control/Component Can Load Images In Cells
« Reply #13 on: October 30, 2024, 11:56:19 pm »
Please provide me with the sourcecode so i can study over it. Thanks again.
The source code (including lots of comments) is in the attachment of my post.
« Last Edit: October 31, 2024, 12:28:21 am by wp »

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: Which Control/Component Can Load Images In Cells
« Reply #14 on: October 31, 2024, 05:10:24 am »
I didn't realize that you had it attached. I believe originally it was only showing the image.
So, where is the official documentation of how to populate this TDrawGrid or where did you learn it from? I'd like to review this documentation.

 

TinyPortal © 2005-2018