Net-Base Iris

03.06.2026

Leaganacha freagartha i Delphi FMX: Breakpoints gan caos sa Designer (le Layout-Router mar shampla cód foinse)

Bíonn leaganacha freagracha FMX leochaileach go tapa sa chleachtas: stoirmeacha athmhéidithe, athruithe DPI, rothlú agus „Visible-Layouts“ a ghineann staid dhúbailte agus athshruthanna deacair a dhífhabhtú. Taispeánann an t-alt seo Layout-Router le Breakpoints a rialaíonn blocanna UI le linn rith an chláir...

03.06.2026

Ó théama an iris go cleachtas tionscadail

Leathanaigh seirbhíse agus teicniúla oiriúnacha don alt

Má tá ort i Delphi FireMonkey roinnt fhormátar a láimhseáil, téann tú go tapa chuig Responsive Layouts FMX — agus go tapa freisin isteach i meascán de Align-kascáidí, coimeádáin leagan i bhfolach agus oibreacha timpeallaithe ón dearthóir a bhriseann le chéad athrú DPI nó rothlaithe. I gcliaint bogearraí gnó atá fásaithe tá sé seo go háirithe míchompordach: forbraítear an UI, athraíonn foirne, agus go tobann tá loighic nasctha le sonraí amhairc.

Lár an fhadhb: cuireann FireMonkey go leor bloic thógála ar fáil (m.sh. Align, Anchors, TScaledLayout, TFlowLayout, TGridPanelLayout), ach níl córas “nádúrtha” Breakpoint ann cosúil leis an ngréasán. Is féidir freagairt d’athruithe méide, ach gan ailtireacht shoiléir críochnaíonn sé i “if Width < … then …” scaipthe thar iliomad Forms.

Taispeánann an ailt seo Layout-Router: comhéadan beag a bhainistíonn Breakpoints go lárnach agus a athchluicheann Controls (nó bloic iomlána leagan) idir Slots réamhullmhaithe. Sprioc: coinnítear státanna, tá an cód inbhainistithe, agus laghdaítear cásanna teorann mar rothlú, leaganacha fite, agus Re-Entrancy. Ina theannta sin tá cúpla cleas nach bhfuil chomh follasach a dhéanann i bhfíorshaol an difríocht idir “oibríonn sa demo” agus “oibríonn go cobhsaí i mbun oibre”.

Cén fáth go bhfuil Breakpoints i FMX difriúil ón ngréasán

I leaganacha gréasáin bíonn Breakpoints go minic dearbhaitheach (CSS Media Queries). I FMX bíonn cinntí leaganáin gníomhaithe go tipiciúil go h-imperative: athraítear iad sa OnResize. Chomh maith leis sin tagann saintréithe sonraithe do phlátaí:

  • Device-Pixel vs. logische Pixel: ClientWidth/ClientHeight i n-aonaid loighiciúla (ag brath ar shcála). Is féidir athruithe DPI (m.sh. Windows Per-Monitor-DPI) an leaganú a athspreagadh, gan athrú “fíorúil” ar cháilíocht nó ar mhéid na fuinneoige.
  • Rotation und Safe Areas: Soláthraíonn feistí soghluaiste Insets (Notch/Safe Area) — ag brath ar an OS agus ar an Device. Bíonn “Breakpoint bunaithe ar leithead amháin” ró-shimplí go minic, toisc go mbíonn an limistéar inbhainte níos lú ná méid na fuinneoige féin.
  • Layout-Pass: Déanann FireMonkey ríomh an leaganaithe i bphásaí. Má athraíonn tú Parent/Align ag an nóiméad mícheart, tá fo-iarmhairtí ann (m.sh. athfhuinneamh il-uaire nó méideanna ag scairtinate).

Freagraíonn Layout-Router don cheist trí (1) an “Cathain” (Resize/Scale/Rotation) a dhícheangal ón “Conas” (rialacha leaganaithe) agus (2) na rialacha a lárú i bplás amháin. Do cheannairí teicniúla is é an éifeacht is tábhachtaí: lár-ionad cinntí soiléir agus iniúchta in ionad go leor cásanna speisialta áitiúla.

Ailtireacht: Layout-Router le Slots in ionad ginte Controls

An cleas glan do FMX: Controls a ghiniúint go dinimiciúil, ach Controls atá ann cheana a athchluich idir Slots. Is coimeádán é Slot go simplí (m.sh. TLayout), a ionadaíonn réimse den UI: Sidebar, Toolbar, Content, Footer, Details-Pane.

Buntáistí i mbogearraí corparáideacha shaincheaptha:

  • Coinnítear státanna (ábhar eagarthóireachta, suíomh scrolla, míreanna roghnaithe), toisc nach ndéantar na hinstanistí a aththógáil.
  • Riosca níos lú maidir le nasctha dúbailte d’Events, Timers nó Bindings.
  • Fágaann rialacha leaganaithe le feiceáil: is féidir “cén bloc atá i ngach Slot” a leanúint agus a athbhreithniú de réir gach Breakpoint.

Tábhachtach don chleachtas: gearr bloic UI sách móra. Má aistríonn tú 30 rialuithe aonair, éiríonn liosta na bealaí féin ina fhoinse earráide. Is fearr coimeádáin mar layFilterBar, layNavigation, layResultList, layDetails.

Sleachta Foinse: Breakpoint-Router do Leaganacha Freagartha FMX

Tá an cód thíos mar aonad chabhrach le húsáid i bhfoirmí FMX. Ríomhann sé pointe bhrise (XS/SM/MD/LG/XL) agus aistríonn sé rialuithe sainmhínithe isteach i gcoimeádáin slot sainmhínithe. Sonraí tábhachtacha:

  • Maolú (Debounce) trí TThread.ForceQueue: cuirtear roinnt imeachtaí Resize le chéile isteach i nuashonrú amháin (níos lú creathadh UI, níos lú lúbanna reflow).
  • Cosaint in-athiontrála: is minic a spreagann nuashonrú layout féin imeachtaí Resize/Layout arís.
  • Roghnach: Treoshuíomh (Portrait/Landscape) is féidir a áireamh i loighic an phointe bhrise.
Delphi
unit NB.FMX.LayoutRouter;

interface

uses
  System.Classes, System.SysUtils, System.Types, System.Generics.Collections,
  FMX.Types, FMX.Controls;

type
  TNBLayoutBreakpoint = (bpXS, bpSM, bpMD, bpLG, bpXL);

  // Mapa: cén Control ba chóir a bheith sa Slot (Container) do bhriseadhphointe.
  TNBRoute = record
    Control: TControl;
    TargetSlot: TControl; // de ghnáth TLayout nó TPresentedControl
    Align: TAlignLayout;
  end;

  TNBRouteList = TList<TNBRoute>;

  TNBGetBreakpointEvent = reference to function(const AClientSize: TSizeF): TNBLayoutBreakpoint;

  TNBLayoutRouter = class(TComponent)
  private
    FRoot: TControl;
    FPending: Boolean;
    FUpdating: Boolean;
    FCurrent: TNBLayoutBreakpoint;
    FOnGetBreakpoint: TNBGetBreakpointEvent;
    FRoutes: TObjectDictionary<Integer, TNBRouteList>;
    function KeyOf(const ABp: TNBLayoutBreakpoint): Integer;
    procedure RootResized(Sender: TObject);
    procedure ApplyPending;
    procedure ApplyRoutes(const ABp: TNBLayoutBreakpoint);
    function DefaultBreakpoint(const AClientSize: TSizeF): TNBLayoutBreakpoint;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure AttachRoot(const ARoot: TControl);
    procedure DefineRoute(const ABp: TNBLayoutBreakpoint; const AControl, ASlot: TControl;
      const AAlign: TAlignLayout = TAlignLayout.Client);

    procedure Invalidate; // ríomh arís go láimhe
    property Current: TNBLayoutBreakpoint read FCurrent;
    property OnGetBreakpoint: TNBGetBreakpointEvent read FOnGetBreakpoint write FOnGetBreakpoint;
  end;

implementation

{ TNBLayoutRouter }

constructor TNBLayoutRouter.Create(AOwner: TComponent);
begin
  inherited;
  FRoutes := TObjectDictionary<Integer, TNBRouteList>.Create([doOwnsValues]);
  FCurrent := bpMD;
