2013-02-25 10 views
5

Questo accade in tutti Delphi fino a XE3:Soluzione alternativa per l'interruzione delle ancore durante la ricreazione di una finestra?

  1. Creare un modulo e mettere un pannello su di esso. Ancorare il pannello a [akLeft, akTop, akRight, akBottom], ma lasciare spazio tra esso e i bordi.
  2. Aggiungi un pulsante che chiama RecreateWnd()
  3. Esegui l'app. Ridimensiona il modulo in modo che il pannello sia nascosto perché ha una dimensione inferiore a 0 pixel a causa dell'ancoraggio. Premere il pulsante RecreateWnd.
  4. Ridimensionare il modulo indietro e notare che l'ancoraggio del pannello è interrotto.

Finché mi ricordo di aver usato Delphi, le ancore erano sempre impossibili da usare per questo motivo. Ridimensiona il modulo, quindi collegalo: la finestra viene ricreata, il tuo layout è rotto.

Mi chiedo se esiste una soluzione alternativa?

Aggiornamento

due soluzioni sono disponibili nei commenti, una comprovata e stabile, ma con la forma lampeggiante, un altro sperimentale, ma potenzialmente più approfondita e pulito.

Non ho intenzione di votare per nessuno dei due mentre uno di questi è mio e non sono nemmeno sicuro che sia stabile. Invece, aspetterò qualche input pubblico.

+0

"Impossibile da usare" è un po 'esagerato. Un sacco di casi d'uso in cui la maniglia della forma non viene mai ricreata. –

+0

Io non la penso così. Anche quando apparentemente non lo fai ora, un mese dopo fai qualcosa che innesca la ricreazione e il botto, hai introdotto dei bug senza saperlo. Le ancore sono imprevedibili. – himself

+0

Hmm si, certo, è per questo che sono usati così tanto ... Le ancore funzionano abbastanza bene e lo hanno fatto per me e molti altri per anni. Apparentemente il tuo chilometraggio è diverso, ma la tua incapacità di usarli non li rende impossibili da usare per tutti gli altri. –

risposta

4

Le due opzioni che ho usato di cui né è davvero ideale per i problemi con il fondo e le ancore a destra sono:

  1. rendere la finestra grande di nuovo prima di chiamare o far chiamare RecreateWnd();, poi ne fanno piccoli ancora. Deve essere visibile prima di renderlo di nuovo piccolo tuttavia.
  2. Imposta i vincoli del modulo in modo che non possano essere ridimensionati in modo così piccolo da rendere nascoste le cose.

Un esempio che lampeggia la forma più grande, l'altezza l'uso e valori elevati di larghezza sufficiente in modo che il pannello non è nascosto:

procedure TForm1.Button1Click(Sender: TObject); 
Var 
    OldWidth, OldHeight : integer; 
begin 
    OldWidth := Form1.Width; 
    OldHeight := Form1.Height; 
    Form1.Visible := false; 
    Form1.Width := 1000; 
    Form1.Height := 800; 
    RecreateWnd(); 
    Form1.Visible := true; 
    Form1.Width := OldWidth; 
    Form1.Height := OldHeight; 
end; 
+0

Grazie. Il trucco aiuta. Tuttavia, trattare con gli ancoraggi è un PITA ... – himself

+0

Mi chiedo se l'utilizzo di un tipo di pannello "principale" potrebbe aiutare a risolvere il problema. Intendo un pannello impostato su 'alClient' e contenente * tutto * il contenuto. Quindi, prima della ricreazione, ingrandiresti il ​​pannello invece della forma. Qualche sfarfallio potrebbe essere ancora visibile, ma probabilmente in misura minore rispetto all'allargamento del modulo. –

0

scopre che la funzione che si rompe tutto è UpdateAnchorRules. TControl memorizza FOriginalParentSize e ha la propria dimensione originale in FAnchorRules e lo utilizza per ridimensionare automaticamente come ridimensionamento padre. UpdateAnchorRules() prende la dimensione principale corrente e il controllo corrente Width e Height e li salva in FOriginalParentSize e FAnchorRules.

Se tutto ha funzionato correttamente, non avrebbe avuto alcun effetto durante le normali ridimensionazioni, poiché il controllo e il genitore cambiano di dimensioni in accordo.

Ma quando il controllo Width è inferiore a zero a causa dell'ancoraggio, Windows, e di conseguenza Delphi lo considera ancora 0. Se a questo punto viene chiamato il numero UpdateAnchorRules, viene salvato il valore errato 0 per la larghezza originale. Dopo questo il layout è irreparabile.

(Se non è chiamato, Width continua ad essere aggiornato in relazione proprio genitore Width a causa di dimensioni originali conservati)

scopre tutto ciò che comporta la creazione di un handle di finestra chiama UpdateAnchorRules due volte: prima in WinAPI CreateWindow come invia WM_SIZE prima di restituire (e WM_SIZE il gestore chiama UpdateAnchorRules) e il secondo, esplicitamente in CreateHandle dopo la creazione della maniglia.

Sembrerebbe che finché potremo disabilitare per la durata di CreateHandle, avremo successo. Ma ci sono chiamate esplicite a in CreateHandle, il che significa che qualcuno ha pensato che ha bisogno di per essere un adeguamento delle regole di ancoraggio dopo la creazione della maniglia.

Quindi forse mi manca qualcosa e disabilitandolo qualcosa si romperà?

In ogni caso, esistono due metodi pronti per disabilitare UpdateAnchorRules: per impostare FAnchorMove o per impostare csLoading. Il primo non va bene dato che c'è il codice che lo cancella a metà del numero RecreateWnd e poi chiama di nuovo UpdateAnchorRules.

seconda funziona ed ecco una soluzione:

type 
    TComponentHack = class helper for TComponent 
    public 
    procedure SetCsLoading(Value: boolean); 
    end; 

procedure TComponentHack.SetCsLoading(Value: boolean); 
var i: integer; 
begin 
    if Value then 
    Self.FComponentState := Self.FComponentState + [csLoading] 
    else 
    Self.FComponentState := Self.FComponentState - [csLoading]; 
    for i := 0 to Self.ComponentCount-1 do 
    if Self.Components[i] is TControl then 
     TControl(Self.Components[i]).SetCsLoading(Value); 
end; 

procedure SafeRecreateWnd(); 
begin 
    MyControl.SetCsLoading(true); 
    try 
    MyControl.RecreateWnd(); //or any operation which triggers it -- such as docking or making the window visible first time after RecreateWnd() 
    finally 
    MyControl.SetCsLoading(false); 
    end; 
end; 

responsabilità:

Non ho idea di che cosa sarà spezzato eseguendo TControl operazioni con set csLoading.

migliore alternativa sarebbe quella di agganciare UpdateAnchorRules procedura e aggiungere un altro controllo bandiera specificamente per questo scopo, ma che avrebbe richiede né reimplementando UpdateAnchorRules completamente (tendenti alla rottura su diverse versioni di Delphi con differente originale UpdateAnchorRules) o inventare qualche modo per chiama l'originale UpdateAnchorRules che di solito viene distrutto riscrivendolo con un gancio.

Problemi correlati