Ó 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/ClientHeighti 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: ní 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.
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.
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/HitTestsocraithe 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:
Landscapear tháibléid is minic cosúil le timpeallacht deisce,Portraitní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.
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.