end;

destructor TNBLayoutRouter.Destroy;
begin
  if Assigned(FRoot) then
    FRoot.OnResize := nil;
  FRoutes.Free;
  inherited;
end;

procedure TNBLayoutRouter.AttachRoot(const ARoot: TControl);
begin
  if FRoot = ARoot then
    Exit;

  if Assigned(FRoot) then
    FRoot.OnResize := nil;

  FRoot := ARoot;
  if Assigned(FRoot) then
    FRoot.OnResize := RootResized;

  Invalidate;
end;

procedure TNBLayoutRouter.DefineRoute(const ABp: TNBLayoutBreakpoint; const AControl,
  ASlot: TControl; const AAlign: TAlignLayout);
var
  LKey: Integer;
  LList: TNBRouteList;
  LRoute: TNBRoute;
begin
  if (AControl = nil) or (ASlot = nil) then
    raise EArgumentNilException.Create('Níor chóir go mbeadh Control/Slot nil');

  LKey := KeyOf(ABp);
  if not FRoutes.TryGetValue(LKey, LList) then
  begin
    LList := TNBRouteList.Create;
    FRoutes.Add(LKey, LList);
  end;

  LRoute.Control := AControl;
  LRoute.TargetSlot := ASlot;
  LRoute.Align := AAlign;
  LList.Add(LRoute);
end;

function TNBLayoutRouter.KeyOf(const ABp: TNBLayoutBreakpoint): Integer;
begin
  Result := Ord(ABp);
end;

procedure TNBLayoutRouter.RootResized(Sender: TObject);
begin
  Invalidate;
end;

procedure TNBLayoutRouter.Invalidate;
begin
  if (FRoot = nil) or FUpdating then
    Exit;

  // Debounce: cur i bhfeidhm uair amháin in aghaidh an Message-Loop
  if FPending then
    Exit;

  FPending := True;
  TThread.ForceQueue(nil,
    procedure
    begin
      ApplyPending;
    end);
end;

procedure TNBLayoutRouter.ApplyPending;
var
  LBp: TNBLayoutBreakpoint;
  LSize: TSizeF;
begin
  if (FRoot = nil) then
    Exit;

  if not FPending then
    Exit;

  FPending := False;

  LSize := TSizeF.Create(FRoot.Width, FRoot.Height);

  if Assigned(FOnGetBreakpoint) then
    LBp := FOnGetBreakpoint(LSize)
  else
    LBp := DefaultBreakpoint(LSize);

  if LBp = FCurrent then
    Exit;

  ApplyRoutes(LBp);
  FCurrent := LBp;
end;

procedure TNBLayoutRouter.ApplyRoutes(const ABp: TNBLayoutBreakpoint);
var
  LList: TNBRouteList;
  LRoute: TNBRoute;
begin
  if FUpdating then
    Exit;

  FUpdating := True;
  try
    if not FRoutes.TryGetValue(KeyOf(ABp), LList) then
      Exit;

    // Tabhair faoi deara: athrú Parent athraíonn Z-Order.
    // Má tá tábhacht leis an ord, glaoigh DefineRoute sa t-ord inmhianaithe.
    for LRoute in LList do
    begin
      if (LRoute.Control.Parent <> LRoute.TargetSlot) then
        LRoute.Control.Parent := LRoute.TargetSlot;

      // Socraigh Align i ndiaidh Parent; murach sin d'fhéadfadh Bounds a bheith léirithe go difriúil.
      LRoute.Control.Align := LRoute.Align;
      LRoute.Control.Visible := True;
    end;

  finally
    FUpdating := False;
  end;
end;

function TNBLayoutRouter.DefaultBreakpoint(const AClientSize: TSizeF): TNBLayoutBreakpoint;
var
  W: Single;
begin
  W := AClientSize.cx;
  // Breakpoints go hintinneach garbh, toisc go bhfuil éagsúlacht mhór in ardáin sprioc FMX.
  if W < 480 then Exit(bpXS);
  if W < 768 then Exit(bpSM);
  if W < 1024 then Exit(bpMD);
  if W < 1440 then Exit(bpLG);
  Result := bpXL;
end;

end.

Conas an Router a úsáid i bhFhoirm

