Results 1 to 8 of 8

Thread: Left en Top instellen van TComponent bij plaatsen op een form

  1. #1
    Member
    Join Date
    Aug 2003
    Location
    Vlaardingen
    Posts
    89

    Left en Top instellen van TComponent bij plaatsen op een form

    Hallo,

    Ik heb een TComponent afstammeling gemaakt die als subcomponent een TADOConnection heeft.
    Een TADOConnection stamt af van een TComponent en heeft geen Left en Top property.
    Echter bij het plaatsen van een gewone TADOConnection op een form wordt in de form file wel Left en Top weggeschreven.
    Als ik mijn TComponent afstammeling op het form plaats wordt de ADOConnection in linkerbovenhoek geplaatst van het form,
    het maakt niet waar ik de muis neerzet bij het plaatsen.

    Weet iemand hoe je een TComponent afstammeling toch op gewenste plek op het form kan plaatsen. Terwijl die TComponent een subcomponent is?

    Groet,

    Sjoerd

  2. #2
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,665
    TADOConnection is toch geen GUI component, dus waarom zal deze een left/top moeten hebben?
    Delphi is great. Lazarus is more powerfull

  3. #3
    Member
    Join Date
    Aug 2003
    Location
    Vlaardingen
    Posts
    89
    Quote Originally Posted by jkuiper View Post
    TADOConnection is toch geen GUI component, dus waarom zal deze een left/top moeten hebben?
    Wat ik wil is dat je in designtime in 1 keer meerdere TComponents op je form kan plaatsen die dan netjes naast elkaar staan.
    Bijvoorbeeld. een TADOConnection, een TADOQuery en een TDataSource netjes naast elkaar met de belangrijkste properties al ingesteld.
    Met de oplossing die ik nu heb zouden de drie componenten over elkaar heen geplaatst worden in de linkerbovenhoek van het form.
    Last edited by ActiveS; 09-Oct-19 at 10:37.

  4. #4
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,496
    Quote Originally Posted by jkuiper View Post
    dus waarom zal deze een left/top moeten hebben?
    Om hem @runtime een vaste plek te geven op je form of datamodule, anders zouden alle dergelijke componenten
    kriskras door elkaar of over elkaar heen staan; deze waarde wordt ook voor niet visuele componenten opgeslagen
    in de dfm.
    Delphi Code:
    1. object dmKuiper: TdmKuiper
    2.   OldCreateOrder = False
    3.   OnCreate = DataModuleCreate
    4.   Height = 637
    5.   Width = 789
    6.   object JohnConnection: TADOConnection
    7.     CommandTimeout = 300
    8.     ConnectionString =
    9.       'Provider=SQLOLEDB.1;Password=G3h3!m;Persist Security Info=True' +
    10.       ';User ID=sa;Initial Catalog=master;Data Source=JKUIPER\SQLEXPR' +
    11.       'ESS'
    12.     LoginPrompt = False
    13.     Provider = 'SQLOLEDB.1'
    14.     Left = 48
    15.     Top = 464
    16.   end
    17. end

    De .Left en .Top-properties worden normaal automagisch naar dfm weggeschreven via de private .WriteLeft() en
    .WriteTop()-methods en weer ingelezen met .ReadLeft() en .ReadTop binnen de TComponent klasse.
    Heb je hier wellicht aan lopen morrelen en is je eigen component écht een afstammeling van TComponent?

    Quote Originally Posted by ActiveS View Post
    Wat ik wil is dat je in designtime in 1 keer meerdere TComponents op je form kan plaatsen die dan netjes naast elkaar staan.
    Dit werkt zo niet, je krijgt dan drie componenten binnen een enkel component: je ziet er dan nog steeds maar
    één op je form staan.
    Last edited by VideoRipper; 09-Oct-19 at 10:49.
    TMemoryLeak.Create(Nil);

  5. #5
    Quote Originally Posted by ActiveS View Post
    Weet iemand hoe je een TComponent afstammeling toch op gewenste plek op het form kan plaatsen. Terwijl die TComponent een subcomponent is?
    Even ter extra informatie. ALLE componenten bevatten een DesignInfo property. Deze bevatten de gewenste Left en Top voor op het form en worden inderdaad in de dfm geschreven.

    Left := LongRec(YourComponent.DesignInfo).Lo
    Top := LongRec(YourComponent.DesignInfo).Hi

    https://stackoverflow.com/questions/...phi-components

  6. #6
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,665
    Ja, Peter, maar niet als published property. @runtime is dat ook overbodig, omdat het geen visueel component is en niet wordt getoond @runtime.
    Daarom is left/top niet relevant. Dat het in de stream wordt opgeslagen is enkel dat de IDE weet waar deze staat. Ook handig voor jezelf dat deze niet op een visual component staat, maar op een veilige plaats zonder hinder te hebben.
    Delphi is great. Lazarus is more powerfull

  7. #7
    Member
    Join Date
    Aug 2003
    Location
    Vlaardingen
    Posts
    89
    Quote Originally Posted by rvk View Post
    Even ter extra informatie. ALLE componenten bevatten een DesignInfo property. Deze bevatten de gewenste Left en Top voor op het form en worden inderdaad in de dfm geschreven.

    Left := LongRec(YourComponent.DesignInfo).Lo
    Top := LongRec(YourComponent.DesignInfo).Hi

    https://stackoverflow.com/questions/...phi-components
    Code:
    type
      TMyComponent = class(TComponent)
      public
        FSubComponent: TComponent;
        FSubComponent2: TComponent;
      public
        constructor Create(AOwner:TComponent); override;
    end;
    
    procedure Register;
    
    implementation
    constructor TMyComponent.Create(AOwner: TComponent);
    begin
      FSubComponent:=TComponent.Create(AOwner);
      FSubComponent.Name:='Component'+IntToStr(FSubcomponent.ComponentIndex);
      FSubComponent.DesignInfo := 200;
    
      FSubComponent2:=TComponent.Create(AOwner);
      FSubComponent2.Name:='Component2'+IntToStr(FSubcomponent.ComponentIndex);
      FSubComponent2.DesignInfo := 100;
     end;
    
    procedure Register;
    begin
      RegisterComponents('ComponentAfstammeling', [TMyComponent]);
    end;
    Dit werkt alleen het is wel noodzakelijk om het form direct na het plaatsten op te slaan, zodat de TComponents op de gewenste plek komen te staan.
    Weet iemand een methode om het form gelijk te refreshen zonder op te slaan?

  8. #8
    Member
    Join Date
    Aug 2003
    Location
    Vlaardingen
    Posts
    89
    Quote Originally Posted by rvk View Post
    Even ter extra informatie. ALLE componenten bevatten een DesignInfo property. Deze bevatten de gewenste Left en Top voor op het form en worden inderdaad in de dfm geschreven.

    Left := LongRec(YourComponent.DesignInfo).Lo
    Top := LongRec(YourComponent.DesignInfo).Hi

    https://stackoverflow.com/questions/...phi-components
    Het is gelukt uiteindelijk Dankzij de stackoverflow link. Hieronder staat de code. Het zit hem in de SetNonVisualPos procedure.

    Bedankt voor de hulp!

    Code:
    unit unitTComponentAfstammeling;
    
    interface
    
    uses System.Classes, Vcl.ExtCtrls, System.SysUtils, Vcl.Forms, Winapi.Windows, Vcl.Controls;
    
    type
      TMyComponent = class(TComponent)
      public
        FSubComponent: TComponent;
        FSubComponent2: TComponent;
      public
        procedure SetNonVisualPos(Form: TCustomForm; Component: TComponent; X, Y: Integer);
        constructor Create(AOwner:TComponent); override;
    end;
    
    procedure Register;
    
    implementation
    
    constructor TMyComponent.Create(AOwner: TComponent);
    var NewDesignInfo:LongRec;
    begin
      FSubComponent:=TComponent.Create(AOwner);
      FSubComponent.Name:='Component'+IntToStr(FSubcomponent.ComponentIndex);
      SetNonVisualPos(TCustomForm(AOwner),FSubComponent,100,100);
    
      FSubComponent2:=TComponent.Create(AOwner);
      FSubComponent2.Name:='Component2'+IntToStr(FSubcomponent.ComponentIndex);
      SetNonVisualPos(TCustomForm(AOwner),FSubComponent2,200,200);
    end;
    
    
    procedure TMyComponent.SetNonVisualPos(Form: TCustomForm; Component: TComponent; X, Y: Integer);
    const
      NonvisualClassNamePattern = 'TContainer';
      csNonVisualSize = 28;
      csNonVisualCaptionSize = 14;
      csNonVisualCaptionV = 30;
    var
      P: TSmallPoint;
      H1, H2: HWND;
      Offset: TPoint;
    
      function HWndIsNonvisualComponent(hWnd: hWnd): Boolean;
      var
        AClassName: array[0..256] of Char;
      begin
        AClassName[GetClassName(hWnd, @AClassName, SizeOf(AClassName) - 1)] := #0;
        Result := string(AClassName) = NonvisualClassNamePattern;
      end;
    
      procedure GetComponentContainerHandle(AForm: TCustomForm; L, T: Integer; var H1, H2: hWnd; var Offset: TPoint);
      var
        R1, R2: TRect;
        P: TPoint;
        ParentHandle: hWnd;
        AControl: TWinControl;
        I: Integer;
      begin
        ParentHandle := AForm.Handle;
        AControl := AForm;
        if AForm.ClassNameIs('TDataModuleForm') then // ÊÇ DataModule
        begin
          for I := 0 to AForm.ControlCount - 1 do
            if AForm.Controls[I].ClassNameIs('TComponentContainer')
            and (AForm.Controls[I] is TWinControl) then
            begin
              AControl := AForm.Controls[I] as TWinControl;
              ParentHandle := AControl.Handle;
              Break;
            end;
        end;
        H2 := 0;
        H1 := GetWindow(ParentHandle, GW_CHILD);
        H1 := GetWindow(H1, GW_HWNDLAST);
        while H1 <> 0 do
        begin
          if HWndIsNonvisualComponent(H1) and GetWindowRect(H1, R1) then
          begin
    
            P.x := R1.Left;
            P.y := R1.Top;
            P := AControl.ScreenToClient(P);
    
            if (P.x = L) and (P.y = T) and (R1.Right - R1.Left = csNonVisualSize)
            and (R1.Bottom - R1.Top = csNonVisualSize) then
            begin
              H2 := GetWindow(ParentHandle, GW_CHILD);
              H2 := GetWindow(H2, GW_HWNDLAST);
              while H2 <> 0 do
              begin
                if HWndIsNonvisualComponent(H2) and GetWindowRect(H2, R2) then
                begin
                  if (R2.Top - R1.Top = csNonVisualCaptionV) and (Abs(R2.Left + R2.Right - R1.Left - R1.Right) <= 1)
                  and (R2.Bottom - R2.Top = csNonVisualCaptionSize) then
                  begin
                    Offset.x := R2.Left - R1.Left;
                    Offset.y := R2.Top - R1.Top;
                    Break;
                  end;
                end;
                H2 := GetWindow(H2, GW_HWNDPREV);
              end;
              Exit;
            end;
          end;
          H1 := GetWindow(H1, GW_HWNDPREV);
        end;
      end;
    
    begin
      P := TSmallPoint(Component.DesignInfo);
      GetComponentContainerHandle(Form, P.x, P.y, H1, H2, Offset);
      Component.DesignInfo := Integer(PointToSmallPoint(Point(X, Y)));
      if H1 <> 0 then
        SetWindowPos(H1, 0, X, Y, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
      if H2 <> 0 then
        SetWindowPos(H2, 0, X + Offset.x, Y + Offset.y, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
    end;
    
    procedure Register;
    begin
      RegisterComponents('ComponentAfstammeling', [TMyComponent]);
    end;
    
    end.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •