-
Content Count
2998 -
Joined
-
Last visited
-
Days Won
135
Everything posted by Remy Lebeau
-
In the "shell" key, set its "(Default)" value to "option 3". See Specifying the Position and Order of Static Verbs
-
Create component ERROR in expert in D10.2.3
Remy Lebeau replied to limelect's topic in RTL and Delphi Object Pascal
Not sure if this will help, but you might try calling ActivateClassGroup(TControl) before calling CreateComponent() to create a TControl-derived component. At least in DFM streaming, ActivateClassGroup() can be used to limit the class types that are looked at, to avoid ambiguities with VCL and FMX classes of the same name. -
Create component ERROR in expert in D10.2.3
Remy Lebeau replied to limelect's topic in RTL and Delphi Object Pascal
FMX didn't exist yet in D7, there was only VCL. Not easily, and not always. If a component's class name is fully qualified, you could look at the prefix to see if it begins with 'Vcl.' vs 'Fmx.' but that only works for components that are distinctly VCL or FMX, it will not work for classes that are shared by both frameworks, ie classes whose qualified names begin with 'System.', 'Data.', 'Xml.', etc. Otherwise, you could drill into each component's RTTI to see if they derive from Vcl.Controls.TControl vs Fmx.Controls.TControl, but again that only works for VISUAL components that are distinctly VCL vs FMX, but will not work for NON-VISUAL components that derive from TComponent and not from TControl. And, of course, the situation may get more complicated in cases where users (despite being told not to) decide to mix VCL and FMX together into a single project. -
Should Exit be used instead of 'record Exists?' boolean?
Remy Lebeau replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
In cases where I need the index of a found item, I prefer to have my Find* functions accept an optional parameter to output the index. That way, I can still return a pointer to the actual data and not have to re-index back into the data storage after Find* exits, but I can still use the index for other things as needed. For example: function FindRecord(aID: Integer; vIndex: PInteger = nil): PDataRec; var i: Integer; begin Result := nil; if vIndex <> nil then vIndex^ := -1; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; if vIndex <> nil then vIndex^ := i; Exit; end; end; end; Or: function FindRecord(aID: Integer; var vIndex: Integer): PDataRec; overload; var i: Integer; begin Result := nil; vIndex := -1; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; vIndex := i; Exit; end; end; end; function FindRecord(aID: Integer): PDataRec; overload; var ignore: Integer; begin Result := FindRecord(aProjectID, aID, ignore); end; -
What is wrong with TStringList
Remy Lebeau replied to pyscripter's topic in RTL and Delphi Object Pascal
It is worse than that. It loads the entire file into a local byte array, then it decodes the entire byte array into a single Unicode string, and then it parses that string to extract the lines into individual substrings. So, by the time the TStringList has finished being populated, and before TStrings.LoadFrom...() actually exits, you could be using upwards of 4-5 times the original file size in memory! Granted, this is temporary, and all of that memory gets freed when LoadFrom...() finally exits. But there is small window where you have a LOT of memory allocated at one time. -
What is wrong with TStringList
Remy Lebeau replied to pyscripter's topic in RTL and Delphi Object Pascal
You can do something similar using TStreamReader and its ReadLine() method, eg: var Stream := TReadOnlyCachedFileStream.Create('c:\temp\t'); try var Reader := TStreamReader.Create(Stream); try while not Reader.EndOfStream do begin S := Reader.ReadLine; // use S as needed... end; finally Reader.Free; end; finally Stream.Free; end; -
Should Exit be used instead of 'record Exists?' boolean?
Remy Lebeau replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Yes. Though, in the case of multiple identifiers, it may make sense to wrap them in another record, if that suits your needs, eg: type TDataRecID = record ProjectID: Integer; // or wharever ID: integer; end; PDataRec = ^TDataRec TDataRec = record DataID: TDataRecID; DataName: string; end; var Data: TArray<TDataRec>; function FindRecord(const aID: TDataRecID): PDataRec; var i: Integer; begin Result := nil; for i := Low(Data) to High(Data) do begin if (Data[i].DataID.ProjectID = aID.ProjectID) and (Data[i].DataID.ID = aID.ID) then begin Result := @Data[i]; Exit; end; end; end; function AddRecord(const aID: TDataRecID): PDataRec; var vNewData: TDataRec; begin vNewData := Default(TDataRec); vNewData.DataID := aID; Data := Data + [vNewData]; Result := @Data[High(Data)]; end; function EnsureRecord(const aID: TDataRecID): PDataRec; begin Result := FindRecord(aID); if Result = nil then Result := AddRecord(aID); end; procedure SaveData1(const aID: TDataRecID; const aName: string); var pData: PDataRec; begin pData := EnsureRecord(aID); pData.DataName := aName; end; Otherwise, yes, you could just handle them individually: type PDataRec = ^TDataRec TDataRec = record DataID: Integer; DataName: string; ProjectID: Integer; // or whatever end; var Data: TArray<TDataRec>; function FindRecord(aProjectID, aID: TDataRecID): PDataRec; var i: Integer; begin Result := nil; for i := Low(Data) to High(Data) do begin if (Data[i].ProjectID = aProjectID) and (Data[i].DataID = aID) then begin Result := @Data[i]; Exit; end; end; end; function AddRecord(aProjectID, aID: Integer): PDataRec; var vNewData: TDataRec; begin vNewData := Default(TDataRec); vNewData.DataID := aID; vNewData.ProjectID := aProjectID; Data := Data + [vNewData]; Result := @Data[High(Data)]; end; function EnsureRecord(aProjectID, aID: Integer): PDataRec; begin Result := FindRecord(aProjectID, aID); if Result = nil then Result := AddRecord(aProjectID, aID); end; procedure SaveData1(aProjectID, aID: Integer; const aName: string); var pData: PDataRec; begin pData := EnsureRecord(aProjectID, aID); pData.DataName := aName; end; -
Should Exit be used instead of 'record Exists?' boolean?
Remy Lebeau replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Just my 2-cents worth - I prefer to use something more like this: type PDataRec = ^TDataRec TDataRec = record DataID: integer; DataName: string; end; var Data: TArray<TDataRec>; function FindRecord(aID: Integer): PDataRec; var i: Integer; begin Result := nil; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; Exit; end; end; end; function AddRecord(aID: Integer): PDataRec; var vNewData: TDataRec; begin vNewData := Default(TDataRec); vNewData.DataID := aID; Data := Data + [vNewData]; Result := @Data[High(Data)]; end; function EnsureRecord(aID: Integer): PDataRec; begin Result := FindRecord(aID); if Result = nil then Result := AddRecord(aID); end; procedure SaveData1(aID: Integer; const aName: string); var pData: PDataRec; begin pData := EnsureRecord(aID); pData.DataName := aName; end; -
More accurately, UTF-8 is the default encoding used by Lazarus, not by FreePascal itself. On Windows, FPC's RTL sets the default encoding to the system encoding, just as Delphi does (on Linux/OSX, the default encoding is set to UTF-8). Lazarus overrides that RTL setting. https://wiki.freepascal.org/Unicode_Support_in_Lazarus#RTL_with_default_codepage_UTF-8 That is still a beta feature, and it doesn't work quite as well as everyone had hoped it would. Maybe in the future, it will be better.
-
Delphi 10.4.1 LIBSUFFIX AUTO
Remy Lebeau replied to pyscripter's topic in RTL and Delphi Object Pascal
The actual {$LIBSUFFIX AUTO} directive was added to the compiler in 10.4, but they didn't advertise its existence yet, so nobody has really played with it until now. So, if the linkage is broken now, it was probably broken in 10.4 to begin with and nobody noticed. 10.4.1 just adds the ability to set the libsuffix to AUTO in the Project Options dialog. I don't have 10.4 or 10.4.1 installed, so I can't test this myself. I created a ticket for this: RSP-30820: Fail to load package with LIBSUFFIX AUTO -
Main form appears when i openn a sub-sub form. :-(
Remy Lebeau replied to Ian Branch's topic in General Help
How do you want the Forms to behave in relation to each other? Do you want the MainForm to ever be able to appear on top of Form2? If not, then set the MainForm as the PopupParent for Form2. And set Form2 as the PopupParent for Form3, if you don't want Form2 to ever appear on top of Form3. See this blog article: PopupMode and PopupParent. -
Well, that is pretty easy to accomplish using TRttiContext.GetType() or TRttiContext.FindType(), and then using TRttiType.GetField() and TRttiType.GetProperty().
-
Are you looking for an RTTI solution to detect at run-time whether or not a given class type has declared a given class variable/property at compile-time? What is the end goal here that you are trying to accomplish?
-
Yup. Microsoft Office is notorious for using its own UIs that are very different from the rest of the OS experience. Office is like Microsoft's test bed for new UI ideas. For example, Office used ribbon controls before they were officially integrated into the Win32 API. Basically. no. Not in the standard Win32 API , no.
-
Where is localBMP coming from? You don't really need to make a copy of a TBitmap just to draw it, so you could just use localBMP as-is and get rid of tempBMP. Unless localBMP is actually supposed to be aBMP instead (typo?), then using tempBMP makes more sense if you are trying to draw a TBitmap onto itself. When calling DrawBitmap(), RecFull is supposed to be a rectangle within the TBItmap that you are drawing from, but you are setting it to the rectangle of the TBitmap that you are drawing onto. Change aBMP to tempBMP when populating RecFull.
-
Or, you could just treat them as-is as RCDATA resources instead. Any data can be stored in RCDATA, it is just raw bytes. Now, whether you can load a PNG image from an RCDATA resource at runtime is another issue, depending on HOW you load it.
-
https://stefansundin.github.io/xn_resource_editor/
-
Boolean short-circuit with function calls
Remy Lebeau replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
If they all have the SAME argument types, yes. The TFunc generic supports 0..4 arguments, plus the return type: TFunc<TResult> = reference to function: TResult; TFunc<T,TResult> = reference to function (Arg1: T): TResult; TFunc<T1,T2,TResult> = reference to function (Arg1: T1; Arg2: T2): TResult; TFunc<T1,T2,T3,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3): TResult; TFunc<T1,T2,T3,T4,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4): TResult; I don't have a working IDE right now, so I didn't try to compile it. I was trying to be clever using a const, instead of a var that has to be recreated every time the function is called, eg: function IsAnyTrue5: boolean; var Funcs: array[0..2] of TFunc<Boolean>; i: Integer; begin Result := False; Funcs[0] := A; Funcs[1] := B; Funcs[2] := C; for i := Low(Funcs) to High(Funcs) do Result := Funcs[i]() or Result; end; Or: function IsAnyTrue5: boolean; var Funcs: TArray<TFunc<Boolean>>; i: Integer; begin Result := False; Funcs := [A, B, C]; for i := Low(Funcs) to High(Funcs) do Result := Funcs[i]() or Result; end; Or: var Funcs: TArray<TFunc<Boolean>>; function IsAnyTrue5: boolean; var i: Integer; begin Result := False; for i := Low(Funcs) to High(Funcs) do Result := Funcs[i]() or Result; end; initialization Funcs := [A, B, C]; In any case, the idea being to put all of the functions into an array, and then loop through the array calling them and tallying up the results. This way, more functions can be added in the future with minimal effort, Sure, that will work. I knew TFunc existed, I had just forgot about plain function pointers, too. Yes, all of the functions would have to be of same signature. Otherwise they have to be called individually. Since the OP mentioned running through a lot of options, I assume there is some common interface for them. -
Boolean short-circuit with function calls
Remy Lebeau replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
How about something like this? uses System.SysUtils; function IsAnyTrue5: boolean; const Funcs: array[0..2] of TFunc<Boolean> = (A, B, C); var i: Integer; begin Result := False; for i := Low(Funcs) to High(Funcs) do Result := Funcs[i]() or Result; end; -
Is interposer class really best to customize TPanel.Paint?
Remy Lebeau replied to Mike Torrettinni's topic in VCL
In this example, no, since the only design-time functionality being used is RegisterComponents() which is implemented in the RTL in a runtime package, not a design-time package. So this example can exist in a single runtime+designtime package. Yes, so that the IDE knows that it is allowed to use this package for both installation into the IDE and compiling into executables. Yes, because designtime-only packages are not allowed to be compiled into executables, only runtime-only and runtime+designtime packages. Marking the package for runtime usage is important. Maybe not a hard requirement, especially in the early days, but around D6 or so this actually did start getting enforced. And besides, it is how the system has always been intended to be used, and how it gets documented by 3rd party books and such. And frankly, it just makes sense to do it this way. Component logic goes in a runtime package, design-time editors go in a design-time package. If there are no editors, the two packages can be merged into one. Simple and straight forward. Whether or not it works to compile a designtime-only package into a runtime executable is another matter. It is not supposed to work. -
Is interposer class really best to customize TPanel.Paint?
Remy Lebeau replied to Mike Torrettinni's topic in VCL
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Package-specific_Compiler_Directives https://www.oreilly.com/library/view/delphi-in-a/1565926595/re414.html -
Is interposer class really best to customize TPanel.Paint?
Remy Lebeau replied to Mike Torrettinni's topic in VCL
If you make the layered window be a child of the panel, then that will only work on Windows 8+. On earlier Windows, you would have to make the layered window be a top-level overlay window that follows the panel onscreen. -
Is interposer class really best to customize TPanel.Paint?
Remy Lebeau replied to Mike Torrettinni's topic in VCL
Um no, because designtime-only packages are not used in runtime executables. The component needs to be in a runtime package, which in this particular example can ALSO be used as a design-time package. -
Is interposer class really best to customize TPanel.Paint?
Remy Lebeau replied to Mike Torrettinni's topic in VCL
If the component does not have extra design-time functionality that directly interacts with IDE APIs (property/component editors, OpenTools plugin, etc), then you do not need to make a separate design-time package. You can create 1 package and mark it as being BOTH a runtime package AND a design-time package. That will work just fine. -
enums with duplicate values
Remy Lebeau replied to dummzeuch's topic in RTL and Delphi Object Pascal
According to my notes, assigning explicit ordinal values to enums has been supported since D6. I haven't tested it in earlier versions, though.