Déanaimid slots a shainiú mar TLayout (m.sh. layTop, layLeft, layContent) agus cláraímid ansin do gach Breakpoint cá bhfuil na blácaí suite. Is minic go mbíonn sé tipiciúil go mbogann an Sidebar agus an Details-Pane faoi chéile i mion-Breakpoints.

Delphi
procedure TFrmMain.FormCreate(Sender: TObject);
begin
  FRouter := TNBLayoutRouter.Create(Self);
  FRouter.AttachRoot(LayoutRoot); // z. B. ein TLayout, das Client-aligned ist

  // XS: alles untereinander
  FRouter.DefineRoute(bpXS, layToolbar, slotTop, TAlignLayout.Top);
  FRouter.DefineRoute(bpXS, laySidebar, slotContent, TAlignLayout.Top);
  FRouter.DefineRoute(bpXS, layDetails, slotContent, TAlignLayout.Top);
  FRouter.DefineRoute(bpXS, layMain,    slotContent, TAlignLayout.Client);

  // MD: Sidebar links, Details rechts
  FRouter.DefineRoute(bpMD, layToolbar, slotTop,    TAlignLayout.Top);
  FRouter.DefineRoute(bpMD, laySidebar, slotLeft,   TAlignLayout.Client);
  FRouter.DefineRoute(bpMD, layMain,    slotCenter, TAlignLayout.Client);
  FRouter.DefineRoute(bpMD, layDetails, slotRight,  TAlignLayout.Client);

  // Optional: eigene Breakpoint-Logik
  FRouter.OnGetBreakpoint :=
    function(const S: TSizeF): TNBLayoutBreakpoint
    begin
      if (S.cx < 700) or (S.cy < 420) then
        Result := bpSM
      else
        Result := bpMD;
    end;
end;

Cuir i gcomhthéacs: Cén fáth go mbíonn „Umhängen“ go minic níos cobhsaí ná Visible a chasadh

Tá cur chuige coitianta ann curtha i bhfeidhm ina gcoinnítear crainn leagan amach ar leithligh do gach éagsúlacht agus a bhíonn Visible á chasadh faoi dhó. Tá sé sin compordach sa Designer, ach tá fo-iarmhairtí tipiciúla leis:

  • Dúbailte Binding/Events: Caithfidh dhá smachtlár cosúil a bheith comhuaineach (m.sh. dhá bharra scagaire).
  • Ordú Tab agus Fócas: Nuair a athraítear tú, cailltear fócas nó téann tú isteach i smachtláin dofheicthe má tá TabStop/HitTest socraithe go míchuí.
  • Sreabhadh Stáit: Bíonn suímh scrolla, staid roghnúcháin nó téacsanna eagarthóireachta ag dul i bhfad óna chéile.

Coinníonn an umhängen an insteáns aonair soiléir. Tá sé tábhachtach blocanna leagan amach a dhearadh ionas gur féidir iad a aistriú go neamhspleách (m.sh. „Sidebar“ mar choimeádán neamhspleách in ionad go leor smachtlár aonair). Íocann sé sin as i gcothabháil agus i anailís earráidí: déanaimid debug ar insteáns amháin, ní ar dhá UI scáthacha i dara háit.

Péileanna troda sa chleachtas (agus conas iad a debugáil)

1) Stoirmeacha athrúméide agus athiontráil

Ní ghineann FMX an OnResize amháin le linn athrú ón úsáideoir; tarlaíonn sé freisin le linn athruithe stíle, athruithe parent agus uaireanta le linn athruithe DPI. Gan Debounce, bíonn an aip greamaithe i lúbanna leagan amach. Úsáideann an Router TThread.ForceQueue chun na hathruithe a chur isteach sa chéad UI-tic eile.

Leideanna chun debugáil: cabhraíonn logging (m.sh. trí OutputDebugString) le breakpoint, méid agus comhaireoir nuashonraithe chun lúbanna reflow a aimsiú. Má lógaíonn tú freisin an t-am a thosaíonn agus a chríochnaíonn ApplyRoutes, feicfidh tú go tapa an bhfuil athrú aonair ar mhéid ag cascáidú.

2) Z-Order, HitTest agus bacanna-cliceáil „dofheicthe“

