Autor Téma: Delphi 7 component layout  (Přečteno 1991 krát)

JJ

  • Host
Delphi 7 component layout
« kdy: 07-03-2013, 03:57:15 »
Ahoj, po dlouhé době (a doufám že na dlouhou dobu naposled) jsem se pustil do programování v prehistorických Delphi 7 a zasekl jsem se na jedné věci. Potřebuju navrhnout komponentu skládající se z panelu, groupboxu a v něm budou další komponenty jako list, tlačítka.. Protože jsem nepřišel na to, jak to navrhnout vizuálně, zkouším to celé nakódovat. Mám panel, do něj umístím groupbox a do něj listbox. Komponenta pak vypadá při návrhu normálně. Ale při spuštění programu se listbox roztáhne přes celou plochu panelu a ignoruje okraje a svou původní velikost. Systém mám Win 7 64 bit. Díky za každou radu.

komponenta vložená na formulář: http://i.imgur.com/cb7jZ9Q.png
po spuštění: http://i.imgur.com/ghbYu4U.png

kód komponenty:

Kód: Delphi [Vybrat]
  1. unit PanelFilters;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Classes, Controls, ExtCtrls, StdCtrls, IniFiles;
  7.  
  8. Const
  9.   DEFAULT_WIDTH = 297;
  10.   DEFAULT_HEIGHT = 217;
  11.   BUTTON_WIDTH = 75;
  12.   BUTTON_HEIGHT = 25;
  13.  
  14. type
  15.   TPanelFilters = class(TPanel)
  16.   private                      
  17.     { Private declarations }
  18.     //...
  19.  
  20.     GroupBoxFilters : TGroupBox;
  21.     ListBoxFilters:TListBox;
  22.  
  23.     //...
  24.     procedure AddComponents;
  25.   protected
  26.     { Protected declarations }
  27.   public
  28.     { Public declarations }
  29.     constructor Create(AOwner: TComponent); override;
  30.     destructor  Destroy; override;
  31.   published
  32.     { Published declarations }
  33.     //...
  34.   end;
  35.  
  36. procedure Register;
  37.  
  38. implementation
  39.  
  40. constructor TPanelFilters.Create(AOwner: TComponent);
  41. begin
  42.   inherited Create(AOwner);
  43.  
  44.   Caption := '';
  45.   Width := DEFAULT_WIDTH;
  46.   Height := DEFAULT_HEIGHT;
  47.   Visible := true;
  48.  
  49.  
  50.   AddComponents;
  51.  
  52.  
  53.   //...
  54. end;
  55.  
  56. destructor TPanelFilters.Destroy;
  57. begin
  58.   //...
  59.   inherited;
  60. end;
  61.  
  62. procedure Register;
  63. begin
  64.   RegisterComponents('MOJE', [TPanelFilters]);
  65. end;
  66.  
  67. procedure TPanelFilters.AddComponents;
  68. var
  69.   padding : Integer;
  70. begin
  71.   padding := 0;
  72.  
  73.   GroupBoxFilters := TGroupBox.Create(Self);
  74.   with GroupBoxFilters do
  75.   begin
  76.     Parent := Self;
  77.     Caption := 'Filtry';
  78.     Left := padding;
  79.     Top := padding;
  80.     //Width := Parent.ClientWidth - 2 * padding;
  81.     Width := DEFAULT_WIDTH;
  82.     Constraints.MinWidth := 75;
  83.     Height := DEFAULT_HEIGHT;
  84.     Anchors := [akLeft, akRight, akTop, akBottom];
  85.     Visible := true;
  86.   end;
  87.  
  88.   padding := 8;
  89.  
  90.   ListBoxFilters := TListBox.Create(GroupBoxFilters);
  91.   with ListBoxFilters do
  92.   begin
  93.     Parent := GroupBoxFilters;
  94.     Left := padding;
  95.     Top := 2 * padding;
  96.     Width := GroupBoxFilters.Width - 2 * padding;
  97.     Height := GroupBoxFilters.Height - 3 * padding;
  98.     Anchors := [akLeft, akRight, akTop, akBottom];
  99.     Visible := true;
  100.     AutoSize := false;
  101.   end;
  102. end;
  103.  
  104. //...
  105.  
  106. end.
  107.  

Offline KarelHorky

  • Plnoletý
  • ***
  • Příspěvků: 214
  • Karma: 9
    • Verze Delphi: XE6, Delphi 10.2 Tokyo
Re:Delphi 7 component layout
« Odpověď #1 kdy: 07-03-2013, 07:56:15 »
Nejdřív bych zkusil nastavit Align na alNone.
Win10 Prof 64b, Firebird 2.5

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Delphi 7 component layout
« Odpověď #2 kdy: 07-03-2013, 08:07:21 »
Na Align a Anchors bych se určitě vykašlal. Udělej to natvrdo při Resize:

