Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Die Delphi-IDE (https://www.delphipraxis.net/62-die-delphi-ide/)
-   -   TForm.Height vs. ClientHeight (https://www.delphipraxis.net/207137-tform-height-vs-clientheight.html)

himitsu 26. Feb 2021 18:32

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:
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;
OK, um eine Minimalgröße mit Scrollbar zu bekommen, ist oftmals bei HorzScrollBar/VertScrollBar was eingetragen.
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;

Michael II 26. Feb 2021 22:56

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 ;-).

himitsu 26. Feb 2021 23:24

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:
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
Nach dem Speichern ist es dann, wie erwartet, mit Width/Height, wo es vorher ClientWidth/ClientHeight war.
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
  ...

Uwe Raabe 27. Feb 2021 10:26

AW: TForm.Height vs. ClientHeight
 
Dann setz doch ganz pragmatisch die Scrollbar-Ranges erst im FormCreate oder so.

himitsu 27. Feb 2021 12:19

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

Michael II 27. Feb 2021 13:34

AW: TForm.Height vs. ClientHeight
 
Zitat:

Zitat von himitsu (Beitrag 1484038)
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)

Manuell die DFMs... wir sind hier unter uns; da kannst du ruhig "zugeben", dass du ein kleines Programm arbeiten lassen wirst. ;-)

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...

Michael II 28. Feb 2021 05:03

AW: TForm.Height vs. ClientHeight
 
Zitat:

Zitat von himitsu (Beitrag 1484025)
Wie gesagt, es wird einfach ClientHeight komplett ignoriert.

Code:
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
Nach dem Speichern ist es dann, ...
Code:
object Form2: TForm2
  Left = 0
  Top = 0
  Width = 833
  Height = 1100
  HorzScrollBar.Range = 1150
  VertScrollBar.Range = 770
  ...

Nur noch kurz: Ist dein Beispiel (oben) eines wo es schief läuft?

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.)

himitsu 28. Feb 2021 12:41

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.

Michael II 28. Feb 2021 13:05

AW: TForm.Height vs. ClientHeight
 
Zitat:

Zitat von himitsu (Beitrag 1484088)

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.

Dann war dein gepostetes Beispiel etwas "schräg"... dort hast du ClientHeight = 1200 im Ausgangs DFM File (klar höher als HD) - und dieser Wert wurde in deinem Beispiel auf Height=1100 gekürzt. Dies entspricht exakt der Höhe, welche von Delphi gespeichert wird, wenn du unter Windows Auflösung ?x1092, 100% eingestellt hast.

Falls du ein weiteres Beispiel hast, dann gern - sonst bin ich leise ;-).

himitsu 28. Feb 2021 13:35

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:

himitsu 12. Mär 2021 13:01

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:

Uwe Raabe 12. Mär 2021 13:17

AW: TForm.Height vs. ClientHeight
 
Jetzt bin ich ja mal auf QP-Eintrag gespannt...

himitsu 12. Mär 2021 13:57

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
  • nagelneue VCL-Anwendung erstellen
  • Alt+F12 (in die DFM)
  • unterhalb von ClientHeight ein Height einfügen
    Delphi-Quellcode:
    object Form12: TForm12
      Left = 0
      Top = 0
      Caption = 'Form12'
      ClientHeight = 299
      ClientWidth = 635
      Color = clBtnFace
    Delphi-Quellcode:
      Height = 800
      Width = 50
  • nicht zurück in den Designer
  • speichern
  • und F9
  • =
  • eigentlich müsste die jetzt 999 hoch und 50 breit sein, aber sie ist noch so, wie vorher im Designer gesehn, also was in ClientHeight/ClientWidth steht.
Bin grad nochmal im XE am Probieren.


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)

Rolf Frei 12. Mär 2021 15:00

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.

himitsu 12. Mär 2021 15:18

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:
  ClientHeight = 299
  ClientWidth = 635
  Height = 800
  Width = 50
Mein Beispiel liefert also auch im XE schon eine falsche Größe.

Aber zusammen mit der Vererbung (ClientHeight in einer DFM und Height in einer Anderen), da funktionierte damals noch (D5, D7, XE)

himitsu 15. Mär 2021 12:37

AW: TForm.Height vs. ClientHeight
 
https://quality.embarcadero.com/browse/RSP-33368

himitsu 24. Mär 2021 23:40

AW: TForm.Height vs. ClientHeight
 
Zitat:

Zitat von Closed
Works As Expected

Ähhhh NEIN!

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.

himitsu 17. Jun 2022 12:50

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.

Rolf Frei 17. Jun 2022 14:09

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.

himitsu 17. Jun 2022 19:31

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.

Rolf Frei 20. Jun 2022 14:59

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.

himitsu 20. Jun 2022 16:04

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:
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;
Stattdessen hat jetzt Kollege einen 1500-Zeilen-Hook-Unit geschrieben, welche Form-Klassen in der IDE registriert und dort die Setter überschreibt. :cyclops:


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