Athraíonn athruithe parent an Z-Order. Má theipeann ar overlays (m.sh. flyouts) freagairt do chliceáil, is minic toisc go bhfuil coimeádán client-aligned os a chionn agus go bhfuil HitTest gníomhach. Rogha mhaithe: socraigh slot ar leith, go háirithe ar bharr an leagan amach, agus parentáil na smachtláin overlay ansin amháin. I FMX is gnách go mbíonn HitTest (an ndéanann smachtán imeachtaí lucha/teagmhála a ghabháil) i gceist níos minicí ná an infheictheacht féin.

3) TGridPanelLayout agus toiseanna céatadán

TGridPanelLayout is féidir, i gcás colún/sraitheanna céatadánacha i gcomhcheangal le Align=Client agus athnasctha dinimiciúil, athríomhanna neamhréalaíocha a spreagadh. Má tá ort Grid a úsáid, cuir an Grid i slot, agus déan athnasctha ach ar bhloic iomlána Grid, ní ar pháistí an Grid. Laghdaíonn sin an iliomad comhcheangail i bpasanna leagan amach.

4) Fócas, méarchlár fíorúil agus réimsí ionchuir „léimneacha”

Rud imeallach a tharlaíonn i n‑aip FMX soghluaiste agus freisin ar Windows‑tháibléid: le linn an athnasctha féadfaidh comhpháirt eagarthóireachta atá faoi fhócas a tuismitheoir a chailleadh go sealadach. Féadfaidh sé sin an méarchlár fíorúil a dhúnadh nó an cursóir a athshocrú. Cleachtas praiticiúil a chruthaíodh go maith is ea: sábháil an fócas reatha go sealadach roimh an Routing (Focused/IFMXFocusControl), agus tar éis an Routing (sa tick UI céanna) an fócas a aisghairm. Tá sé sin go háirithe úsáideach i bhfoirmeacha ionchuir a athraíonn idir „dhá‑cholúnach“ (Tablet/PC) agus „colún‑amháin“ (Phone).

Variáin: Breakpoints de réir fhormfachtóra seachas ach leithead

I gcliantí il‑ardán réalaíoch, ní bhíonn an t‑eochair „Leithead“ ina chomhartha cuí go heisiach go minic. Roghanna ciallmhara:

  • Leithead agus Airde: fuinneoga an‑íseal (m.sh. teirminéil POS, scáileáin roinnte) a éilíonn rialacha éagsúla.
  • Treoshuíomh: Landscape ar tháibléid is minic cosúil le timpeallacht deisce, Portrait níos cosúla le timpeallacht soghluaiste.
  • Réimse inúsáidte Safe‑Area: Ar iOS/Android d’fhéadfadh an airde inúsáidte a bheith laghdaithe go mór ag barraí an chórais. Má fhéachtar díreach ar Height, uaireanta bíonn an routáil ró‑dhéanach.

Tá an Router déanta go cúramach ionas gur féidir leat an fheidhm Breakpoint a mhalartú. Cabhrach é sin i gcásanna Legacy freisin, nuair a rith an fhoirm chéanna i roinnt óstach (m.sh. uair amháin mar fhuinneog ghnáth, agus uair eile i gcoimeádán ionchlóite).

Go neamhghnách glan: Layout‑Routing mar „idirbheart”

I scáileáin níos mó, ní hé an cheist go príomha faoi na Breakpoints féin ach faoin ord na n‑oibríochtaí UI. Patrún praiticiúil ná an Routing a chóireáil mar idirbheart: cinntiú ar dtús, ansin athnasctha, agus ansin na héifeachtaí taobh (infheictheacht, fócas, athnuachan sonraí) a chur i gcrích go hordeáilte.

Go sonrach ciallaíonn sé sin: seachain go spreagfaidh rialtóirí aon‑imeachtaí féin le linn an athnasctha a thosaíonn ar leagan amach nó ar rochtain sonraí. I FMX tarlóidh sé seo, mar shampla, nuair a bhíonn athrú tuismitheora agus go n‑imoibríonn OnEnter/OnExit, nó nuair a athmheasctar léiriú LiveBinding mar thoradh ar Bounds‑nuashonrú. Má fheiceann tú a leithéid d’éifeachtaí, cabhróidh lasc lárnach „Updating“ (mar atá sa Router) i gcomhcheangal le céim iarghníomh shoiléir: ní cheadófar rudaí costasacha rith ach tar éis ApplyRoutes (m.sh. liosta a athlódáil, radharc mionsonraí a nascadh).