Kód: Delphi [Vybrat]
  1.   TPanelFilters = class(TPanel)
  2.   private
  3.     { Private declarations }
  4.     //...
  5.  
  6.     GroupBoxFilters : TGroupBox;
  7.     ListBoxFilters:TListBox;
  8.  
  9.     //...
  10.     procedure AddComponents;
  11.     procedure AlignComponents;
  12.   protected
  13.     { Protected declarations }
  14.     procedure SetParent(AParent: TWinControl); override;
  15.   public
  16.     { Public declarations }
  17.     constructor Create(AOwner: TComponent); override;
  18.     destructor  Destroy; override;
  19.  
  20.     procedure Resize; override;
  21.   published
  22.     { Published declarations }
  23.     //...
  24.   end;
  25.  

Kód: Delphi [Vybrat]
  1. procedure TPanelFilters.AlignComponents;
  2. const
  3.   xPadding = 8;
  4. begin
  5.   if Parent = nil then
  6.     exit;
  7.  
  8.   GroupBoxFilters.SetBounds(0, 0, Self.ClientWidth, Self.ClientHeight);
  9.  
  10.   ListBoxFilters.SetBounds(
  11.     xPadding,
  12.     2*xPadding,
  13.     GroupBoxFilters.ClientWidth - 2 * xPadding,
  14.     GroupBoxFilters.ClientHeight - 3 * xPadding);
  15.  
  16. end;
  17.  
  18. constructor TPanelFilters.Create(AOwner: TComponent);
  19. begin
  20.   inherited Create(AOwner);
  21.  
  22.   Caption := '';
  23.   Width := DEFAULT_WIDTH;
  24.   Height := DEFAULT_HEIGHT;
  25.   Visible := true;
  26.   BevelOuter := bvNone;
  27.   Constraints.MinWidth := 75;
  28.  
  29.  
  30.   AddComponents;
  31.  
  32.  
  33.   //...
  34. end;
  35.  
  36. destructor TPanelFilters.Destroy;
  37. begin
  38.   //...
  39.   inherited;
  40. end;
  41.  
  42. procedure TPanelFilters.Resize;
  43. begin
  44.   inherited;
  45.  
  46.   AlignComponents;
  47. end;
  48.  
  49. procedure TPanelFilters.SetParent(AParent: TWinControl);
  50. var
  51.   xChange: Boolean;
  52. begin
  53.   xChange := (AParent <> Parent) and (AParent <> nil);
  54.  
  55.   inherited;
  56.  
  57.   if xChange then
  58.     AlignComponents;
  59. end;
  60.  
  61. procedure TPanelFilters.AddComponents;
  62. begin
  63.   GroupBoxFilters := TGroupBox.Create(Self);
  64.   with GroupBoxFilters do
  65.   begin
  66.     Parent := Self;
  67.     Caption := 'Filtry';
  68.     Visible := true;
  69.   end;
  70.  
  71.   ListBoxFilters := TListBox.Create(GroupBoxFilters);
  72.   with ListBoxFilters do
  73.   begin
  74.     Parent := GroupBoxFilters;
  75.     Visible := true;
  76.     AutoSize := false;
  77.   end;
  78. end;
  79.  

Popřípadě taky můžeš využít tuto funkci (z TWinControl):
Kód: Delphi [Vybrat]
  1.     procedure AlignControls(AControl: TControl; var Rect: TRect); virtual;
  2.  

Ale Resize je taky úplně v poho.
« Poslední změna: 07-03-2013, 08:24:40 od oxo »
Embarcadero Technology Partner

Offline < z >

  • Administrátoři
  • Guru
  • *****
  • Příspěvků: 1145
  • Karma: 44
    • Verze Delphi: 7, 2010
Re:Delphi 7 component layout
« Odpověď #3 kdy: 07-03-2013, 10:02:19 »
nesdilim vase opovrzeni Align ;)

zakladni chyba je pouziti "padding" s pevnou hodnotou vzhledem k tomu,
ze okraje mohou byt vykreslovany v zavislosti na tematu Woken

nejcistsim resenim je udelat groupbox, do nej vlozit panel s Align alClient a do nej pak vlozit listbox taky s alClient,
jak je znamo, panel ma border

tim si lze usetrit tunu prace ... jinak jsem kod zkousel v beznym kodu a jede to normalne, takze tezko rict,
cim presne je to zpusobene

Offline KarelHorky

  • Plnoletý
  • ***
  • Příspěvků: 214
  • Karma: 9
    • Verze Delphi: XE6, Delphi 10.2 Tokyo
