TForm.Height vs. ClientHeight
N'abend,
also ganz früher wurde mal Height in der DFM gespeichert (D7), was natürlich Spaß machte, als jede Windows-Version unterschiedlich große Titel und Border hatte, also wurde nun ClientHeight gespeichert (so steht es auch in unseren DFMs drin) aber nun im 10.4.1/2 sind fast ALLE Forms nun kaputt, da die Größe nicht mehr stimmt. Trotz nichtfunktionierendem DeklarationSuchen hatte ich mich nun durchgekämpft und was gefunden.
Delphi-Quellcode:
OK, um eine Minimalgröße mit Scrollbar zu bekommen, ist oftmals bei HorzScrollBar/VertScrollBar was eingetragen.
type
TControl = class(TComponent) property ClientHeight: Integer read GetClientHeight write SetClientHeight stored False; TCustomForm = class(TScrollingWinControl) property ClientHeight write SetClientHeight stored IsClientSizeStored; property ClientWidth write SetClientWidth stored IsClientSizeStored; function TCustomForm.IsClientSizeStored: Boolean; begin Result := not IsFormSizeStored; end; function TCustomForm.IsFormSizeStored: Boolean; begin Result := AutoScroll or (HorzScrollBar.Range <> 0) or (VertScrollBar.Range <> 0); end; Somit würde bei diesen Fenstern ab nun Height statt ClientHeight gespeichert. ABER, warum wird dann dort, wo noch ClientHeight in den DFM steht, das nicht geladen? Weder in der IDE, noch im kompilierten Programm stimmt die Größe (es dürfte etwa die Standardgröße der TForm sein). Geladen müsste es eigentlich werden, denn in der DFM steht es drin, also wird auch der Setter aufgerufen, aber scheinbar funktioniert hier was nicht und Delphi "ignoriert" es. Und ja, wir kommen beim csReadingState durch.
Delphi-Quellcode:
procedure TCustomForm.SetClientHeight(Value: Integer);
begin if csReadingState in ControlState then begin FClientHeight := Value; ScalingFlags := ScalingFlags + [sfHeight]; end else inherited ClientHeight := Value; end; |
AW: TForm.Height vs. ClientHeight
Kannst du mal ein Minimalprojekt posten und schreiben, was man testen soll?
Mir ist das nicht aufgefallen. ( OK, ich lade bei vielen Fenstern clientheight und clientwidth beim Erzeugen des Fensters, aber ich habe auch andere... und die sehen "normal" aus und "leben" teilweise seit Delphi2... ) Ich habe soeben eine Form erzeugt, clientheight und clientwidth werden normal geladen und die Werte stimmen (IDE (zum Beispiel 400x500) und zur Laufzeit (500x625, da scaled=TRUE und unter Windows 125%)). Ich habe auch via Editor in .dfm clientwidth und clientheight verändert, das Projekt neu geladen. Sowohl in der IDE wie auch zur Laufzeit sind die Werte von clientwidth und clientheight wie erwartet. ( Vor einigen Delphiversionen gab's ja mal ein Problem beim Laden gewisser Fenster in der IDE. Soweit ich mich erinnere war bei jedem Laden das Fenster etwas kleiner oder grösser. Aber das wurde damals rasch behoben. ) Sehr wahrscheinlich teste ich nicht das, was du meinst... drum Minimalprojekt und Anleitung ;-). |
AW: TForm.Height vs. ClientHeight
Joar, wo soll man anfangen?
Wir hatten nur "paar" der über 300 Units geöffnet, aber schon bei den Wichtigsten wurde einfach die Größe aus der DFM ignoriert. Upgrade von XE zu 10.4.x * inzwischen funktioniert zumindestens das Compilieren recht gut * CodeInsight ist eine Katastrophe (aber ignorieren wir das erstmal) * erste Versuche beim Debuggen von DesignTimePackages lief komplett schief, da von fast allen eigenen Packages keine Debuginfos gefunden wurden (ich würde die Schuld aber hier erstmal auf Eurekalog schieben) * das Öffnen von FormUnits war saulangsam, aber da gab es schon Abhilfe * und eben bei vielen Forms stimmt einfach die Größe garnicht Wie gesagt, es wird einfach ClientHeight komplett ignoriert. Es sind zwar mehrfach vererbte Forms, aber das sollte eigentlich egal sein. Im Programm könnte ich den Setter von ClientHeight/ClientWidth überschreiben und das Problem bestimmt beheben, aber der FormDesigner nutzt nicht "die" Klasse des Vorfahren, sondern einen generischen TForm-Dummy, also kann ich da nichts machen und eine Lösung nur im Programm wäre sinnlos, wenn der FormDesigner beim nächsten Speichern das entgültig zerschießt. Eine neue leere Unit/DFM, um die "vermuteten" Dinge zu erweitern, brachte leider keine Ergebnisse (hier funktioniert es).
Code:
Nach dem Speichern ist es dann, wie erwartet, mit Width/Height, wo es vorher ClientWidth/ClientHeight war.
object Form2: TForm2
Left = 50 Top = 100 ClientHeight = 1200 ClientWidth = 800 HorzScrollBar.Range = 1100 VertScrollBar.Range = 770 Caption = 'Form2' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 end Siehe oben, liegt am HorzScrollBar, was ich ja schon rausgefunden hatte. Und es wäre auch egal, wenn die "richtig" Größe gespeichert würde (egal ob als Height oder ClientHeight), nachdem sie beim Öffnen auch geladen wurde.
Code:
object Form2: TForm2
Left = 0 Top = 0 Width = 833 Height = 1100 HorzScrollBar.Range = 1150 VertScrollBar.Range = 770 ... |
AW: TForm.Height vs. ClientHeight
Dann setz doch ganz pragmatisch die Scrollbar-Ranges erst im FormCreate oder so.
|
AW: TForm.Height vs. ClientHeight
Joar, falls es nur daran liegt.
Im "einfachen" Test ließ es sich nicht reproduzieren. Drum die Rundfrage, ob sowas Andere auch schon hatten und vielleicht sogar mit "einfacher" Lösung. Und dann massig Units suchen, da manuell die DFMs bearbeiten und das nach PAS kopieren. (oder das mit der Größe eventuell auch anders lösen) Hatte erstmal begonnen, nochmal die Branches zu vergleichen, zwischen XE un 10.4 |
AW: TForm.Height vs. ClientHeight
Zitat:
Ich würde HorzScrollBar.Range, VertScrollBar.Range auch aus der DFM ins FormCreate verschieben. "Mist" ist, dass (wie du schreibst) die Form-Abmessungen nicht mehr stimmen. Aber du hast ja sicher massenhaft Backups... |
AW: TForm.Height vs. ClientHeight
Zitat:
Falls Nein, dann lies nicht weiter. Falls aber Ja: Du schreibst, dass ClientHeight komplett ignoriert wird. Ist es auch mit Clientwidth so, wenn du Clientwidth im DFM nur gross genug (zum Beispiel 3000) wählst? Wenn du deinen Monitor mit einer Auflösung 1920x1092 (zum Beispiel 1920x1092 HD Monitor mit 100% Skalierung unter Windows Anzeigeeinstellungen) verwendest, dann vermute ich, dass nach dem Speichern Height=1100 und Width=1940 drin steht. (Dann würde das von dir beschriebene "Problem" aber abhängig von der "Windows Auflösung" und unabhängig von der Verwendung von ScrollBars auftreten: Wenn du im DFM ClientWidth=3000 und ClientHeight=3000 ohne Scrollbars wählen würdest, dann hättest du nach dem Laden und Speichern sehr wahrscheinlich Client Werte um 1924x1061 im DFM.) |
AW: TForm.Height vs. ClientHeight
Nein, leider nicht.
Das ist jenes, was allen fehlerhaftens Forms gemeinsam ist (was ich bissher entdeckt hab), aber "irgendwas" fehlt noch. :cry: ClientHeight/ClientWidth ist in allen DFMs aus'm Delphi XE gespeichert, aber in 10.3 und 10.4 (davor weiß ich nicht), da wird Dieses nicht "beachtet", wenn die Forms im Formdesigner oder im laufenden Programm geladen werden, jedenfalls dort nicht, wo auch HorzScrollBar/VertScrollBar vorhanden sind. Die Forms sind und waren kleiner als FullHD bei 100% und nach dem Laden sind sie "jetzt" noch kleiner, ungefähr so hoch, wie eine nagelneue TForm ist. |
AW: TForm.Height vs. ClientHeight
Zitat:
Falls du ein weiteres Beispiel hast, dann gern - sonst bin ich leise ;-). |
AW: TForm.Height vs. ClientHeight
Sorry, ich hatte das Beispiel testweise per Hand zusammengeklöppelt/gekürzt und bissl auf 100er gerundet.
Ja, mein Monitor ist zufällig 1920x1200, aber du hast Recht, ich hatte hier die Zahlen verdreht. Es ist querformat und nicht hoch, also 1200 war Width und nicht Height. :oops: |
AW: TForm.Height vs. ClientHeight
OK, den genauen Grund konnte ich nun sehen, leider.
Es liegt indirekt an der Vererbung. Es gibt 3 Vorfahren * der Erste ohne DFM * dann zwei mit DFM, mit ClientWidth/ClientHeight (Standard, wie bei fast Allen) * und dann die eigenetliche(n) Form(s), teilweise mit Width/Height in der DFM (weil HorzScrollBar.Range bzw. VertScrollBar.Range) Wenn die DFMs geladen werden, werden zuerst die Vorfahren mit ClientWidth/ClientHeight geladen und darüber dann die Property die eigentlichen FormDFM, somit steht insgesamt sowohl ClientWidth/ClientHeight, als auch Width/Height, in der DFM. ClientWidth/ClientHeight werden von TForm aber zwischengespeichert und erst später (TCustomForm.CMShowingChanged bzw. TCustomForm.ScaleForPPIRect) ausgewertet. "Eigentlich" würde hier ja zuletzt Width/Height aus den DFMs geladen und die vorher geladenen ClientWidth/ClientHeight überschreiben, nur setzt die TForm dabei nicht FClientWidth/FClientHeight zurück, wodurch sie dann nachfolgend mit aller Hörte zuschlagen. :cry: Im SetWidth/SetHeight könnte ich den Fehler zwar beheben, aber nur zur Laufzeit, im Programm, aber nicht im FormDesigner. Aber das Schön, von alleine tritt dieser Fehler nur auf, wenn aus der DFM ClientHeight/ClientHeight geladen wird, was standardmäßig bei fast Jedem der Fall ist. Und es betrifft Alle, die zusätzlich Width/Height in der DFM stehen haben, aber auch jene, welche Width/Height im Contructor beim Laden von SubKomponenten (vor dem Anzeigen) zuweisen, oder HorzScrollBar/VertScrollBar aktivieren. Außerdem zerballert es dir die Form, wenn sich die DPI zur Laufzeit ändern, z.B. mit'm RDP verbinden oder einen Monitor anschalten/ausschalten/anstöpseln/... :cheer: |
AW: TForm.Height vs. ClientHeight
Jetzt bin ich ja mal auf QP-Eintrag gespannt...
|
AW: TForm.Height vs. ClientHeight
Eine "schnelle" Lösung ist hier die Width/Height in den DFMs zu suchen und durch ClientWidth/ClientHeight zu ersetzen (notfalls mit bissl Zuschlag, aber egal, da wir mit Align arbeiten) und HorzScrollBar/VertScrollBar in den constructor zu verschieben.
Ich hab jetzt erstmal das absolute MinimalBeispiel gebastelt
Grundsätzlich ist es doch eh ein Fehler, dass Width/Height gespeichert wird? wenn irgendwas nicht miz Align ausgerichtet ist, dann kann die Form per se falsch geladen werden. (das, weswegen man damals von Height auf ClientHeight umgestiegen ist) |
AW: TForm.Height vs. ClientHeight
Noch eine Anmerkung für dich, die aber eventuell bei aktuellen Versionen nicht mehr zutrifft:
Sobald AutoScroll=True im DFM steht, wird die Grösse (Widht/Height) des Fenster gespeichert. Ist das False wird ClientWidth/Height gespeichert. Ob das aktuell noch so ist, habe ich jetzt nicht getestet, aber in D7 war es noch so. Daher haben alle meine Formen AutoScroll=False und wenn ich es irgendwo benötige, setze ich das Propety im OnCreate der Form auf True. Wieso man da unterscheidet und nicht generell ClientXY nutzt, wissen wohl auch nur die, die das mal so angedacht haben. Bis glaube ich D3 wurde nur Width/Height gespeichert was dann spätestens bei Windows XP (andere Titelgrösse der Fenster) zu falschem Forminhalt führte. Durch die grössere Titelleiste wurden in Delphi Formen der Clientbereich verkleinert. Da wurde dan auf ClientXY umgestellt, aber eben nur wenn AutoScroll=False ist, was IMO ein ziemlicher Blödsinn ist. |
AW: TForm.Height vs. ClientHeight
Delphi 7 war's auch noch so.
Und ja, als es seit XP mit den verschiedenen Fensterrahmen/Titelleisten in jedem neuen Windows anders. Man konnte da nur alles in ein Panel legen und das mit alClient, sonst rutschten schnell mal Komponenten aus dem Fenster. Hmmm, also Grundsätzlich ist im XE der Code ähnlich. Dort wird auch mal Height und mal ClientHeight gespeichert, abhängig von VertScrollBar. Und im SetClientHeight wird ebenfalls in einer Variable zwischengespeichert.
Delphi-Quellcode:
Mein Beispiel liefert also auch im XE schon eine falsche Größe.
ClientHeight = 299
ClientWidth = 635 Height = 800 Width = 50 Aber zusammen mit der Vererbung (ClientHeight in einer DFM und Height in einer Anderen), da funktionierte damals noch (D5, D7, XE) |
AW: TForm.Height vs. ClientHeight
|
AW: TForm.Height vs. ClientHeight
Zitat:
Erwarten tut man tu ich was Anderes. Und außer dem Status kein Wort dazu. Echt nett. :thumb: Vor allem, da das Problem vermutlich mit 2 Zeilen Code, ala FClientWidth:=0; gelöst wäre. |
AW: TForm.Height vs. ClientHeight
Muß man da jetzt nochmal ein neues Tiket machen, oder bekommen die das so mit, dass man nochmal was nachgeschoben hat?
https://quality.embarcadero.com/browse/RSP-33368 Oder gibt es sonst wirklich niemand Anderes, der auch Form-Vererbung nutzt. |
AW: TForm.Height vs. ClientHeight
Ich sage es nochmals: Height und Width wurden nur gepeichert, wenn Autoscroll=True ist. Also die Frage, ob du diese auf True hast? Wenn ja setze das im Design auf False und setzte zur Runtime das Property im OnCreate der Form, wenn du dieses Feature nutzen willst. Ich nutze selber nur wenige vererbte Formen, aber bei keiner habe ich dieses Problem, weil bei mir alle Formen AutoScroll=False haben. Schau mal ob das in deiner Situation was ändert.
|
AW: TForm.Height vs. ClientHeight
Hier soll es aber Autoscroll sein, z.B. für bei Kunden mit zu kleinen Monitoren, was in der Fabrikhallte schonmal vorkommen kann.
Das Scroll ist auch garnicht das Problem ... nur dass Delphi hier einen Bug hat, beim Laden der Fenstergröße. |
AW: TForm.Height vs. ClientHeight
Lies bitte nochmals meine Nachricht! Setze AutoScroll im Design auf FALSE und im OnCreate der Form schreibst du "AutoScroll := True;" und dein Probem ist 99% sicher gelöst. Deine Kunden können so nachwievor die Autoscroll Funktion nutzen und deine Form wird richtig geladen mit den CcientXY Angaben. Wenn AutoScroll True ist, wenn du die Form speicherst, hast du die falschen Höhen und Breiten und lädst dann die Form.Height/Width und nicht ClientHeight/ClientWidth.
Wie gesagt mache ich das genau so bei allen meinen Formen, die AutoScroll nutzen sollen. Das "komische/falsche" Verhalten besteht seit Anfang an und wurde leider nie angepasst. Habe das schon vor 20 Jahren als Bug gemeldet, aber angepasst wurde das bis Heute nicht. |
AW: TForm.Height vs. ClientHeight
Ich hatte den ganzen Mist in hunderten Forms bereits von den DFMs ins OnCreate geschoben.
Aber Chäffe will dass so nicht, weil dann die Bearbeitung im FormDesinger das Scrollen dann noch nicht hat und somit die Form dort abgeschnitten wird. Das Problem wäre auch ganz einfach zu lösen, aber eben nur zur Laufzeit, aber nicht im FormDesigner. (der denn die Form schrottet, sobald man sie einmal in der IDE lädt+speichert) Nur dass sich Emba einfach weigert da die zwei Zeilen aufzunehmen und den Bug zu beheben. Wie gesagt, es muß einfach nur beim Zuweisen von Width das FClientWidth gelöscht werden.
Delphi-Quellcode:
Stattdessen hat jetzt Kollege einen 1500-Zeilen-Hook-Unit geschrieben, welche Form-Klassen in der IDE registriert und dort die Setter überschreibt. :cyclops:
type
TFormAccess = class(TForm); TMyForm = class(...) ... protected //procedure SetWidth(Value: Integer); override; // doesn't work because it's not virtual //procedure SetHeight(Value: Integer); override; procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override; end; procedure TMyForm.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); begin if Width <> AWidth then {TFormAccess(Self).}FClientWidth := 0; if Height <> AHeight then {TFormAccess(Self).}FClientHeight := 0; inherited; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:09 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz