2016-05-27 26 views
5

Lo scenario è questo:Perché il mio controllo del modulo Delphi viene ritagliato quando il mio modulo è più grande del mio schermo?

  • Ho creato una forma di Delphi (XE2).
  • Su di esso è un singolo TGroupBox (o altro controllo) allungato in modo da occupare l'intera larghezza del modulo con la parte superiore.
  • L'ancoraggio destro (oltre a sinistra e in alto) su TGroupBox è impostato.
  • Larghezza modulo impostata su 1200px (per illustrare il punto).

Se eseguo l'applicazione su un monitor la cui Screen.Width proprietà è maggiore di 1200px (sto correndo senza virtualizzazione per quanto ne so DPI) allora il TGroupBox rende come ci si aspetterebbe.

Tuttavia, se la larghezza del monitor è inferiore a 1200 px, la parte destra del controllo non viene visualizzata sullo schermo indipendentemente da come viene ridimensionato il modulo.

ho sovrascritto il metodo della mia forma con la direttiva override;Create() e verificato che sto impostando la proprietà width correttamente, ma il controllo è ancora tagliata.

chiunque può consigliare sia come:

a) impostare la proprietà larghezza del modulo in modo che sia incide sul posizionamento dei componenti figlio o ...

b) suggerire un modo per forzare un relayout di tutti i componenti figlio una volta che il modulo è stato reso?

+1

Che ne dici di impostare la proprietà 'Align' di GroupBox su' alTop'? Ciò equivale a abilitare le ancore sinistra, superiore e destra in modo che si allunghi mentre il modulo padre viene ridimensionato. –

+0

Ho osservato una situazione simile con una cornice in una forma. Se il frame è più grande del modulo, non viene ridimensionato alle dimensioni del modulo anche se la proprietà Align è impostata su Client. Con la cornice il trucco è rendere più piccolo e lasciare che la proprietà del Client faccia il lavoro. –

risposta

3

Tracciare il codice per vedere cosa succede, ho trovato la regolazione seguente.

procedure TForm1.WMWindowPosChanging(var Message: TWMWindowPosChanging); 
var 
    MessageWidth: Integer; 
begin 
    MessageWidth := Message.WindowPos.cx; 
    inherited; 
    if MessageWidth > Message.WindowPos.cx then 
    GroupBox1.Width := GroupBox1.Width - MessageWidth + Message.WindowPos.cx; 
end; 

Questa non è una soluzione generalizzata, ma chiarisce qual è il problema. VCL richiede una dimensione della finestra per il suo modulo che non è concessa dal sistema operativo poiché è più grande del desktop. Da quel momento in poi, il modulo riprende l'ancoraggio del controllo figlio con la larghezza specificata per il tempo di progettazione, che è maggiore della larghezza del modulo del client, quindi il lato destro del controllo figlio supera i limiti.

Un'altra soluzione può essere quella di ignorare la gestione del messaggio WM_GETMINMAXINFO per consentire al sistema operativo di concedere la larghezza richiesta.

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo); 
begin 
    inherited; 
    Message.MinMaxInfo.ptMaxTrackSize.X := 1200; 
end; 

questo non può essere una buona soluzione perché allora la forma sarà più grande del desktop.

Per quanto riguarda gli elementi "a" e "b", non penso che sia possibile "b" - o almeno non è possibile effettuare il relayout VCL da solo - poiché VCL rimanda le regole di ancoraggio fino a dopo il componente (modulo) è stato caricato. A quel punto, la larghezza del modulo è diversa dalla larghezza del tempo di progettazione ma il posizionamento dei controlli secondari rimane inalterato. Nessuna quantità di forzatura al layout li renderà nuovamente sincronizzati.

Tuttavia dovrebbe essere possibile ricalcolare tutto da zero se il proprio codice mantiene un riferimento alla larghezza del tempo di progettazione. Sotto non è completo il codice.

