Leaderboard
Popular Content
Showing content with the highest reputation on 02/08/19 in Posts
-
How to obtain the value of a field of type TWndMethod via RTTI?
Stefan Glienke replied to Kryvich's topic in RTL and Delphi Object Pascal
It probably is lacking the `()` there which it sometimes needs when invoking a method that returns an invokable type. -
Conditional compilation for various Delphi versions
Remy Lebeau replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Actually, since Delphi 6+, the preferred method is to use $IF with the CompilerVersion and/or RTLVersion constants, instead of using $IFDEF with the VERxxx conditionals. -
What is the fastest way to check if a file exists?
Remy Lebeau replied to dummzeuch's topic in Windows API
Why is GetFileAttributes the way old-timers test file existence? -
Is there already a statistic about the new registrations?
Markus Kinzler replied to sh17's topic in Community Management
-
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?
David Schwartz replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
That looks a LOT better! I'd fill out the constructors. The purpose of a ctor is to initialize the state of an object. When it's a simple item like what you've got, there might be multiple ctors: one would take no arguments and return an empty object, but initialize the contents anyway just to be safe. The other(s) would offer different combinations of parameters to allow you to create and set values in one statement. Instead, you create an empty object that's not initialized, then assign values to it separately. While that's fine, it's extra coding that can be eliminated. Also, you seem addicted to using TArray, even though the way you're using it is more like a TList. You never set the initial size anywhere, which appears to be unbounded. So why not use a TList instead? In ParseFile, you don't need try...finally because you don't want to delete the object you just created b/c it's being added to a list, as your comment suggests. If you delete it, you'll end up with a list full of pointers to freed objects. Consider this instead of that whole block: AddNode( TABCStructureNode.Create( 25, 'parent_of_25', 'contents of node 25' ) ); But, if you stare at that long enough, you start to think, "why not just do this instead?" AddNode( 25, 'parent_of_25', 'contents of node 25' ); where the TABCStructureNode is created implicitly by AddNode -
FYI: Graph showing iOS crashes with recent Delphi versions
ByteJuggler replied to Hans♫'s topic in Cross-platform
Relatedly and somewhat in the same vein I read an article yesterday about AirBnB and why they're now moving off of React native, basically too much churn and too many landmines, even if it works really well when it works. -
Pitfalls of Anonymous methods and capture
Uwe Raabe replied to Lars Fosdal's topic in RTL and Delphi Object Pascal
I imagine what is happening and I assume it to be expected behavior, although I admit one has to know how variable capturing works to get it. It is even documented (Variable Binding Mechanism) There is still a lot of guessing about what is THandlerClass, OnHandle and how AddHandler is defined and what it does with its parameter, so it is difficult to give a detailed analysis. -
Pitfalls of Anonymous methods and capture
David Heffernan replied to Lars Fosdal's topic in RTL and Delphi Object Pascal
If we have no knowledge of the types involved in this code then for sure we can't know what's wrong with it. -
Thanks a lot. I will look and eventually extend your code somewhat. I am really missing the OI expert from Uwe Schuster, that went along similar ideas that you have. So maybe I can come up with a similar solution than Uwe's expert. At least your code is a good starting point, so thanks a lot for sharing.
-
Your TIdHTTP code is all wrong for this kind of POST request. Try something more like this instead: uses ..., IdGlobalProtocols, IdHTTP, IdSSLOpenSSL; procedure TForm3.Button2Click(Sender: TObject); var SoapMsg: string; PostData, ResponseData: TStream; begin // buid up this string however you want (XML library, etc) ... SoapMsg := '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">' + ' <soapenv:Header/>' + ' <soapenv:Body>' + ' <tem:Consulta>' + ' <!--Optional:-->' + ' <tem:expresionImpresa><![CDATA[?re=LSO1306189R5&rr=GACJ940911ASA&tt=4999.99&id=e7df3047-f8de-425d-b469-37abe5b4dabb]]></tem:expresionImpresa>' + ' </tem:Consulta>' + ' </soapenv:Body>' + '</soapenv:Envelope>'; ResponseData := TMemoryStream.Create; try PostData := TStringStream.Create(SoapMsg, TEncoding.UTF8); try IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1; IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoNoProtocolErrorException, hoWantProtocolErrorContent]; IdHTTP1.Request.ContentType := 'text/xml'; IdHTTP1.Request.Charset := 'utf-8'; IdHTTP1.Request.Accept := 'text/xml'; IdHTTP1.Request.CacheControl := 'no-cache'; IdHTTP1.Request.CustomHeaders.Values['SOAPAction'] := 'http://tempuri.org/IConsultaCFDIService/Consulta'; IdHTTP1.Post('https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl', PostData, ResponseData); finally PostData.Free; end; Memo1.Lines.BeginUpdate; try Memo1.Lines.Add(Format('Response Code: %d', [IdHTTP1.ResponseCode])); Memo1.Lines.Add(Format('Response Text: %s', [IdHTTP1.ResponseText])); ResponseData.Position := 0; ReadStringsAsCharset(ResponseData, Memo1.Lines, IdHTTP1.Response.Charset); finally Memo1.Lines.EndUpdate; end; finally ResponseData.Free; end; end;
-
appending to a dynamic array
Remy Lebeau replied to dummzeuch's topic in Algorithms, Data Structures and Class Design
I would probably take it a step further, to avoid repeatedly indexing into the array: var Idx: integer; Rec: ^TSomeRec; // [...] Idx := CountInMyArr; SetLength(MyArr, Idx + SomeDelta); Rec := @MyArr[Idx]; Rec.SomeField := SomeValue; // and repeated for each field in TSomeRec Inc(CountInMyArr); -
version control system Version Control System
stijnsanders replied to Soji's topic in Delphi IDE and APIs
I made my own diff just to get it the way I want it: DirDiff What I didn't want is the stuff that's the same for both twice on screen. The last re-work I did on it enabled diffs between 3 or more files, but that's still not exactly what's needed for conflict resolution. I've open-sourced it here: Github...- 49 replies
-
- git
- subversion
-
(and 1 more)
Tagged with:
-
Should I create subclass for User interface interaction?
David Schwartz replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Whoa. Spaghetti AND meatballs. 😮 Do NOT mix UI elements with data classes! I don't have time to unravel this mess for you. I'd start with your basic "item", which seems to be something like a TStringlist plus a name (that record thing). This could be a TUPLE of some sort. Alternatively, you could use the first entry of the stringlist to contain its own name, simply to avoid the additional structure just to have a separate identifier for it. But it may not even be necessary ... hang on. Your second level is you have a collection of these items. You use a TArray, but it could be a TList or even a TCollection. Whatever. It needs Add, Insert, Get, and Delete methods, and maybe a lookup of some kind (so you can find an "Item by name"). However, because of the simplicity of this, you could use one main TStringlist where the Strings[n] element is a 'name' and Objects[n] is a TStringlist. Then sl.IndexOf(some_name) -> n, and sl.Objects[n] -> the TStringlist (from your record). Viola! No need for a record or even an array. Just one TStringlist. Why use multiple structures when one will work fine for all needs? Technically speaking, while you could get by with just a single TStringlist, I'd wrap it into a class just to provide a simpler and more appropriate interface for it (eg., so you don't know how it's actually implemented). Memo.Lines is of type TStrings, so you'd want methods like these to interface nicely with TMemos: function TmyClass.GetItem( const nm : string ) : TStrings; var n : integer; begin Result := NIL; n := sl.IndexOf(nm); // assums 'sl' is the name of the main TStringlist in this object if (n >= 0) then Result := TStrings( sl.Objects[n] ) end; procedure TmyClass.SetItem( const nm : string; Value : TStrings ); var n : integer; sl2 : TStringlist; begin sl2 := GetItem(nm); if Assigned(sl2) then sl2.Assign(Value) else begin sl2 := TStringlist.Create(); sl2.Assign(Value); sl.AddObject( nm, sl2 ); end; end; Then when you need to get an item's value to a Memo, you'd use: memo1.Lines.Assign( myClassObj.GetItem( some_name ) ); // maybe do GetItem first to check for NIL before calling Assign in case Assign chokes if you give it NIL and to save the memo into an item buffer, you'd use: myClassObj.SetItem( some_name, memo1.Lines ); See how you're completely hiding the implementation, while providing an interface that makes using it very simple? And it knows nothing about UI elements, and yet works very simply with them. The class TmyClass is actually very simple, as it just contains a TStringlist (named 'sl' above). (Not DERIVED from it, but CONTAINS it.) The constructor would create it, and the destructor would destroy it. You'd have GetItem, SetItem, and maybe one or two other methods. That's it. -
Does application.processmessages behaviour differ between VCL and FMX?
Leif Uneus replied to Incus J's topic in RTL and Delphi Object Pascal
@Incus J Using Application.ProcessMessages is not the correct way to test if the GUI is updated in a lengthy process. Put your lengthy operation in a separate thread and add a possibility to cancel it if the GUI detects such a request. Application.ProcessMessages can lead to many hard to find anomalies and program failures. -
Guessing the decimal separator
Uwe Raabe replied to dummzeuch's topic in Algorithms, Data Structures and Class Design
function GuessDecimalSeparator(const Value: string): Char; { assumes that the decimal separator is the last one and does not appear more than once } var idx: Integer; begin idx := Value.LastIndexOfAny(['.', ',']); // possible decimal separators if (idx >= 0) then begin Result := Value.Chars[idx]; if Value.CountChar(Result) = 1 then Exit; end; Result := FormatSettings.DecimalSeparator; // Default end; -
You need to use sslxxxx PostgreSQL connection parameters: https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-PARAMKEYWORDS And put them into FireDAC PGAdvanced connection parameter: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Connect_to_PostgreSQL_(FireDAC)#Connection_Definition_Parameters
-
I can't blame you. I have the same problem with GExperts.