Re:Delphi 7 component layout
« Odpověď #4 kdy: 07-03-2013, 10:55:02 »
Citace
Na Align a Anchors bych se určitě vykašlal. Udělej to natvrdo při Resize
Pokud nebude Align na alNone, můžeš resizovat kolik chceš, ale stejně se to bude roztahovat samo podle Align. Nejdřív vypnout Align (nebo jej rozumně použít  :) ) a potom začít natvrdo resizovat.
Win10 Prof 64b, Firebird 2.5

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Delphi 7 component layout
« Odpověď #5 kdy: 07-03-2013, 11:46:50 »
Karle, nevšiml jsem si, že by JJ měl v původním kódu nastaveno Align na cokoliv jiného než defaultní hodnotu - tudíž alNone. Takže máš sice pravdu (to nikdo nezpochybňuje), ale není to relevantní. Mimochodem, pokud budeš resizovat pomocí procedury AlignControls, tak si můžeš dělat co chceš, align nealign ;)

Ad <z>: Já nepohrdám align... ale pokud chci použít padding v D7 tak tak mi align prostě moc nepomůže.
TPanel tady používá jako kontejner, což je víceméně v pořádku. Stačí vypnout border u panelu (viz BevelOuter := bvNone;), a nastavit ParentBackground na True (na to jsem asi zapomněl) a je to.
Ale je pravda, že pro tuto věc si ten panel může ušetřit a zadefinovat si TPanelFilters jako group box a do toho vložit ten listbox.

Ten listbox je ale s alClient moc blízko okrajů, a to JJ podle mě nechce (nevypadá to moc hezky).
Citace
zakladni chyba je pouziti "padding" s pevnou hodnotou vzhledem k tomu,
ze okraje mohou byt vykreslovany v zavislosti na tematu Woken
To je pravda, viz TCustomGroupBox.AdjustClientRect.

Správné řešení s padding by bylo takové nějaké:
Kód: Delphi [Vybrat]
  1. type
  2.   TMyWinControl = class(TWinControl)
  3.   end;
  4.  
  5. procedure TPanelFilters.AlignComponents;
  6. const
  7.   xPadding = 6;
  8. var
  9.   xClientRect: TRect;
  10. begin
  11.  
  12.   if Parent = nil then
  13.     exit;
  14.  
  15.   GroupBoxFilters.SetBounds(0, 0, Self.ClientWidth, Self.ClientHeight);
  16.  
  17.   xClientRect := GroupBoxFilters.ClientRect;
  18.   TMyWinControl(GroupBoxFilters).AdjustClientRect(xClientRect);
  19.  
  20.   ListBoxFilters.SetBounds(
  21.     xClientRect.Left + xPadding,
  22.     xClientRect.Top + xPadding,
  23.     xClientRect.Right - xClientRect.Left - 2*xPadding,
  24.     xClientRect.Bottom - xClientRect.Top - 2*xPadding);
  25. end;
  26.  

Sice moc nechápu, že vlastnost ClientRect není už s AdjustClientRect (tedy že GetClientRect nevolá AdjustClientRect), ale není problém to obejít.

Anchors bych v D7 radši moc nepoužíval, moc jim nevěřím - mám dojem, že minimálně do Delphi 2007 byla ve VCL chyba - ignorovaly styly při pozicích. Když člověk na Windowsech bez stylů zadefinoval formulář a dal na něj komponentu s Align = alNone, a Top = 0 a pak to spustil na Windowsech se styly, tak se ta komponenta šoupla o pár px nahoru mimo formulář. Delphi prostě ignorovaly výšku hlavičky okna a jeho okraje. Řešení bylo dát na formulář panel s Align = alClient a všechny komponenty až do něj. Ale je to už strašně let, když jsem na to narazil, XE2 to má už v pořádku.
« Poslední změna: 07-03-2013, 11:51:38 od oxo »
Embarcadero Technology Partner

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Delphi 7 component layout
« Odpověď #6 kdy: 07-03-2013, 12:19:33 »
Teď mě ještě napadlo: vizuálně to půjde pomocí TFrame. Záleží na tom, jak ji budeš využívat. Podle toho bude buď komponenta nebo frame vhodnější. Já bych šel do komponenty :)
« Poslední změna: 07-03-2013, 12:21:16 od oxo »
Embarcadero Technology Partner

JJ

  • Host
Re:Delphi 7 component layout
« Odpověď #7 kdy: 07-03-2013, 14:53:28 »
Díky všem za reakce, takovou odezvu jsem ani nečekal. Zkusím se tím večer prokousat a dám vědět, jak to dopadlo.