Jump to content

Uwe Raabe

Members
  • Content Count

    2889
  • Joined

  • Last visited

  • Days Won

    169

Posts posted by Uwe Raabe


  1. Just to make sure I understand correct: You want to comment the implementation of a method, but not the declaration?

    6 hours ago, Ian Branch said:

    During development/rework I often need to select a full procedure or function for delection or replacement.

    In such a case I usually extract the current method with MMX into a new one. Let's assume the method is named MyMethod. Then I extract the content in question (can be the whole) into a new method MyMethodA. If configured accordingly that leaves a single call to MyMethodA in the body of MyMethod. Then I can either comment that call or replace it with another call to MyMethodB, which is implemented differently. 

     

    This has the advantage that I can call either method depending on some condition or configuration setting to test the behavior without re-compiling.

    • Like 1

  2. 57 minutes ago, Ian Branch said:

    My issue is that with large methods it would be easier if the method could be readily selected, rather than having to manually select from start to finish.

    MMX has an action Select Method Body (under Text Tools...), although that spares the variable declarations before the begin. There is no shortcut by default, but that can be configured.


  3. TActivityIndicator uses a TTimer to update itself and thus relies on the main thread message queue to be served. This would detect most of the cases where the main thread is blocking.

     

    Other threads must implement some other way to signal they are still working, which then can be monitored by the main thread to act accordingly.


  4. 1 minute ago, limelect said:

    TAdvCircularProgress does it . It turns until you stop it.

    AFAIK, a Windows Spinner control is an edit containing numbers with arrows to increase/decrease.


  5. 46 minutes ago, DJof SD said:

    It would hang after it was doing something with GetIt.

    It may appear so, but often it is a question of patience. Even when you never installed anything from GetIt, most of the IDE is installed with it and that needs some time to uninstall.

    • Like 2

  6. 8 minutes ago, Rollo62 said:

    Would you please explain a little, how the 64Bit IDE is integrated into the existing system?

    It is located in the bin64 subfolder, which already exists. Most of the new 64-bit files are placed there, too. A couple of 64-bit design time BPL and DCP files are added to the appropriate places. The amount of additional needed disk scape can be neglected.

     

    The 64-bit IDE shares most of the registry entries, while adding a couple of x64 keys like Known IDE Packages x64 and Known Packages x64.

    • Like 2

  7. Vcl.Graphics internally registers the following extensions: tiff, tif, wmf, emf, ico and bmp.

     

    All other extensions are registered in the units the format is implemented: 

    • gif in Vcl.Imaging.GIFImg
    • jpeg and jpg in Vcl.Imaging.jpeg
    • png in Vcl.Imaging.pngimage
    • svg, webp and wbmp in Vcl.Skia

    Only when these units are used in your application the corresponding file extensions will be supported.

     

    While designing in the IDE, these units are usually registered because the vclimg and the Skia packages are loaded.


  8. I found the solution using the SB_THUMBPOSITION approach working best for all my tests. As I was a bit irritated by the WM_KEYDOWN, WM_MOUSEFIRST..WM_MOUSELAST (why act on every keystroke or mouse move?), I used the previous approach with CN_COMMAND, WM_HSCROLL and WM_VSCROLL message handlers:

    type
      TLinkMemo = class(TMemo)
      private
        FLinkedMemo: TLinkMemo;
        procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
        procedure WMHScroll(var Message: TMessage); message WM_HSCROLL;
        procedure WMVScroll(var Message: TMessage); message WM_VSCROLL;
        procedure SyncLink;
      public
        property LinkedMemo: TLinkMemo read FLinkedMemo write FLinkedMemo;
      end;
    
    procedure TLinkMemo.CNCommand(var Message: TWMCommand);
    begin
      inherited;
      if (Message.NotifyCode = EN_VSCROLL) or (Message.NotifyCode = EN_HSCROLL) then
        SyncLink;
    end;
    
    procedure TLinkMemo.SyncLink;
    
      procedure UpdateScrollBar(BarFlag: Integer; Msg: Cardinal);
      var
        scrollInfo: TScrollInfo;
      begin
        scrollInfo.cbSize := SizeOf(scrollInfo);
        scrollInfo.fMask  := SIF_POS;
        if GetScrollInfo(Handle, BarFlag, scrollInfo) then
          LinkedMemo.Perform(Msg, MAKEWPARAM(SB_THUMBPOSITION, scrollInfo.nPos), 0);
      end;
    
    begin
      if LinkedMemo = nil then Exit;
    
      var savedLink := LinkedMemo.LinkedMemo;
      try
        LinkedMemo.LinkedMemo := nil;
        UpdateScrollBar(SB_HORZ, WM_HSCROLL);
        UpdateScrollBar(SB_VERT, WM_VSCROLL);
      finally
        LinkedMemo.LinkedMemo := savedLink;
      end;
    end;
    
    procedure TLinkMemo.WMHScroll(var Message: TMessage);
    begin
      inherited;
      SyncLink;
    end;
    
    procedure TLinkMemo.WMVScroll(var Message: TMessage);
    begin
      inherited;
      SyncLink;
    end;

    A more sophisticated solution can separate the HSCROLL and VSCROLL events and reduce the UpdateScrollbar call to the corresponding part.


  9. 22 hours ago, Willicious said:

    I might be imagining that RAD Studio has ever done this

    I am pretty sure that this has never worked before - at least it does not in Delphi 7, Delphi XE8 or Delphi 12. So instead of filing a bug report this should probably better be a feature request.

     

    Besides that, I actually have problems using the mouse wheel while pressing the left mouse button, but that can also be caused by my age.

    • Like 1

  10. Horizontal scrolling can be made to work, but doing that with the mouse wheel always produces glitches. I guess, it is because the scrolling is done with pixels, while EM_LINESCROLL does it with characters.

     

    type
      TLinkMemo = class(TMemo)
      private
        FLinkedMemo: TLinkMemo;
        FSkipScroll: Boolean;
        procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
        procedure WMHScroll(var Message: TMessage); message WM_HSCROLL;
        procedure WMVScroll(var Message: TMessage); message WM_VSCROLL;
        procedure SyncLink;
        procedure DoScroll(var Message: TMessage);
      public
        property LinkedMemo: TLinkMemo read FLinkedMemo write FLinkedMemo;
      end;
    
    procedure TLinkMemo.CNCommand(var Message: TWMCommand);
    begin
      inherited;
      FSkipScroll := False;
      if (Message.NotifyCode = EN_VSCROLL) or (Message.NotifyCode = EN_HSCROLL) then begin
        SyncLink;
        FSkipScroll := True;
      end;
    end;
    
    procedure TLinkMemo.DoScroll(var Message: TMessage);
    begin
      var saveLinkedMemo := FLinkedMemo;
      try
        FLinkedMemo := nil;
        Perform(Message.Msg, Message.WParam, Message.LParam);
      finally
        FLinkedMemo := saveLinkedMemo;
      end;
    end;
    
    procedure TLinkMemo.SyncLink;
    begin
      if LinkedMemo = nil then Exit;
    
      var saveLink := LinkedMemo.LinkedMemo;
      try
        LinkedMemo.LinkedMemo := nil;
    
        var myFirstVisibleChar := Perform(EM_CHARFROMPOS, 0, 0);
        var linkFirstVisibleChar := LinkedMemo.Perform(EM_CHARFROMPOS, 0, 0);
        if myFirstVisibleChar = linkFirstVisibleChar then Exit;
    
        var myLineIndex := Perform(EM_LINEFROMCHAR, myFirstVisibleChar, 0);
        var myLineStart := Perform(EM_LINEINDEX, myLineIndex, 0);
        var myCharIndex := myFirstVisibleChar - myLineStart;
    
        var linkLineIndex := LinkedMemo.Perform(EM_LINEFROMCHAR, linkFirstVisibleChar, 0);
        var linkLineStart := LinkedMemo.Perform(EM_LINEINDEX, linkLineIndex, 0);
        var linkCharIndex := linkFirstVisibleChar - linkLineStart;
    
        LinkedMemo.CaretPos := CaretPos;
        if myCharIndex < linkCharIndex then begin
          LinkedMemo.CaretPos := TPoint.Create(0, myLineIndex);
          LinkedMemo.Perform(EM_SCROLLCARET, 0, 0);
          LinkedMemo.CaretPos := CaretPos;
          linkCharIndex := 0;
        end;
        LinkedMemo.Perform(EM_LINESCROLL, myCharIndex - linkCharIndex, myLineIndex - linkLineIndex);
      finally
        LinkedMemo.LinkedMemo := saveLink;
      end;
    end;
    
    procedure TLinkMemo.WMHScroll(var Message: TMessage);
    begin
      inherited;
      if FSkipScroll then begin
        FSkipScroll := False;
        Exit;
      end;
    
      if LinkedMemo <> nil then
        LinkedMemo.DoScroll(Message);
    end;
    
    procedure TLinkMemo.WMVScroll(var Message: TMessage);
    begin
      inherited;
      if FSkipScroll then begin
        FSkipScroll := False;
        Exit;
      end;
    
      if LinkedMemo <> nil then
        LinkedMemo.DoScroll(Message);
    end;

     


  11. OK, next iteration:

    type
      TLinkMemo = class(TMemo)
      private
        FLinkedMemo: TLinkMemo;
        procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
        procedure WMHScroll(var Message: TMessage); message WM_HSCROLL;
        procedure WMVScroll(var Message: TMessage); message WM_VSCROLL;
        procedure SyncLink;
      public
        property LinkedMemo: TLinkMemo read FLinkedMemo write FLinkedMemo;
      end;
    
    procedure TLinkMemo.CNCommand(var Message: TWMCommand);
    begin
      inherited;
      if (Message.NotifyCode = EN_VSCROLL) or (Message.NotifyCode = EN_HSCROLL) then
        SyncLink;
    end;
    
    procedure TLinkMemo.SyncLink;
    begin
      if LinkedMemo = nil then Exit;
    
      var saveLink := LinkedMemo;
      try
        LinkedMemo := nil;
    
        saveLink.CaretPos := CaretPos;
        saveLink.Perform(EM_SCROLLCARET, 0, 0);
    
        var myLine := Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
        var linkLine := saveLink.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
        if myLine = linkLine then Exit;
    
        saveLink.Perform(EM_LINESCROLL, 0, myLine - linkLine);
      finally
        LinkedMemo := saveLink;
      end;
    end;
    
    procedure TLinkMemo.WMHScroll(var Message: TMessage);
    begin
      inherited;
      SyncLink;
    end;
    
    procedure TLinkMemo.WMVScroll(var Message: TMessage);
    begin
      inherited;
      SyncLink;
    end;

     


  12. Just now, Tom Mueller said:

    I wonder how DevExpress handles this, as the scaling works even when the cxImageList is placed on a DataModule.

    I'm not familiar with the DevExpress approach, but I assume the DX controls can request an image of arbitrary size/DPI from an DX image list (probably acting like a VCL TImageCollection). Standard controls based on Windows require an HIMAGELIST at the end, which contains images all of the same size. Compatibility is the limiting factor here.


  13. Usually you connect the actions of such a TActionList to some visual control of a form (TMainMenu, TPopupMenu, TToolBar, TTreeView, TListView ...). Most of these controls have their own property to connect a TVirtualImageList, which should reside on the form itself. The latter is mandatory to make DPI awareness work properly.

     

    It may sound wrong to have separate virtual image lists in each form, which often contain the same content - sometimes the same as the one connected to the ActionList. If you imagine that each each image list can only hold one size of images and each form can have run on a different DPI it becomes clear that this is unavoidable.

     

    While it can be tedious to have all these TVirtualImagelist instances at design time, there are ways to simplify it. If you are interested I suggest reading my blog posts about ImageLists and High DPI

    • Like 1

  14. I can provide an alternative solution:

    type
      TLinkMemo = class(TMemo)
      private
        FLinkedMemo: TLinkMemo;
        procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
        procedure WMVScroll(var Message: TMessage); message WM_VSCROLL;
        procedure SyncLink;
      public
        property LinkedMemo: TLinkMemo read FLinkedMemo write FLinkedMemo;
      end;
    
    procedure TLinkMemo.CNCommand(var Message: TWMCommand);
    begin
      inherited;
      if Message.NotifyCode = EN_VSCROLL then
        SyncLink;
    end;
    
    procedure TLinkMemo.SyncLink;
    begin
      if LinkedMemo = nil then Exit;
    
      var myFirstLine := Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
      var linkFirstLine := LinkedMemo.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
    
      if myFirstLine = linkFirstLine then Exit;
    
      LinkedMemo.Perform(EM_LINESCROLL, 0, myFirstLine - linkFirstLine);
    end;
    
    procedure TLinkMemo.WMVScroll(var Message: TMessage);
    begin
      inherited;
      SyncLink;
    end;

     


  15. type
      TSendParameter = class
      private
        Fpayment_method: TArray<string>;
        Ftransaction_type: string;
        Ffull_name: string;
        Femail: string;
      public
        property email: string read Femail write Femail;
        property full_name: string read Ffull_name write Ffull_name;
        property payment_method: TArray<string> read Fpayment_method write Fpayment_method;
        property transaction_type: string read Ftransaction_type write Ftransaction_type;
      end;
      
      ...
      
      var par := TSendParameter.Create;
      try
        par.payment_method := TArray<string>.Create('credit-card', 'open-banking');
        par.transaction_type := 'SALE';
        par.full_name := 'Joe Blogs';
        par.email := 'etc etc';
        RestReq.AddBody<TSendParameter>(par);
      finally
        par.Free;
      end;

     

    • Like 1

  16. In MMX options select Pascal - Sorting. In the group Format unit uses clauses check Group and sort uses clause. Next time you execute Format Uses Clause (Ctrl-Alt-U) the unit names are resolved based on the current Unit Scope Names of the current project.

     

    If you don't want the grouping you can simply empty the Groups entry in MMX Project options.

×