2013-02-25 14 views
5

geschieht in allen Delphi bis zu XE3:Problemumgehung, dass Anker beim Erstellen eines Fensters beschädigt werden? Diese

  1. Erstellen Sie ein Formular und eine Platte auf sie. Verankern Sie das Panel an [akLeft, akTop, akRight, akBottom], aber lassen Sie Abstand zwischen ihm und den Grenzen.
  2. Fügen Sie eine Schaltfläche hinzu, die RecreateWnd() ruft
  3. Führen Sie die App. Ändern Sie die Größe des Formulars, sodass das Bedienfeld ausgeblendet wird, da es aufgrund der Verankerung weniger als 0 Pixel groß ist. Drücken Sie die RecreateWnd-Taste.
  4. Ändern Sie die Größe des Formulars und beachten Sie, dass die Verankerung des Panels unterbrochen ist.

Solange ich mich erinnern kann Delphi verwenden, Anker waren immer unmöglich zu verwenden, weil dies. Ändern Sie die Größe des Formulars und docken Sie es an: Das Fenster wird neu erstellt, Ihr Layout ist beschädigt.

Ich frage mich, ob es eine Art Workaround gibt?

aktualisiert

Zwei Abhilfen sind in den Kommentaren zur Verfügung, ein bewährten und stabil, aber mit Form zu blinken, einen anderen experimentellen, aber potentiell gründlich und sauber.

Ich werde nicht für eine Weile für beide stimmen, da eine davon meine ist und ich bin mir nicht einmal sicher, dass es stabil ist. Stattdessen warte ich auf öffentliche Eingaben.

+0

"Unmöglich zu verwenden" ist ein bisschen übertrieben, denke ich. Viele Anwendungsfälle, in denen das Handle des Formulars nie neu erstellt wird. –

+0

Ich glaube nicht. Selbst wenn Sie es jetzt scheinbar nicht tun, einen Monat später tun Sie etwas, das neu erstellt und knallt, Sie haben Bugs eingeführt, ohne es zu wissen. Anker sind unberechenbar. – himself

+0

Hmm ja, sicher, deshalb werden sie so oft benutzt ... Anker funktionieren ziemlich gut und haben das für mich und viele andere seit Jahren getan. Anscheinend ist Ihre Laufleistung anders, aber Ihre Unfähigkeit, sie zu benutzen, macht sie nicht unmöglich für alle anderen zu benutzen. –

Antwort

4

Die beiden Optionen, die ich von denen verwendet haben weder ist wirklich ideal für Probleme mit der unteren und rechten Anker sind:

  1. das Fenster Stellen wieder groß vor dem Aufruf oder Verursachung RecreateWnd(); aufgerufen werden, dann machen es klein nochmal. Muss sichtbar sein, bevor du es aber wieder klein machst.
  2. Legen Sie die Bedingungen des Formulars fest, damit es nicht so klein skaliert werden kann, dass der Inhalt verborgen bleibt.

Ein Beispiel, das die größere Form, Höhe und Breite Verwendung große Werte genug, so dass die Platte verborgen ist nicht blinkt:

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

Danke. Der Trick hilft. Dennoch, mit Ankern zu tun ist ein PITA ... – himself

+0

Ich frage mich, ob die Verwendung einer Art "Haupt" -Panel helfen könnte, um das Blinken zu umgehen. Ich meine ein Panel, das auf 'alClient' gesetzt ist und * alle * Inhalte enthält. Dann, vor der Erholung, würden Sie das Panel anstelle des Formulars vergrößern. Ein gewisses Flackern ist vielleicht noch sichtbar, aber wahrscheinlich in einem geringeren Ausmaß als beim Vergrößern des Formulars. –

0

Es stellte sich heraus, dass die Funktion, die alles UpdateAnchorRules ist bricht. TControl speichert FOriginalParentSize und seine eigene Originalgröße in FAnchorRules, und verwendet, um die Größe automatisch als Elterngrößen zu ändern. UpdateAnchorRules() nimmt aktuelle übergeordnete Größe und aktuelle Kontrolle Width und Height und speichert diese in FOriginalParentSize und FAnchorRules.

Wenn alles ordnungsgemäß funktionierte, hätte das bei normalen Größenanpassungen keine Auswirkungen, da das Steuerelement und die übergeordneten Elemente die Größe ändern.

Aber wenn das Steuerelement Width ist weniger als Null aufgrund der Verankerung, Windows und folglich Delphi immer noch es 0. Wenn UpdateAnchorRules an diesem Punkt aufgerufen wird, wird der falsche, nicht übereinstimmende 0 Wert für die ursprüngliche Breite gespeichert. Danach ist das Layout nicht mehr zu reparieren.

(Wenn es nicht genannt wird, Width weiterhin in der richtigen Beziehung zu Eltern Width aufgrund ursprünglichen Größen erhalten aktualisiert werden)

Stellt sich etwas aus der Griff erstellen ein Fenster beinhaltet ruft UpdateAnchorRules zweimal: zuerst in WinAPI CreateWindow wie es Versendet WM_SIZE vor der Rückgabe (und WM_SIZE Handler ruft UpdateAnchorRules), und zweitens explizit in CreateHandle nach der Erstellung von Handle.

Es scheint so lange, wie wir UpdateAnchorRules für die Dauer von CreateHandle deaktivieren können, werden wir erfolgreich sein. Aber es gibt explizite Aufrufe an UpdateAnchorRules in CreateHandle, was bedeutet, dass jemand dachte, benötigt, um eine Anpassung der Anchor-Regeln nach der Erstellung von Handle zu sein.

Also vielleicht fehlt mir etwas, und wenn ich es deaktiviere, wird etwas kaputt gehen?

In jedem Fall gibt es zwei Möglichkeiten, UpdateAnchorRules zu deaktivieren: FAnchorMove oder csLoading zu setzen. Der erste ist nicht gut, weil es Code gibt, der es in der Mitte durch RecreateWnd löscht und dann UpdateAnchorRules erneut aufruft.

Zweite man arbeitet und hier ist eine Lösung:

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; 

Haftungsausschluss:

Ich habe keine Ahnung, was sonst durch Ausführen TControl Operationen mit csLoading Satz gebrochen werden.

bessere Alternative wäre UpdateAnchorRules Verfahren Haken und andere Flagprüfung speziell für diesen Zweck hinzufügen, aber das würde erfordern entweder Neuimplementierung UpdateAnchorRules vollständig (anfällig für verschiedene Versionen von Delphi mit verschiedenen Originalen UpdateAnchorRules zu brechen) oder zu erfinden, einen Weg Rufen Sie das Original UpdateAnchorRules an, das normalerweise zerstört wird, indem Sie es mit einem Haken umschreiben.

Verwandte Themen