Jump to content

PeterBelow

Members
  • Content Count

    563
  • Joined

  • Last visited

  • Days Won

    13

Posts posted by PeterBelow


  1. 4 hours ago, Rollo62 said:

    Hi there,

     

    I'm looking for an IndexOfAny( array or string, ... ) function, and find that there is already one in the TStringHelper.

    Unfortunately this is declared as a private function.

     

    
      TStringHelper = record helper for string
        ...
      private
        ...
        //<== NICE TO HAVE
        function IndexOfAny(const Values: array of string; var Index: Integer; StartIndex: Integer): Integer; overload;
        ..
      public
        ...
        // Maybe these bites with above declaration, as Char may interpreted as string too ?
        function IndexOfAny(const AnyOf: array of Char): Integer; overload;
        function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer): Integer; overload;
        function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer; Count: Integer): Integer; overload;
        ...
    end;

    I'm not realy sure why this function is hidden.

    Maybe because Char and String might cause issues when mixing in a overload, I haven't checked what would happen when making this public too ?

     

     

     

    There would probably be a conflict in overload resolution.

     

    Anyway, System.StrUtils contains IndexStr and IndexText functions that would serve your need here.


  2. 42 minutes ago, stacker_liew said:

    Anyone experience this or not? I'm using Delphi 11.1, it stuck occassionaly while opening project.

     

    Btw, I'm using Windows 11.

    I have seen something like this occasionally (D 11.1 on Win10). Task Manager shows 100% use of one CPU core for the process. Sometimes it resolves itself after a few seconds but often the only option is to kill the process. On restarting the IDE it usually works normally. I have never been able to reproduce it at will.

    • Like 1

  3. The VCL is not thread-safe in itsself, creating top-level objects like forms, frames or datamodules accesses some global stuff in vcl.forms connected to reading components from the dfm file.

     

    Try to replace your datamodules with a class (not derived from TCustomForm) that creates and configures all components you now place at design-time in code. I dimly remember a tool that could create such code from a dfm file, never used it myself, though.

     

    Are all your threads created in the same host thread? If so that should actually mitigate the problem since the thread constructor runs in the host thread, so all datamodules would be created in the same thread. But that may cause another problem: database connections are usually bound to the thread that creates them. If the datamodule creation already creates the connection, which is then later used in the context of the thread that owns the datamodule that may cause problems since the db access library may try to solve the conflict by serializing all DB access in a separate thread.

     

    Multithreading using a database can be even trickier than multithreading itself...:classic_mellow:

    • Like 1

  4. 19 hours ago, David Heffernan said:

    I'm not happy.  Optional parens means that a symbol like MyFunc can mean either the procedure or the value returned by a call to the procedure.  And there are times when that ambiguity can't be resolved by the compiler.  Most commonly when MyFunc returns another procedural type.  So when you write SomeFunc := MyFunc are you assigning MyFunc or MyFunc() to SomeFunc?  It sucks that in Delphi there is this ambiguity.  The ambiguity would not exist if () were not optional.  Like they aren't in so many other better designed languages.

    As far as I remember this "feature" comes from the original Wirth Pascal in Delphi's anchestry. Dropping it now would break heaps of legacy code, so is very unlikely to happen.


  5. 3 hours ago, ChrisChuah said:

    Hi

    Actually I want to use delphi to create a DLL with functions or procedures containing a callback.

    How can i create such functions in delphi so that the project can be compiled to a dll for C Sharp programmer to use

    Previously all DLL functions does not have function pointer or callback functions when i was using Delphi 6 era.

    Also my C sharp programmers said they cannot use COM because their program will be running in Docker for linux

     

    A COM dll usually uses interfaces as callbacks as well, not function pointers.

     

    I know nothing about Docker so cannot give you any advice on this topic. .NET has an interface to unmanaged code, which is used to interact with the OS API, though. Your dll would be unmanaged code, you just have to make sure you do not use any Delphi-specific types (especially compiler-managed ones, like String or dynamic arrays) in the functions the DLL exports.


  6. 2 hours ago, ChrisChuah said:

    Hi

    I have an existing component that communicates with a server via TCP.

    However, this component can only be used in delphi.

    When i call a function in this component, it will send out a TCP message.

    After some time, it will return back data and it will trigger an event back in the component.

    So, anytime i want to use this component, i can drop the component into the form.

    I can double click on the event and write codes to handle the result from the event.

     

    Now, if i want to make this component into a DLL for C sharp programmer to use

    How can i create events into the dll for C Sharp programmer to use?

     

    Create a COM dll, Delphi has a wizard for that. Google for "C# com interop" to find examples for how to use such a thing from the .NET side.

    • Like 1

  7. 35 minutes ago, Diego Simonini said:

    Hi everyone, I'm guessing if exists a shortcut or a plugin to keep declaration of functions and procedures in sync with implementation.

    Something bidirectional, if positioned on declaration the shortcut should update implementation and viceversa.

     

    Thank you

    ModelMaker Code Explorer (MMX) can do this, as well as a lot of other things. Could not live without it...  See https://www.mmx-delphi.de/ It is free and maintained.


  8. 42 minutes ago, AndrewHoward said:

    RaizeComponentsVcl_Reg.pas(25) Fatal: E2213 Bad packaged unit format: C:\Program Files (x86)\Embarcadero\Studio\17.0\lib\win32\release\rtl.dcp.System

    The script is looking at the  wrong version of the rtl package. 17.0 is not 10.2 Tokyo, that would be 19.0. Check the pathes used in the script or the dproj files it refers to. 17.0 is 10.0 Seattle if memory serves.


  9. 13 hours ago, abdellahmehdi said:

    When recalling a shape from another project😩

    please what should i do🙏

     

    The error message looks like the designer tries to read values from a dfm file into a component that has not been created yet.

     

    Was this other project created with the same Delphi version? Does it open and compile in Delphi Alexandria?  Does the form you are trying to use in the new project use any self-written or 3rd-party components you are not yet using in forms of the new project?

     

     

     

     

     

    • Like 1

  10. 9 hours ago, Behdadsoft said:

    Hi. 

    I added many images into Access Database as binary. Now I want to load them form database and put in TImage.

    I wrote code below but it doesn't work and give me an error (Attached). 

    I compound my code with this example: Streaming Bitmaps and other Binary Data to BLOB Fields

     

     

    The source of your problem is probably the line

     TImage1.Picture.Assign(Image);

    Should'nt that be

     Image1.Picture.Assign(Image);

     


  11. 7 hours ago, MarkShark said:

    This is going to sound like a homework assignment, but it's actually needed for some ZeosLib code to handle PostgreSQL client library digital array format.  The array information is the following:

     

    NDims:  The number of dimensions:   Example: 3

    DimArray:  An array of dimension sizes.  Example [1,2,2]

    ItemsArray:  An array of data items (say Integer.)  Example: [1,2,3,4]

     

    I'm trying to figure out an algorithm to turn the information above into a string that has a format like: {{{1,2},{3,4}}}.  I've got it working for 1 and 2 dimensions, but it seems like I'm brute forcing it when it seems like a more clever approach should be possible.   Any tips, hints, or psuedo-code (or actual code!) appreciated!

    unit Unit1;
    
    interface
    
    uses system.Generics.Collections, system.Typinfo, system.sysutils;
    
    type
      TDynamicArrayFormatter<T> = class
      strict private
        FData: TArray<T>;
        FDimensions: TArray<cardinal>;
        FIndices: TArray<cardinal>;
        FType: PTypeInfo;
      strict protected
        procedure AddValue(aBuilder: TStringBuilder);
        function CalcLinearIndex: Integer;
        function GetText: string;
        procedure ProcessDimension(aDimension: Cardinal; aBuilder: TStringBuilder);
      public
        constructor Create(const aDimensions: array of cardinal; const aDataArray:
            TArray<T>);
        class function Execute(const aDimensions: array of cardinal; const aDataArray:
            TArray<T>): string;
      end;
    
    implementation
    
    constructor TDynamicArrayFormatter<T>.Create(const aDimensions: array of
        cardinal; const aDataArray: TArray<T>);
    begin
      inherited Create;
      SetLength(FDimensions, Length(aDimensions));
      Move(aDimensions[0], FDimensions[0], Length(FDimensions) * Sizeof(Cardinal));
      FData := aDataArray;
      FType:= TypeInfo(T);
      SetLength(FIndices, Length(FDimensions));
    end;
    
    procedure TDynamicArrayFormatter<T>.AddValue(aBuilder: TStringBuilder);
    var
      LValue: T;
      N: Integer;
      S: string;
    begin
      N:= CalcLinearIndex;
      LValue := FData[N];
      case FType.Kind of
        tkInteger: S:= Pinteger(@LValue)^.ToString;
        tkUnicodeString: S:= PPChar(@LValue)^;
      else
        S:= 'unknown type of T';
      end;
      aBuilder.Append(S);
    end;
    
    function TDynamicArrayFormatter<T>.CalcLinearIndex: Integer;
    var
      I, N: Integer;
    begin
      Result := 0;
      N:= 1;
      for I := High(FDimensions) downto Low(FDimensions) do begin
        Inc(Result, N * Pred(FIndices[I]));
        N := N * FDimensions[I];
      end;
    end;
    
    class function TDynamicArrayFormatter<T>.Execute(const aDimensions: array of
        cardinal; const aDataArray: TArray<T>): string;
    var
      LInstance: TDynamicArrayFormatter<T>;
    begin
      LInstance := TDynamicArrayFormatter<T>.create(aDimensions, aDataArray);
      try
        Result := LInstance.GetText;
      finally
        LInstance.Free;
      end;
    end;
    
    function TDynamicArrayFormatter<T>.GetText: string;
    var
      LBuilder: TStringBuilder;
    begin
      LBuilder := TStringBuilder.Create;
      try
        ProcessDimension(1, LBuilder);
        Result := LBuilder.ToString;
      finally
        LBuilder.Free;
      end;
    end;
    
    procedure TDynamicArrayFormatter<T>.ProcessDimension(aDimension: Cardinal;
        aBuilder: TStringBuilder);
    var
      I: Cardinal;
      LAddValues: Boolean;
    begin
      aBuilder.Append('{');
      LAddValues := integer(aDimension) = Length(FDimensions);
      for I := 1 to FDimensions[Pred(aDimension)] do begin
        FIndices[aDimension-1] := I;
        if LAddValues then begin
          if I > 1 then
            aBuilder.Append(',');
          AddValue(aBuilder);
        end
        else
          ProcessDimension(Succ(aDimension), aBuilder);
      end;
      aBuilder.Append('}');
    end;
    
    
    
    end.

    Usage like

     

    var
      S: string;
    begin
       S:= TDynamicArrayFormatter<string>.execute([1,2,2], ['one','two','three','four']);
       WriteLn(S);
    end;

     

    • Thanks 1

  12. 13 hours ago, PenelopeSkye said:

    I must have performed the search incorrectly because I did not find anything like this, so please point me to wherever I should be looking for answers to this question.  I am a newbie to both Delphi\pascal and the forum.

     

    I have an app that brings up a search dialog box that leads to a result dialog box. 

    When the result dialog box appears the focus is always on the last button pushed when last in the result dialog box.  

     

    How do I get a specific button (the OK button) to always have focus no matter what button was last pushed?

     

    I tried clicking on the button in the IDE (Delphi 10.3) to see if there was an  ActiveControl property in the object inspector but there is not.

     

    How can I set focus to the OK button?

     

    Thanks!

    In addition to Anders' reply: note that (VCL) buttons have two useful properties for dialog boxes:

    • Default - if you set that to true the button will "click" if the user hits the Enter or Return key, regardless of whether the button has focus or not.
    • Cancel - if that is set to true the ESC key will click the button. If the button's ModalResult is set to mrCancel that will close the dialog.

  13. 24 minutes ago, gioma said:

    I almost found a solution:

     

    
    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    var
      buf:WideChar;
      KSta:TKeyboardState;
      s:string;
    begin
      log.Lines.Add('KeyUp : '+ inttoStr(key) );
      Winapi.Windows.ToUnicodeEx( key, 0, ksta, @buf,255, 0, 0);
      s:=WideCharToString(@buf);
      log.Lines.Add('KeyUp : '+ s);
    end;

    Obviously I will not use it like that, but there is a problem, it goes into exception when it writes the result to the log (TMemo).
    Even if I levo the last line goes into exception, however the variable s is valued.

    buf is declared as a single Widechar but you tell ToUnicodeEx that it can hold 255 Widechars. A good way to ruin your call stack. :classic_cool:

    • Like 1

  14. On 4/17/2022 at 6:03 PM, David Heffernan said:

    Of course it makes sense. Try declaring set of TObject and see how that works out. You'd need to constrain to an ordinal type with 256 or fewer elements and you can't do that with constraints. Too bad we can't have templates. 

    The  error message makes no sense since it gives the impression that the code would work if T is constraint to class or interface. That is of course not the case.


  15. On 4/15/2022 at 6:21 PM, gioma said:

    Hi everyone, I'm making an application that communicates between different operating systems. In this case I have to send a character when it is pressed from Windows to MAC.
    In the Form.OnKeyUp function there is the parameter "key: Word" which represents the character code.
    If it is not a special character (à, è, ì, ò, ù) this co corresponds to the ASCII code.
    If, on the other hand, I press the "è" key, the code will be 222 which however does not correspond to its ASCII code and therefore I send wrong information to the MAC which is unable to retrieve the corresponding character.
    How do I get the exact ASCII code of that character?
    Thank you all.

    Like Remy said this would be much easier to handle if you transmit the whole input string after the user has entered it. There are ways to figure out which character would be created from a virtual key code and the current state of the modifier keys (Shift, Alt, Ctrl), see the MapVirtualKeyEx Windows API function, but this pointless if you have to deal with accented characters or other composites that are created by a sequence of keystrokes, or Alt+numpad input. Let Windows do this work for you and use the OnKeyPress event; it gives you the character directly.

    • Like 1

  16. 3 hours ago, Behdadsoft said:

    Hi.

    I have a DBGrid on my form that contain many rows. the problem is that, scrollbar don't work normally like other programming language. I searched in google for find a solution for this issue but I couldn't find anything. for better understanding, I captured a video from C# DataGridView and Delphi DBGrid that the problem is obvious.
    Also I Use Delphi 11.1.

     

    Video: Compare C# and Delphi Scrollbar

    A TDBGrid is a kind of virtual grid. It shows rows from a dataset and does not know how many rows the dataset contains (the dataset itself may not know that, in fact). So it scrolls the active row in the dataset, not the rows in the grid; the selected row in the grid corresponds to the active record in the dataset. The grid actually contains only enough rows to fill the visible area, which get reused for new content as the dataset is scrolled.


  17. On 4/15/2022 at 9:27 PM, Remy Lebeau said:

    You can't declare a Generic for a stand-alone Set, no.  But I'm pretty sure (I haven't tried it lately, though) that you can move the Set into the class, and then use a Generic on the class, eg:

    
    type
      TFPropertiesCpt<T> = class (TInterfacedObject, IFCompteurUpdate)
      public
        type
          TSetOfT = Set of T;
      private
        FItems      : TDictionary<Integer, rCompteurUpdate<T>>;
        FProperties : TSetOfT;
        ...
        procedure Duplicate(const aValue : TFPropertiesCpt<T>);
      public
        ...
        property Items : TDictionary<Integer, rCompteurUpdate<T>> read FItems write FItems;
        property Properties : TSetOfT read FProperties;
        function Add(const aTypeOf: T; const aInc: Integer = 1) : TFPropertiesCpt<T>;
        function WithInit: TFPropertiesCpt<T>;
        function WithInfo(const aValue: T; aProc: TProc) : TFPropertiesCpt<T>;
        function WithMax(const aValue : Integer) : TFPropertiesCpt<T>;
        function ResetCompteur(const aValue: T): TFPropertiesCpt<T>; overload;
        ...
        class function Clone(const aValue: TFPropertiesCpt<T>): TFPropertiesCpt<T>;
      end;

    Where T can then be set to any enum type, like TTypeOfProperties, etc.

    I tried something like that and the compiler does not accept the "set of T" declaration, moaning about T not having a class or interface constraint. Which makes no sense at all in this case.


  18. 1 hour ago, PatV said:

    Delphi 11.0 

     

    Hi All,

     

    I would like to have an advice on how can I get this class more useful, I'm annoying with the 'set of  ..' and the property of the set.

     

    Sets have their use but they also have limitations, e. g. they are not supported with generics as far as I know, so a "set of T" does not work. If you could replace the set with a list you could turn the class into a generic base class with the generic T: record parameter for the enumeration that the set is now defined with. Of course a check for "x in set" is much faster than a check for "x in list".

     

    The compiler (11.1) accepts something like

    type
      TWrapper<T: record> = class
      private
        FSet: TList<T>;
      end;
      TEnum = (one, two, three);
      TEnumWrapper = class(TWrapper<TEnum>)
      end;

    But you still cannot apply functions like Ord to T in methods of TWrapper, nor cast it to Byte. The constraint system for generics is too limited here since you cannot specify T as an ordinal type.


  19. 56 minutes ago, Fons N said:

    Hi,

     

    I am trying to import using the clipboard some text which has to be processed. I am not a professional coder, it's just a hobby, but I do use some of my application at work (administration department).

     

    Below is data from a web application. In notepad is looks like this. 

     

    image.png.25c45af0f0566740e56a8e3d381bf211.png

     

     

    You are approaching this from the wrong angle. The data you showed pasted into notepad looks like a semicolon-separated CSV format. To dissect this you can use TStringlist. Something like this:

     

    var
      LText, LLine: TStringlist;
      i: integer;
    begin
      LText := TStringlist.Create;
      try
        LText := Clipboard.AsText;
        // This splits the data into lines
    
        LLine := TStringlist.Create;
        try
          LLine.StrictDelimiter := true;
          LLine.Delimiter := ';';
         
          for i:= 0 to LText.Count - 1 do begin
            LLine.DelimitedText := LText[i];
            if i = 0 then
              ProcessHeaderLine(LLine)
            else
              ProcessDataLine(LLine); 
          end;
        finally
          LLine.Free;
        end;
      finally
        LText.Free;
      end;
    end;
           
         

    Untested, just typed into the post directly.

     

    The two Process routines are something you would write yourself. For each the passed stringlist should hold 5 lines, the column captions for the header and the column values for the data.

    If you really want to replace a non-breaking Unicode space it is a single character with the code #$00A0, not a two-character string. Your hex viewer probably pastes the clipboard content as ANSI text, while Notepad pastes it as Unicode (UTF-16).

     

    • Like 1
    • Thanks 1

  20. 21 hours ago, kvk1989 said:

    hi , how can add file path ?

     

    i want to add file with file path

    like this 

    if combobox.itemindex =0 then

    begin

    firehose loader file with file path

    end;

    thanks

     

    The System.IOUtils unit contains a number of helpers to work with files in general. The TPath record has methods to build a path, dissect a path, find system folders etc.


  21. 10 hours ago, Mike Torrettinni said:

    It's quite common to initialize Result of string function with SetLength(Result, len) and then work with the Result, like:

     

    
    // Switch Upper to lower and lower to Upper case
    function SwitchCase(const aStr: string): string;
    var i: integer;
    begin
      SetLength(Result, Length(aStr)); // without Result := '';
      for i := 1 to aStr.Length do
        if CharInSet(aStr[i], ['a'..'z']) then
          Result[i] := UpCase(aStr[i])
        else
          Result[i] := LoCase(aStr[i]);
    end;

    the Result holds some data, which is overwritten with the code after SetLength. Of course if we initialize Result := ''; before SetLength, then Result is a new string.Is that always unused memory location or is there a danger that we are actually overwriting valid memory block (part of other string, or long array.,..) and can cause issues in the running code?

     

     

    A function return value of type string as well as other compiler-managed types (e.g. dynamic arrays) is actually implemented as an additional Var parameter, so your function would be equivalent to

    procedure SwitchCase(const aStr: string; var Result:string);

    The compiler initializes the string variable passed for Result at the point of call, so it will always be valid. It is not guaranteed to be nil (string.empty), though. The compiler may reuse another hidden local variable used previously in the calling method.

     

    Such things are documented in the Delphi Language guide, see https://docwiki.embarcadero.com/RADStudio/Sydney/en/Program_Control_(Delphi)

    • Thanks 1

  22. 4 hours ago, Ian Branch said:

    Hi Team,
    I need a mechanism/code where a 3 letter Company code is combined with an autoinc number, but, the autoinc number is related to the Company code.  The combined are to fit in a 10 char field.  These are to be individual Company Asset Numbers to go on to QRCode labels and into the table.
    To clarify:
    Let's say there are 3 companies, there will be lots more in practice, with Company codes of ABC, DEF, and GHI.
    I need to be able to generate as/when required, and sequentially, ABC0000001 to ABC9999999, and DEF0000001 to DEF9999999, and GHI0000001 to GHI9999999, etc, on an as needed basis.

    Thoughts/suggestions appreciated.

    Regards & TIA,
    Ian

    Is this for a multi-user application, where several users may request a new code/number combination for the same code concurrently? That may pose a problem unless you can figure out  a way to avoid or at least detect collisions. On a database level sequences (or generators, nomenclature differs between databases) were introduced to solve such issues, but in your case you would need one sequence per code. A unique index on the table storing the code+number values would at least give you a way to detect collisions if you simply use a SELECT max(value) FROM <table> WHERE value like :code+'%' to get the last value used.


  23. 3 hours ago, Henry Olive said:

    I wrote below code ( Delphi 10.3)  and everything is OK mouse wheel works

    but to me, there should not need below code, mouse wheel should work

    without any code. 

    The VCL controls do not implement a default handling of the mouse wheel, unless a Windows control implements it on the API level. TScrollbox is not based on an API control, so you have to code this yourself.  You only have to do this once, though: create a descendant of TScollbox that implements the behaviour you want and the use that. Note that when creating a component you do not use the parent component's events, those are for the component user. Instead you overwrite the virtual or dynamic methods that fire the events.

    • Like 1
×