Mike Torrettinni
Members-
Content Count
1509 -
Joined
-
Last visited
-
Days Won
3
Everything posted by Mike Torrettinni
-
User settings - split logic and UI
Mike Torrettinni posted a topic in Algorithms, Data Structures and Class Design
Hi I'm slowly preparing my application to run without UI, as cmd tool. So I started with User Settings. Right now I read and write user settings directly from Registry to UI (checkboxes) and back, Logic accesses UI to decide on workflow. Now I'm thinking like this: - Setup GlobalSettings record which will hold all user settings - on application start: read settings from Registry and write into GlobalSettings - on application exit (or on user demand - Save button on settings screen) - save settings from GlobalSettings to Registry - when logic needs to read user settings to decide on workflow, it reads directly from GlobalSettings - no more UI access from logic - if application is run with UI, I will have 2 methods to work with UI - UserSettingsToUI and UserSettingsFromUI which will populate UI with settings from GlobalSettings; and when user changes any settings they will be saved into GlobalSettings with UserSettingsFromUI So, the new GlobalSettings record will be the main settings 'engine' and UI will not access Registry directly, anymore. Logic will never access UI anymore, so even if application is run without UI, logic will run ok based on previously saved user settings. Is this the right approach? Thanks! -
User settings - split logic and UI
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Yes, now I have similar design, probably more basic - no RTTI. I have Store/Load Settings To/From Registry and for each Form I have LoadFromSettings(Form) in OnCreate and StoreToSettings(Form/nil = allForms) on Application close. Some reports also require on demand access, saving settings. It was a lot of work, a lot of trial and error cases, but now it works great! Of course all the suggestinos here were very helpful in shaping the solution. -
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!
-
How to get data from class to TVirtualStringTree?
Mike Torrettinni replied to Mike Torrettinni's topic in VCL
And this doesn't annoy you, that you can't just double click event and see the code (the RAD thing)? 🙂 -
How to get data from class to TVirtualStringTree?
Mike Torrettinni replied to Mike Torrettinni's topic in VCL
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? -
How to get data from class to TVirtualStringTree?
Mike Torrettinni replied to Mike Torrettinni's topic in VCL
@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? -
How to switch condition position?
Mike Torrettinni posted a topic in Algorithms, Data Structures and Class Design
Is it possible to switch the condition to the end: from this: If (condition) Then Result := True; into something like this: Result := True if (condition); Or similar variation, where result is shown first. I know that Case works like that, but I need it to work on string values. When visually looking at the statement, sometimes the Result value has a 'priority' over condition - my personal preference. -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Thank you for the example! I'm not really new to Delphi, but never grew out of the beginners's level of thinking, I guess... you can find a thread here me questioning about why should I use classes at all 🙂 -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
While I appreciate all the engagement in this thread, the whole question was just a simple 'is it possible' idea. A little more explanation when I got this idea (please consider my beginners level of Delphi experience): So, I have a function that returns default value of a property and since I was just building up this feature, I wanted to know what the defaults are right away. So, this is rough example: if MatchStr('PropertyName', ['Prop1', 'Prop2', 'Prop3', 'Prop4', 'Prop5', 'Prop6', 'Prop7', 'Prop8', 'Prop9', 'Prop10' ]) then Result := 'N' else if (MatchStr('PropertyName', ['PropertyA', 'PropertyB', 'PropertyC', 'PropertyD', 'PropertyE', 'PropertyF', 'PropertyG', 'PropertyH' 'PropertyI', 'PropertyJ', 'PropertyK', 'PropertyL', 'PropertyM', 'PropertyN', 'PropertyO', 'PropertyP', 'PropertyQ'...]) then Result := 'DefaultABC' else if PropertyName = 'CustomProp' Result := 'X' ... and since I was adding new property names and value, I always wanted to know exactly what is already there and what the names and values are, and a Result was an important information, so I was thinking it would be so cool to have it reversed: Result := 'N' if MatchStr('PropertyName', ['Prop1', 'Prop2', 'Prop3', 'Prop4', 'Prop5', 'Prop6', 'Prop7', 'Prop8', 'Prop9', 'Prop10' ]) else Result := 'DefaultABC' if MatchStr('PropertyName', ['PropertyA', 'PropertyB', 'PropertyC', 'PropertyD', 'PropertyE', 'PropertyF', 'PropertyG', 'PropertyH' 'PropertyI', 'PropertyJ', 'PropertyK', 'PropertyL', 'PropertyM', 'PropertyN', 'PropertyO', 'PropertyP', 'PropertyQ'...]) else Result := 'X' if (PropertyName = 'CustomProp') .... So, it's more visual thing, where I first see possible default values and then which property names resolve to it. I know I can do this 10s of other way with lookup table, consts... but this all means the default values and property names are not together, and I would need to jump back and forth to get the right information. -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
IfThen's are awesome, I use them a lot, but it's not usable for this case, I need Result to be very clear at the beginning. -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Thank you, but was trying to avoid using methods, it kind of defeats the purpose of simple If statement. -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Yes, no matter what i tried, it didn't compile. Was hoping there is simple solution, missing from help. No luck. -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Thanks. I just had an idea if this is possible for one of my statement, where it's a long condition and wanted to reverse so I can see result first. -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Well, I can't see anything helpful for my case. I'm looking here: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Declarations_and_Statements_(Delphi) -
How to switch condition position?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I didn't provide good example, I'm trying to work on statement like this, working on strings: if Property = 'A' then Result := 'N'; so looking for in idea how to have something like this: Result := 'N' if/when (Property = 'A'); -
Should I create subclass for User interface interaction?
Mike Torrettinni posted a topic in Algorithms, Data Structures and Class Design
So, I have my first attempt at designing a class and I was wondering if I need to subclass to separate User interface methods and CLI (cmd) methods (when project is run without main form). So, the class is a file parser (custom file structure, similar to XML) and I need it to ParseFile and then either to show parsed data on Form control (when run with UI) or export to file (when run in CLI mode). Here is the very early version of the class design: unit uParseABCFile; interface uses System.Classes, Vcl.StdCtrls, Vcl.Dialogs; type TABCFileParser = class private type TABCStructure = record NodeName: string; ListOfArguments: TStringList; end; var FABCFileName: string; FABCStructure: TArray<TABCStructure>; // User interface Controls FMemo: TMemo; procedure MemoDblClick(Sender: TObject); public constructor Create; property ABCFileName: string read FABCFileName write FABCFileName; procedure ParseFile; // Methods for User Interface procedure ABCStructureToMemo(aMemo: TMemo); // Methods for non-UI mode procedure ABCStructureToFile(const aFileName: string); end; // Subclasses ?? // TABCFileParser_UserInterface = class(TABCFileParser); // TABCFileParser_CLI = class(TABCFileParser); implementation constructor TABCFileParser.Create; begin // add something, if needed in the future end; procedure TABCFileParser.ParseFile; begin // Parse ABC File - FABCFileName // demo data SetLength(FABCStructure, 1); FABCStructure[0].NodeName := 'ABC Node 1'; FABCStructure[0].ListOfArguments := TStringList.Create; FABCStructure[0].ListOfArguments.AddStrings(['Test','ID', 'Description', 'ABCVersion', 'ABCType']); end; procedure TABCFileParser.ABCStructureToMemo(aMemo: TMemo); begin if aMemo = nil then Exit; aMemo.Clear; aMemo.Lines.AddStrings(FABCStructure[0].ListOfArguments); // Assign aMemo to local FMemo FMemo := aMemo; FMemo.OnDblClick := MemoDblClick; end; procedure TABCFileParser.MemoDblClick(Sender: TObject); begin ShowMessage('from Class : Memo clicked = ' + TMemo(Sender).Name); // OR ? ShowMessage('from Class : local Memo clicked = ' + FMemo.Name); end; procedure TABCFileParser.ABCStructureToFile(const aFileName: string); begin // Save ABC Structure to File // ... end; end. And here is used on Main form: unit uMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uParseABCFile; type TfrmMain = class(TForm) Label1: TLabel; Edit1: TEdit; Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } FABCStructure: TABCFileParser; public { Public declarations } end; var frmMain: TfrmMain; implementation {$R *.dfm} procedure TfrmMain.Button1Click(Sender: TObject); begin FABCStructure := TABCFileParser.Create; FABCStructure.ABCFileName := '...'; FABCStructure.ParseFile; FABCStructure.ABCStructureToMemo(Memo1); end; end. When project is in CLI mode, this is example of how I will use the class: procedure ParseABCFileAndExportToFile(const aABCFileName, aExportFileName: string); var vABCParser: TABCFileParser; begin vABCParser := TABCFileParser.Create; try vABCParser.ABCFileName := aABCFileName; vABCParser.ParseFile; vABCParser.ABCStructureToFile(aExportFileName); finally vABCParser.Free; end; end; So, the main question: 1. There will be more controls (probably multiple Virtual Treeviews for different views of data) interacting with this class, and also more export options for CLI mode, is it better to split (subclass) into a class that will interact with user controls and class that will not, will just work in CLI mode? And 2 small questions: 2. I assign MemoDblClick to a control, so is it better to use Sender argument or local FMemo variable that is assigned to this control? Or it doesn't matter in this case? 3. Since FABCStructure: TABCFileParser; is private variable of Main form, it doesn't need manual Free-ing, since it will be freed (destroyed) when form is destroyed, right? Thank you for any feedback! -
Should I create subclass for User interface interaction?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
OK, thanks for all the time and effort helping me! -
Should my record be a class instead?
Mike Torrettinni posted a topic in Algorithms, Data Structures and Class Design
By removing global variables (and other definitions - 100s of them), I also started removing global type definitions, because I believe this also messes up Delphi's Error insight and Code completion (too many global vars and type definitions to handle properly). So, I read about records vs classes, and I think my global records are used properly. I want to show the structure of example of unit with a global record + local methods, and if anybody has any comments on 'sanity' of such cases, please do help me improve it: So, this is the usual way how I structure a unit with global record: To 'expose' only 1 or as minimum as possible globals: - main record type : TGlobalRec - and 1 global variable : GlobalRec - and as minimum global exposed procedures as possible: PrepareGlobalRec It starts with simple main TGlobalRec, and unit Test; interface type // definition used only by TGlobalRec TValue = record ValName : string; ValInProject : boolean; end; // Global record holder TGlobalRec = record Id : Integer; RecName : string; Values : TArray<TValue>; end; // only public method procedure PrepareGlobalRec; var // global variable GlobalRec: TGlobalRec; implementation procedure PrepareGlobalRec; begin // prepare GlobalRec data end; end. Then I add local types, vars and procedure that are only used for dealing with GlobalRec data: unit Test1; interface type // definition used only by TGlobalRec TValue = record ValName : string; ValInProject : boolean; end; // Global record TGlobalRec = record Id : Integer; RecName : string; Values : TArray<TValue>; end; // only public method procedure PrepareGlobalRec; var // global variable GlobalRec1: TGlobalRec; implementation // local types type TLocalRec = record LocalRecStr: string; // ... end; // Local methods procedure LocalProc1; forward; procedure LocalProc2; forward; // local vars var LocalStrVar : string; LocalRecVar : TLocalRec; procedure PrepareGlobalRec; begin // prepare GlobalRec data LocalStrVar := 'local test'; LocalRecVar.LocalRecStr := 'test'; LocalProc1; LocalProc2; end; procedure LocalProc1; begin // ... end; procedure LocalProc2; begin // ... end; end. And since records allow Private definitions, I move all local definitions into Private section of a record, and also a public procedure: unit Test2; interface type // definition used only by TGlobalRec TValue = record ValName : string; ValInProject : boolean; end; // Global record TGlobalRec = record Id : Integer; RecName : string; Values : TArray<TValue>; // only public method procedure PrepareGlobalRec; private // ALL PREVIOUS LOCAL DEFINITIONS ARE NOW IN PRIVATE SECTION OF RECORD type TLocalRec = record LocalRecStr: string; // ... end; procedure LocalProc1; procedure LocalProc2; var LocalStrVar : string; LocalRecVar : TLocalRec; end; var // global variable GlobalRec2: TGlobalRec; implementation procedure TGlobalRec.PrepareGlobalRec; begin // prepare GlobalRec data LocalStrVar := 'local test'; LocalRecVar.LocalRecStr := 'test'; LocalProc1; LocalProc2; end; procedure TGlobalRec.LocalProc1; begin // ... end; procedure TGlobalRec.LocalProc2; begin // ... end; end. As said above, I like this approach because: - the GlobaRec data is needed to be global and is only 1! (so, no need for classes...) - I don't need to deal with .Create and .Free (class) - I expose only minimum number of elements, so I hope eventually Error insight and Code completion might start working in my projects So, does anybody have any comments or experience that this design should be improved? Is there any benefit to turn this into a class, that my limited experience just can't see, understand? -
Should I create subclass for User interface interaction?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
It's the little things that count, like a little praise I did good 🙂 Thank you! I made changes and added new Create ctor: constructor Create(Level: integer; const Parent, NodeName: string; const Arguments: TArray<TNodeArgument>); overload; I also changed private to strict private in TABCStructureNode, since the other class was able to access all fields directly instead of properties - the Code completion was confusing by allowing me access to FNodeLevel instead of just NodeLevel property: I also added AddNnode overload that calls new ctor, can you confirm this is OK - to use TABCStructureNode.Create in: procedure TABCFileParser.AddNode(Level: integer; const Parent, NodeName: string; const Arguments: TArray<TNodeArgument>); begin FABCStructure := FABCStructure + [TABCStructureNode.Create(Level, Parent, NodeName, Arguments)]; end; As for the TArray vs TList... I just like TArray, as I'm used to it. unit uParseABCFile2; interface uses System.Classes, Vcl.StdCtrls, Vcl.Dialogs; type TNodeArgument = record ArgName : string; ArgValue : string; end; // File structure basic block TABCStructureNode = class strict private FNodeLevel : Integer; FNodeParent : string; FNodeName : string; FArguments : TArray<TNodeArgument>; strict private function GetArgument(Index: integer): TNodeArgument; function GetArgumentCount: integer; function GetArgumentAsString(Index: Integer): string; public constructor Create; overload; constructor Create(Level: integer; const Parent, NodeName: string; const Arguments: TArray<TNodeArgument>); overload; property NodeLevel: integer read FNodeLevel write FNodeLevel; property NodeParent: string read FNodeParent write FNodeParent; property NodeName: string read FNodeName write FNodeName; // Arguments property ArgumentCount: integer read GetArgumentCount; property Arguments[Index: Integer]: TNodeArgument read GetArgument; procedure AddArgument(Argument: TNodeArgument); procedure DeleteArgument(Index: Integer); property ArgumentAsString[Index: Integer]: string read GetArgumentAsString; // ... end; TABCFileParser = class private FABCFileName: string; // File structure FABCStructure: TArray<TABCStructureNode>; public constructor Create; property ABCFileName: string read FABCFileName write FABCFileName; procedure ParseFile; // File structure procedure AddNode(NodeItem: TABCStructureNode); overload; procedure AddNode(Level: integer; const Parent, NodeName: string; const Arguments: TArray<TNodeArgument>); overload; // CORRECT METHOD FOR UI INTERFACE function GetStructureAsString: string; // Methods for non-UI mode procedure ABCStructureToFile(const aFileName: string); end; implementation { TABCStructure } constructor TABCStructureNode.Create; begin // ??? end; constructor TABCStructureNode.Create(Level: integer; const Parent, NodeName: string; const Arguments: TArray<TNodeArgument>); begin FNodeLevel := Level; FNodeParent := Parent; FNodeName := NodeName; FArguments := Arguments; end; function TABCStructureNode.GetArgument(Index: integer): TNodeArgument; begin Result := FArguments[Index]; end; procedure TABCStructureNode.AddArgument(Argument: TNodeArgument); begin FArguments := FArguments + [Argument]; end; procedure TABCStructureNode.DeleteArgument(Index: Integer); begin Delete(FArguments, Index, 1); end; function TABCStructureNode.GetArgumentCount: integer; begin Result := Length(FArguments); end; function TABCStructureNode.GetArgumentAsString(Index: Integer): string; begin Result := FArguments[Index].ArgName + ' = ' + FArguments[Index].ArgValue; end; { TABCFileParser } constructor TABCFileParser.Create; begin // add something, if needed in the future end; procedure TABCFileParser.ParseFile; var vNewItem : TABCStructureNode; vNewArgument1, vNewArgument2: TNodeArgument; vArguments1, vArguments2: TArray<TNodeArgument>; begin // Parse/Read ABC File - FABCFileName // demo data vNewArgument1.ArgName := 'Arg1'; vNewArgument1.ArgValue := 'Value1'; vNewArgument2.ArgName := 'Arg2'; vNewArgument2.ArgValue := 'Value2'; vArguments1 := TArray<TNodeArgument>.Create(vNewArgument1, vNewArgument2); vNewArgument1.ArgName := 'Arg3'; vNewArgument1.ArgValue := 'Value3'; vNewArgument2.ArgName := 'Arg4'; vNewArgument2.ArgValue := 'Value4'; vArguments2 := TArray<TNodeArgument>.Create(vNewArgument1, vNewArgument2); AddNode(0, 'Parent', 'ABC Node 1', vArguments1); AddNode(1, 'ABC Node 1', 'ABC Node 2', vArguments2); end; procedure TABCFileParser.AddNode(NodeItem: TABCStructureNode); begin FABCStructure := FABCStructure + [NodeItem]; end; procedure TABCFileParser.AddNode(Level: integer; const Parent, NodeName: string; const Arguments: TArray<TNodeArgument>); begin FABCStructure := FABCStructure + [TABCStructureNode.Create(Level, Parent, NodeName, Arguments)]; end; procedure TABCFileParser.ABCStructureToFile(const aFileName: string); begin // Save ABC Structure to File // ... end; function TABCFileParser.GetStructureAsString: string; var i,j: Integer; begin Result := ''; for i := Low(FABCStructure) to High(FABCStructure) do begin Result := Result + FABCStructure[i].NodeName; Result := Result + ' Arguments: '; for j := 0 to FABCStructure[i].ArgumentCount - 1 do Result := Result + FABCStructure[i].ArgumentAsString[j] + '; '; Result := Result + sLineBreak; end; end; end. -
Should I create subclass for User interface interaction?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Here is a little changed structure, because each item has a little more info than just Name and TStringList, so I changed the structure. I also change to output String for Memo. so, the idea behind this is: TABCStructureNode is how ABC file is structured, like xml node elements. So this is basic item. TABCFileParser is now a parser that holds content of ABC file in FABCStructure: TArray<TABCStructureNode>;. Now I get a structure into Memo with : Memo1.Lines.Text := FABCStructure.GetStructureAsString; where FABCStructure is private variable of Main form. unit uParseABCFile2; interface uses System.Classes, Vcl.StdCtrls, Vcl.Dialogs; type TNodeArgument = record ArgName : string; ArgValue : string; end; // File structure basic block TABCStructureNode = class private FNodeLevel : Integer; FNodeParent : string; FNodeName : string; FArguments : TArray<TNodeArgument>; private function GetArgument(Index: integer): TNodeArgument; function GetArgumentCount: integer; function GetArgumentAsString(Index: Integer): string; public constructor Create; property NodeLevel: integer read FNodeLevel write FNodeLevel; property NodeParent: string read FNodeParent write FNodeParent; property NodeName: string read FNodeName write FNodeName; // Arguments property ArgumentCount: integer read GetArgumentCount; property Arguments[Index: Integer]: TNodeArgument read GetArgument; procedure AddArgument(Argument: TNodeArgument); procedure DeleteArgument(Index: Integer); property ArgumentAsString[Index: Integer]: string read GetArgumentAsString; // ... end; TABCFileParser = class private FABCFileName: string; // File structure FABCStructure: TArray<TABCStructureNode>; public constructor Create; property ABCFileName: string read FABCFileName write FABCFileName; procedure ParseFile; // File structure procedure AddNode(NodeItem: TABCStructureNode); // CORRECT METHOD FOR UI INTERFACE function GetStructureAsString: string; // Methods for non-UI mode procedure ABCStructureToFile(const aFileName: string); end; implementation { TABCStructure } constructor TABCStructureNode.Create; begin // ??? end; function TABCStructureNode.GetArgument(Index: integer): TNodeArgument; begin Result := FArguments[Index]; end; procedure TABCStructureNode.AddArgument(Argument: TNodeArgument); begin FArguments := FArguments + [Argument]; end; procedure TABCStructureNode.DeleteArgument(Index: Integer); begin Delete(FArguments, Index, 1); end; function TABCStructureNode.GetArgumentCount: integer; begin Result := Length(FArguments); end; function TABCStructureNode.GetArgumentAsString(Index: Integer): string; begin Result := FArguments[Index].ArgName + ' ' + FArguments[Index].ArgValue; end; { TABCFileParser } constructor TABCFileParser.Create; begin // add something, if needed in the future end; procedure TABCFileParser.ParseFile; var vNewItem : TABCStructureNode; vNewArgument: TNodeArgument; begin // Parse/Read ABC File - FABCFileName // demo data vNewArgument.ArgName := 'Arg1'; vNewArgument.ArgValue := 'ArgValue'; vNewItem := TABCStructureNode.Create; try vNewItem.NodeLevel := 0; vNewItem.NodeParent := 'Parent'; vNewItem.NodeName := 'ABC Node 1'; vNewItem.AddArgument(vNewArgument); AddNode(vNewItem); finally //vNewItem.Free; - THIS DELETES JUST ADDED ITEM??? end; end; procedure TABCFileParser.AddNode(NodeItem: TABCStructureNode); begin FABCStructure := FABCStructure + [NodeItem]; end; procedure TABCFileParser.ABCStructureToFile(const aFileName: string); begin // Save ABC Structure to File // ... end; function TABCFileParser.GetStructureAsString: string; var i,j: Integer; begin Result := ''; for i := Low(FABCStructure) to High(FABCStructure) do begin Result := FABCStructure[i].NodeName; Result := Result + ' Arguments: '; for j := 0 to FABCStructure[i].GetArgumentCount - 1 do Result := Result + FABCStructure[i].GetArgumentAsString(j); end; end; end. how does this look? -
Should I create subclass for User interface interaction?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
@David Schwartz If I understand correctly, any kind of complex type ( in my case a record with TStringList) should be a class with all Get/Set (Insert, Add, Deleted...) methods? -
Should I create subclass for User interface interaction?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Aha, I thought only the public methods should be Get/Set, and internal class methods don't need to be like this. -
Should my record be a class instead?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
That record is part of a feature (report) that needs to be available with and without Main form, so application can have a user interface or not. It is standalone report, so I set it as global to be able to connect controls' when needed or just being run from global method that runs all needed reports in case project is run without interface. If it was just a subset of another feature, then I can see why it can be non-global record, but it is a feature on it's own with a good number of lines of code and form controls use it's methods, so I think it should be global. Please understand from my point I'm starting from everything is global, now going to have a global record (or class) with all local methods and vars, while before everything was global. Now I have 1 record a few public methods and a lot of local definitions. that hopefully don't mess with Error insight and Code completion in Main form or any other unit. Up until a few days ago I didn't know that Record can have Private definitions, which is one of the reasons for this question... if I move all local definitions from implementation to Record Private section, should it then be a class. No, unless I need a class behavior. Or the other way around, when I completely switch to class based (OOP) principles, this question is not applicable. -
Should my record be a class instead?
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Well, I try to name the methods and arguments as meaningful as possible, also there are comments, so it's kind of hard to really mess it up in what is supposed to be passed as parameter. For example function GetProjectName(aProjId: integer): string; doesn't really need a lot of checking or exception handling. Not sure how different anybody else is doing, but I never had problems with method arguments or treating them any special way, if I need different arguments, I overload methods. -
Splash screen doesn't show icon in taskbar
Mike Torrettinni replied to Mike Torrettinni's topic in VCL
@KryvichThanks, in doesn't show icon in W10 and in W7 doesn't show the taskbar button at all, until main form. This is my first time trying splash screen (my project needs 2.8-3.5s to open main form) on my PC, so probably it takes longer on more basic computers. I did run some other apps, and it is true, as @Uwe Raabe mentioned, couldn't' find an application that has icon in splash scree... Delphi 10.2 doesn't show it. And as it seems is very Windows version specific behavior, I guess I will leave it as no-icon, for now.