type 
    TForm1 = class(TForm) 
    .. 
    private 
    FAdjustShrinkWidth, FAdjustShrinkHeight: Integer; 
    protected 
    procedure Loaded; override; 
    public 
    procedure SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer; 
     AHeight: Integer); override; 
    end; 

... 

procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); 
var 
    TrackWidth, TrackHeight: Boolean; 
begin 
    TrackWidth := AWidth = 1200; 
    TrackHeight := AHeight = ??; 
    inherited; 
    if TrackWidth and (Width < AWidth) then 
    FAdjustShrinkWidth := AWidth - Width; 
    if TrackHeight and (Height < AHeight) then 
    FAdjustShrinkHeight := AHeight - Height; 
end; 

procedure TForm1.Loaded; 

    procedure ReadjustControlAnchors(Control: TWinControl); 
    var 
    i: Integer; 
    begin 
    for i := 0 to Control.ControlCount - 1 do 
     if (akRight in Control.Controls[i].Anchors) or (akBottom in Control.Controls[i].Anchors) then begin 
     Control.Controls[i].Left := // some complex calculation depending on the anchors set; 
     Control.Controls[i].Top := // same as above; 
     Control.Controls[i].Width := // same as above; 
     Control.Controls[i].Height := // same as above; 
     if (Control.Controls[i] is TWinControl) and (TWinControl(Control.Controls[i]).ControlCount > 0) then 
      ReadjustControlAnchors(TWinControl(Control.Controls[i])); 
     end; 
    end; 

begin 
    inherited; 
    ReadjustControlAnchors(Self); 
end; 

Non ho idea di come riempire gli spazi vuoti nel codice sopra. Leggere e tracciare il codice VCL può essere obbligatorio per imitare l'ancoraggio VCL.

Non riesco a pensare a nulla per 'a'.


Aggiornamento:

VCL ha effettivamente lasciato una backdoor per un controllo di mentire ai suoi figli immediate relative alla dimensione del loro genitore mentre stanno ancorando. Documentation spiega un po 'diverso:

UpdateControlOriginalParentSize è un metodo protetto che aggiorna le dimensioni originali del controllo padre. Viene utilizzato internamente per aggiornare le regole di ancoraggio del controllo.

Possiamo usarlo per indicare al gruppo le dimensioni originali desiderate.

type 
    TForm1 = class(TForm) 
    .. 
    private 
    FWidthChange, FHeightChange: Integer; 
    protected 
    procedure UpdateControlOriginalParentSize(AControl: TControl; 
     var AOriginalParentSize: TPoint); override; 
    public 
    procedure SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer; 
     AHeight: Integer); override; 
    end; 

... 

procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); 
var 
    RequestedWidth, RequestedHeight: Integer; 
begin 
    RequestedWidth := AWidth; 
    RequestedHeight := AHeight; 
    inherited; 
    if csLoading in ComponentState then begin 
    if RequestedWidth <> Width then 
     FWidthChange := Width - AWidth; 
    if RequestedHeight <> Height then 
     FHeightChange := Height - AHeight; 
    end; 
end; 

procedure TForm1.UpdateControlOriginalParentSize(AControl: TControl; 
    var AOriginalParentSize: TPoint); 
begin 
    inherited; 
    if akRight in AControl.Anchors then 
    AOriginalParentSize.X := AOriginalParentSize.X - FWidthChange; 
    if akBottom in AControl.Anchors then 
    AOriginalParentSize.Y := AOriginalParentSize.Y - FHeightChange; 
end; 


Rilevo ancora una volta che questo avrà effetto solo figli diretti del modulo. Se la groupbox ospita controlli che si ancorano a destra e in basso, deve anche eseguire l'override dello stesso metodo.

Si noti inoltre che ciò non annulla il fatto che la larghezza del modulo è stata modificata. Questo è se ci fosse un controllo ancorato a sinistra che è all'estrema destra del modulo, non si sostituirà al limite del client. Agirà come se la larghezza della forma fosse diminuita, cioè rimarrebbe fuori dalla vista.