Mike Torrettinni 198 Posted February 11, 2019 I'm looking for some advice how to connect controls and class, specifically at this moment is Virtual Treeview (TVirtualStringTree - VST). I have a class TABCFileParser that parses text files and holds all the data. I have a method that returns Strings when I want to display some data in TMemo. All good, simple. Now I need to connect the data with VST, and I will use probably a lot of methods (OnGetText, OnGetIconImage, OnPaintText... ). Most of them will be based on data from TABCFileParser class. Up until now, I had no problem because all data was in global variables ( no classes), I just accessed them in each VST method directly. Works good, but once you have a lot of VTSs in Main Form, it gets cluttered with all the code. Then I 'evolved' this into enclosing data into a unit (not a class, yet) and 'exposed' all needed methods like: DataGetText, DataGetIcon... and in VST's methods I call these methods, so the VST's OnGetText has a single line, a call to this DataGetText. This is better, since Main Form unit doesn't get cluttered and I can keep all Data related methods in 1 unit. I was warned not to mix UI elements with data classes. So my idea to just expose ABCGetText, ABCPaintText.. and call them in VST's OnGetText with FABCFileParser.ABCGetText().. is not OK. So, what would be sensible approach to get data from class to VST? I was thinking of a 'bridge' class that would pair up TABCFileParser and VST by pulling data from the ABC class and assign methods to VST. Any other suggestions? Thanks, I appreciate any kind of suggestion! Share this post Link to post
joachimd 4 Posted February 12, 2019 For such purposes I've written my own component, derived from TWinControl. It contains a TVirtualStringTree and implements all methods required to run it. For the outside world, I've implemented my own methods and properties. Within the implementation part of that unit, I've defined a Node record being used for all data handling. This record contains an implementation of a an interface: interface type TAppListViewer = class(TWinControl) //... implementation type PSuperNode = ^TSuperNode; TSuperNode = record obj: IAppListItem; end; //... IAppListItem iss defined in another unit: IAppListItem=interface ['{CA2770B8-8A4B-4F52-AE6F-5F55E45C6014}'] procedure SetID(const aValue: TIDType); function GetID(): TIDType; property ID:TIDType read GetID write SetID; procedure SetCaption(const aValue: string); function GetCaption(): string; property Caption:string read GetCaption write SetCaption; procedure SetParent(const aValue: IAppListItem); function GetParent(): IAppListItem; property Parent:IAppListItem read GetParent write SetParent; function GetChildren(): TAppList; property Children:TAppList read GetChildren; procedure AddChild(aChild: IAppListItem); procedure RemoveChild(aChild: IAppListItem); //... end; My component has a property getting one such an item (the root) and all children of it. Setting it will cause a rebuilt of the tree. property AppList:IAppListItem read FAppList write SetAppList; HTH Joachim 1 Share this post Link to post
Mike Torrettinni 198 Posted February 12, 2019 @joachimd Interesting, own control would be good with all the bells and whistles, instead of constantly applying same changes to new controls... would you mind sharing OnGetText/GetText method details? do you pull full rows or column item one by one from from, or have access to full data structure? Share this post Link to post
joachimd 4 Posted February 13, 2019 (edited) sure ... it's no big deal 😉 I only have two columns for this viewer: First is the caption, second the ID (for Debug purposes, usually not displayed). procedure TAppListViewer.treeviewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); var data: PSuperNode; begin try data := treeview.GetNodeData(Node); case Column of 0: CellText := data.obj.Caption; 1: CellText := ID2String(data.obj.ID); //btw: it's TGUID, but I leave it open for other datatypes end; except end; end; BTW: You can also define a function in your 'IAppListItem" interface to get the string your need (e.g. function GetText(column: integer): string) Edited February 13, 2019 by joachimd 1 Share this post Link to post
Mike Torrettinni 198 Posted February 13, 2019 Thank you! I think I got it now. I will have a class that connects control and data, so I can attach any VST control to it, or connect any data to the control. This way will avoid cluttering the Main from with all the code. So, when you use your control on the form, you don't have any code in the control events, right? All is defined in this interface, so if you want to see how what OnGetText contains, you have to open the unit with this interface, right? Share this post Link to post
joachimd 4 Posted February 13, 2019 Correct. My component only has a few (required) Events and Properties, but VST events are not mapped to the outside. Share this post Link to post
Mike Torrettinni 198 Posted February 13, 2019 And this doesn't annoy you, that you can't just double click event and see the code (the RAD thing)? 🙂 Share this post Link to post
joachimd 4 Posted February 14, 2019 no, because my events are ways simpler 😉 btw: I use very seldom the "RAD things" ... setting all required properties and event handlers in code looks awful at first, but IMHO it results in a clearer structure of your code. I'd love to see Delphi creating code instead of DFM files (like C# does). That would make things even more simple. 1 Share this post Link to post