Jump to content

aehimself

Members
  • Content Count

    1030
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by aehimself


  1. 1 hour ago, PeterBelow said:

    Have you tried to just set DefAttributes.Color  before calling the inherited StreamIn method? SelAttributes.ConsistentAttributes may also be of use if you really need to manually correct the font color.

    Yes, and unfortunately loading the stream overwrites this setting; it has no effect in the new document being loaded.

    My issue with ConsistentAttributes is that it needs a selection - and for that I need to reposition the cursor again, most probably ending up at the same slowdown.

     

    I'm attempting to experiment with EM_GETTEXTRANGE but unfortunately it doesn't seem to care about formatting at all, just returns as many characters as I desire.


  2. First of all, do a WriteLn('d.exe -b '+e1.Text+'d.exe -a '+e2.Text+'d.exe -c'+e3.Text+'d.exe -s'+e4.Text+'-d PATH_OF_DEVICE_A') and ensure that the command executes successfully.

    Next, make sure ExtractFilePath(application.ExeName) + 'bin\' folder exists (I suppose this is the "working directory".

    Finally, make sure that all the external files you reference in the command line are using ABSOLUTE paths, otherwise they must be present in the working directory.

     

    As @FPiette mentioned, neither GetDosOutput or TMemoAppendStream exists in Delphi by default. While we can guess what they do, we cannot guess their implementation. It's possible that your call is correct, only these implementations are buggy.


  3. 15 hours ago, direktor05 said:

    Then I get to "animals":[{"id".... now here gets complicated. How do I parse further to get ID and name? Parse Json further or parse Json Array? Can someone help with some example code please?

    Let's say you have a TJSONObject variable which holds the inmost object only (id and name) named innerjson:

    if innerjson.GetValue('id') <> null then fid := (innerjson.GetValue('id') As TJSONNumber).AsLargeInt;
    if innerjson.GetValue('name') <> null then fname := (innerjson.GetValue('name') As TJSONString).Value;

    if you are sure that these will always be present, you can discard the nullcheck.


  4. I really do suspect that this is a bug. The color of uncolored text is clWindowText, it's just RichEdit is rendering it in a wrong color.

    I'm not good with StyleHooks to actually fix it... I did find a workaround and however it works, it's painfully slow:

      TMyRichEdit = Class(Vcl.ComCtrls.TRichEdit)
      strict private
        Procedure StreamIn(Var Msg: TMessage); Message EM_STREAMIN;
      End;
    
    Procedure TMyRichEdit.StreamIn(Var Msg: TMessage);
    Var
      a: Integer;
    Begin
      inherited;
    
      Self.LockDrawing;
      Try
        Self.SelStart := Integer.MaxValue;
    
        For a := 0 To Self.SelStart Do
        Begin
          Self.SelStart := a;
          If Self.SelStart <> a Then
            Continue;
    
          Self.SelLength := 1;
          If Self.SelAttributes.Color = clWindowtext Then
            Self.SelAttributes.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal);
        End;
    
        Self.SelStart := 0;
      Finally
        Self.UnlockDrawing;
      End;
    End;

    The amount of .SelStart is causing the slowdown. Does anyone know how I can extract the start and end of consecutive blocks, where all formatting is the same? That should speed things up a LOT.

     

    I'll look into how exactly RichEdit is setting the properties of SelAttributes - maybe I can extract the attribute at a specific location without having to move the cursor, that way the only SelStart - SelLength would be at blocks what I actually have to change.


  5. Are you in control of both the data and the header? If yes, open the file for writing in your preferred method (AssignFile, TFiles, TFileStream) and write the header, then the data.

     

    If you get a file from an external source and you need to add a header, the easiest solution is a stream. Write your header and then copy the data from said file, loaded in a TFileStream.

     

     If you receive one header files and need to append data, all 3 methods (AssignFile, TFile, TFileStream) can append binary data to it.


  6. I never checked, but isn’t the Delphi localization file a regular resource DLL, without code?

     

    If this is the case (and your source is not IFDEF-ing resource stings) the same file can be used by 32 and 64 bit applications. Afaik a new DLL is only required if there is ANY code (including self-extracting, like UPX).


  7. 49 minutes ago, Fr0sT.Brutal said:

    Generics are with us since D2009 and you unlikely want to support something older as it will require too much manual job.

     

    Impressive project! Glad to see my stack trace unit 🙂 you'll probably want to update its code from https://github.com/Fr0sT-Brutal/Delphi_StackTraces/blob/master/Ice.Debug.pas since it has an improvement of excluding non-relevant entries and better comments

    There are lots of people who dislike Generics and would like to avoid having them in their projects. Using a standard TList and casting pointers can be an easy solution. In theory this whole thing could be D7 compatible if I'd invest enough free time in it. We'll see.

     

    So the author of said stack trace unit was you? 🙂 I remember having it for ages without any sign of where / who it came from so I can give appropriate credit. There were also some cyrillic characters in it which threw me totally off. As it seems it grew a lot, and since the new version is on GitHub it's easier just to remove it from mine.

    I don't like redundancy.


  8. The whole thing started with this topic. Due to lack of possibilities, I wrote my own update mechanism which noes not rely on any advanced stuff but still should be versatile enough.

     

    Since the initial version TAEUpdater got some improvements and things are looking great. Some more stuff was implemented like hash-based verification, messages, E-tag caching, separate internal, development and production channels, ability to downgrade to a previous version, etc. I'm running it in my main application for a while and it seems to do the job correctly.


    Since not all of us might update from an unauthenticated web server, now 3 different file providers are shipped: HTTP, flatfile and custom. HTTP uses Delphi's TNetHTTPClient, flatfile reads the files from a local disk and custom has all necessary events exposed via events. I also got rid of some personal dependencies (like compressing the update file or using System.Zip2) and now everything is handed to the user for the solution to be more... generic. I still use my own version discovery and comparison method to be able to determine which published one is "newer" but that is going to be my next step. As a workaround, you can call .LoadUpdateFile, check the new version in each ActualProduct.Files and call .Update manually.

     

    What it needs:

    - An update file containing the product, all its files and versions. You can build this with TAEUpdateFile.SaveToStream in AE.Updater.UpdateFile.pas

    - Update packages, which can be zipped or encrypted, on FTP, HTTP, custom protocol - doesn't matter as events should be in place for performing all these actions

     

    Plans for the future:

    - Getting rid of more dependencies, maybe it'll become a standalone updater package with no extras

    - By accomplishing the above the code will get closer and closer to be truly cross-platform (atm it's WIndows only)

    - Get rid of modern stuff (like generics) and implement proper versioning conditionals so the package can be compiled and installed on anything other than D11.2

    - Really, really basic documentation on how to use...

     

    Disclaimer: further changes are on their way. I'll possibly add / remove events / splitting the component in multiple subcomponents which might make existing .DFMs failing to be streamed. Also, publish your new versions on the Internal channel if I might break the core functionality 😞

     

    All words as one - I just wanted to give the existing Delphi community a chance to implement auto-updating feature to their applications without having to pay for the component or the backend. Feel free to check it out. And suggest ways of improvement of course 🙂

    • Like 4
    • Thanks 1

  9. 13 hours ago, Remy Lebeau said:

    You can add a message handler to the Frame class to handle the CM_DESIGNHITTEST message, setting the message's result to 1 if the mouse is over a child control within the Frame's client area.  That will allow the child control to handle the mouse click.

    I'm experimenting with this but I can not seem to get it to work.

    procedure TMyTempComponent.HitTest(Var Msg: TCMDesignHitTest);
    begin
    //  ShowMessage('Edit1.BoundsRect.Top: ' + Edit1.BoundsRect.Top.ToString + sLineBreak +
    //              'Edit1.BoundsRect.Left: ' + Edit1.BoundsRect.Left.ToString + sLineBreak +
    //              'Edit1.BoundsRect.Bottom: ' + Edit1.BoundsRect.Bottom.ToString + sLineBreak +
    //              'Edit1.BoundsRect.Right: ' + Edit1.BoundsRect.Right.ToString + sLineBreak + sLineBreak +
    //              'Msg.XPos: ' + Msg.XPos.ToString + sLineBreak +
    //              'Msg.YPos: ' + Msg.YPos.ToString);
      If PtInRect(Edit1.BoundsRect, Point(Msg.XPos, Msg.YPos)) Then
        Msg.Result := 1
      Else
        Msg.Result := 0;
    end;

    The event does not fire at all if I move the cursor over any child component (Edit, button or radiogroup) only when it is over the frame itself. I also tried adding

    ControlStyle:= ControlStyle - [csDesignInteractive];

    in the constructor.

     

    I'll keep trying, but am I on the right track here? Maybe frames are just work... different? 🙂

     


  10. 4 minutes ago, Attila Kovacs said:

    just being the smart*ss, why are you mixing composite components with frames? can't you just put a frame onto an another frame?

    This is why 🙂

    12 hours ago, aehimself said:

    I suppose this is a limitation, I shouldn't design my custom component on a frame. How else can I achieve graphical designability in the IDE and how can I force for example a dxBarManager toolbars to stay within the components boundaries?

     


  11. 8 hours ago, Uwe Raabe said:

    Can you show the code for the custom component?

    Sure. There is no code whatsoever:

    unit TempComponent;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
      Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
      Vcl.ExtCtrls;
    
    type
      TMyTempComponent = class(TFrame)
        Edit1: TEdit;
        Button1: TButton;
        RadioGroup1: TRadioGroup;
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    Procedure Register;
    
    implementation
    
    Procedure Register;
    Begin
      RegisterComponents('Temp component', [TMyTempComponent]);
    End;
    
    {$R *.dfm}
    
    end.


     


  12. Hello,

     

    Let's imagine the following scenario. I made a custom component which resides on a VCL frame. First of all, it's a lot easier to design something if you can see it (hence no TPanel) and some components require a form or a frame as a parent.

    It looks like this:

     

    image.png.f0bc1ba39665a7b121ae6d93003f7307.png

     

    Install it to the IDE and create a new application. Place this component on the form.

     

    Issue #1:

    You can not select individual components, any click with the mouse will select the whole frame instead. This is not a big thing, as you still can select its child components in the Structure pane.

     

    image.thumb.png.2404ca71b9644df94dfb7c5ef75160a1.png

     

    Now, save your project in an empty git repository and commit once, so you can compare the differences. Load up the project again, select the TEdit and enter something as it's Text property:

     

    image.png.9c674cf747f64509a3993033994d8426.png

     

    Save your project again and check the differences in the DFM:

    image.png.dbbaf85df1494669a9d6e3940cbe8d03.pngimage.png.27ad45d26c8a748c15dcbb3dc6e65783.png

     

    Issue #2:

    All property changes in the components children are simply discarded.

    I can get around this one too by setting these in runtime, but it's less convenient that directly in the IDE.

     

    I suppose this is a limitation, I shouldn't design my custom component on a frame. How else can I achieve graphical designability in the IDE and how can I force for example a dxBarManager toolbars to stay within the components boundaries?

    I'm also interested about the reason why these things happen, if someone knows by heart.

     

    Cheers!


  13. Hello,

     

    I recently started to experiment with Delphi's TRichEdit control. There is one thing left which I don't know if I'm doing it right; and that's to 'repaint' the document to follow VCL styles.

    RTF seems to include the generic text color, which is dark if the document was exported with a light / Windows style. If you load the same document back to a RichEdit, which has a dark style active the text will be unreadable.

     

    The solution was rather easy:

      ro := RichEdit.ReadOnly;
      Try
        RichEdit.ReadOnly := False;
        RichEdit.Lines.LoadFromStream(myStream);
        RichEdit.DefAttributes.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal);
        RichEdit.Modified := False;
      Finally
        RichEdit.ReadOnly := ro;
      End;

    First, I need to make the RichEdit non-read only, otherwise pictures won't show up in the loaded document. Then, load the stream and change the default color according to the current style. Then simply reset the Modified to false and ReadOnly to the original value.

    This all seems to work but with this, even hyperlinks are recolored to the default color. They retain their link attributes and formatting, only the color is lost.

     

    Is this a normal phenomenon? Should I parse the whole document and recolor all links from code? Or I'm simply loading / saving the document the wrong way?

     

    I appreciate all tips 🙂

    Thanks!


  14. For anyone interested I solved this without writing an actual interpreter, it parses all select aliases. The backdraw is that it offers aliases to use in statements where there is no such alias therefore executing the statement will throw an exception. This annoyance is perfectly acceptable by me, so probably I'll just leave it as it is.

     

    It derives a new analyzer from Zeos's generic analyzer, and it looks like this:

    Unit uAEGenericSqlAnalyser;
    
    Interface
    
    Uses ZGenericSqlAnalyser, ZTokenizer, ZSelectSchema;
    
    Type
      TAEGenericSqlAnalyser = Class(TZGenericStatementAnalyser)
      public
        Function DefineAllSelectSchemaFromQuery(const Tokenizer: IZTokenizer; const SQL: string): TArray<IZSelectSchema>;
      End;
    
    Implementation
    
    Uses System.Contnrs, System.Classes;
    
    Function TAEGenericSqlAnalyser.DefineAllSelectSchemaFromQuery(Const Tokenizer: IZTokenizer; Const SQL: string): TArray<IZSelectSchema>;
    Var
      Tokens: TZTokenList;
      sections: TObjectList;
      ss: IZSelectSchema;
      FromTokens: TZTokenList;
      deleted: Boolean;
    Begin
      SetLength(Result, 0);
    
      Tokens := TokenizeQuery(Tokenizer, SQL, True);
      Sections := SplitSections(Tokens);
      Try
        Repeat
          ss := DefineSelectSchemaFromSections(Sections);
          If Assigned(ss) Then
          Begin
            SetLength(Result, Length(Result) + 1);
            Result[High(Result)] := ss;
    
            FromTokens := FindSectionTokens(Sections, 'FROM');
    
            deleted := False;
            While (Sections.Count > 0) And Not deleted Do
            Begin
              deleted := TZStatementSection(sections[0]).Tokens = FromTokens;
              Sections.Delete(0);
            End;
          End;
        Until ss = nil;
      Finally
        Tokens.Free;
        Sections.Free;
      End;
    End;
    
    End.

     

    To use it:

    Procedure TForm1.GetTableName(Var inNameOrAlias: String);
    Var
      sa: TAEGenericSqlAnalyser;
      sch: IZSelectSchema;
      a: Integer;
    Begin
      sa := TAEGenericSqlAnalyser.Create;
      Try
        For sch In sa.DefineAllSelectSchemaFromQuery(SQLConnection.DbcConnection.GetTokenizer, SQLCommand) Do
          For a := 0 To sch.TableCount - 1 Do
            If sch.Tables[a].Table.ToLower = inNameOrAlias.ToLower Then
              Exit
            Else If sch.Tables[a].Alias.ToLower = inNameOrAlias.ToLower Then
            Begin
              inNameOrAlias := sch.Tables[a].Table;
              Exit;
            End;
      Finally
        FreeAndNil(sa);
      End;
    End;

    SQLConnection is a TZConnection object (can be replaced with TZTokenizer.Create if no connection is available), SQLCommand is the string containing all the statements. Simply call this method to "convert" an alias to a table name.

     

    It can be optimized but since it's already pretty quick, I didn't really bother.

    Yeah, extracting the current block would be more elegant. In 1 hours with minimal personal code, this is what I could achieve 🙂


  15. I was afraid of this so.

     

    I do use ZeosLib. The main purpose I'm interested about the current command is to parse table aliases (which Zeos is kind enough to do so) but I need to be able to provide the current command only - otherwise it only considers the first one. Even though if I can split up to separate commands, I somehow need to confirm if that is the command under the cursor...


  16. Hello,

     

    I'm using TurboPack SynEdit latest version, fresh from GitHub. I have an editor where the user can enter multiple SQL commands, like:

     

    SELECT * FROM MYTABLE

    SELECT * FROM OTHERTABLE o

    [...]

     

    Is there a way SynEdt can return the full block, but the current command only? So, if the cursor is staying in line 1 just return "SELECT * FROM MYTABLE" but at line 2 it would "SELECT * FROM OTHERTABLE o"? Keep in mind that commands can be split across several lines, so simply returning the current line is not a good solution.

     

    Summoning @pyscripter 🙂


  17. So, the issue had nothing to do with the panel, but a label on it... and by replacing it from TLabel to TcxLabel to be precise.

     

    There was a section in the constructor which looked like this:

    With TLabel.Create Do
    Begin
      // [...]
      If criteria Then
        Color := clRed;
    End;

    This was fine but in the moment someone changed it with cxLabel (which has no public .Color property) that one line immediately turned ParentBackground off on the panel as it changed it's color instead of the labels.

     

    This is one reason I hate With blocks 😞

     

×