Go háirithe i gcliantí le rochtain REST tá sé ábhartha: d’fhéadfadh athlódáil neamhriachtanach le linn athmhéide a ghiniúint iarratais bhreise. Ní thaispeánann sé sin go soiléir i LAN, ach i VPN nó ar ghléas soghluaiste léirítear é láithreach.

Cathain a bhíonn an cur chuige tairbheach — agus cá bhfuil teorainneacha aige

Bíonn an Layout‑Router tairbheach má:

  • maireann aip FMX ar feadh blianta agus oibríonn roinnt forbróirí ar na scáileáin chéanna,
  • tá riachtanas agat do rialacha Breakpoint inathnuaite in ionad oiriúnúchán Align ad‑hoc.

Feicfidh tú teorainneacha nuair is gá do scáileán a bheith go láidir „fluid“ (go leor blocanna dinimiciúla, leaganacha Masonry fíor). Sa chás sin bheadh TFlowLayout/TGridPanelLayout nó do ranganna leagan féin-oibre níos oiriúnaí. Má aistríonn an iomarca rialuithe aonair idir sliotáin freisin, éiríonn cothabháil na rutaí casta – níos fearr ansin blocanna móra a úsáid nó sraith chumraíochta dearbhaithe a chur i bhfeidhm (m.sh. cumraíocht JSON do shonruithe sliotán a luchtú ag tosaigh).

Conclúid: Do leaganacha freagartha i FMX is meánchlár pragmatach é „Umhängen mit Breakpoints“: níos lú caos ó thaobh dearadh, rialacha soiléire, staidí chobhsaí. Ní dhéanann sé ionadaíocht ar struchtúr UI mionsonraithe, ach tugann sé créat soladach iontaofa duit chun cliaint FMX i réitigh fiontar dhigiteacha a fhorbairt go smachtaithe thar éagsúlacht fhormfhachtóirí.

Má theastaíonn uait ailtireacht leaganachta den chineál seo a chur i bhfeidhm go glan i bhfeidhmchlár Delphi atá ann cheana nó i iarratas FMX, gan riosca a chur faoi regressáin UI i gcásanna oibríochta, is féidir leat é sin a phlé linn ó thaobh teicniúil: pléigh tionscadal nó tionscnamh nuaúcháin le Net-Base.

I gcomhthéacs ghairmiúil imríonn Delphi FMX Breakpoints agus Firemonkey Layout ról tábhachtach freisin nuair is gá go gcomhoibreoidh comhtháthuithe, sreafaí sonraí agus forbairt bhreise go néata.

Pléigh tionscadal nó tionscnamh nuaúcháin le Net-Base.

Céim eile

Nuair a éiríonn an t-ábhar seo ina thionscadal fíor, ba chóir ailtireacht, an córas reatha agus an t-oibriú a mheas le chéile go luath.

Ní hamháin go dtacaímid le ceisteanna aonair, ach freisin nuair is gá ó shlisíní cód foinse, ó ábhair legacy nó ó smaointe portail tionscadal corparáideach iontaofa a fhorbairt.

  • Measúnítear an staid reatha, an stát sprioc agus na rioscaí teicniúla le chéile.
  • Ní chuirfear REST, rochtain ar shonraí, portalí agus Rollout siar mar iarmhairtí.
  • Feiceann sibh go luath cé acu an cosán atá inbhuanaithe ó thaobh eacnamaíochta agus oibríochta.

Roinn an post

Roinn an t-alt seo go díreach

Tá LinkedIn, X, XING, Facebook, WhatsApp agus ríomhphost ar fáil láithreach. Do Instagram ullmhaímid nasc agus téacs gairid láithreach.

Ríomhphost

Osclaítear Instagram i gcluaisín nua. Cóipeáiltear an nasc agus an téacs gairid roimh ré isteach sa ghearrthaisce.