AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto
Thema durchsuchen
Ansicht
Themen-Optionen

Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto

Offene Frage von "VCLVirtuoso"
Ein Thema von VCLVirtuoso · begonnen am 20. Mär 2024 · letzter Beitrag vom 5. Apr 2024
Antwort Antwort
VCLVirtuoso

Registriert seit: 12. Mär 2024
3 Beiträge
 
Delphi 12 Athens
 
#1

Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto

  Alt 20. Mär 2024, 13:26
Bei der Verwendung von TTitleBarPanel in Forms, die mit ShowModal aufgerufen werden, ist mir ein merkwürdiges Verhalten aufgefallen. Wenn Application.ModalPopupMode := pmAuto gesetzt ist (was ja bei neueren Delphi-Anwendungen standardmäßig der Fall ist), wird die Custom Titlebar beim zweiten Aufruf des Fensters nicht über die normale Titlebar gezeichnet, sondern darunter, als wäre sie nicht richtig zugewiesen (siehe Anhang). Beim ersten Aufruf des Fensters sieht alles korrekt aus.

Reproduzieren lässt sich der Fehler mit zwei Forms und einer Titlebar in Form2. Die Titlebar wird über  CustomTitlebar.Control := TitleBarPanel1 und CustomTitlebar.Enabled := True in Form2 zugewiesen. Öffnet man über den Button in Form1 nun Form2, schließt Form2 wieder und öffnet es dann nochmal, tritt der Fehler wie auf dem Bild auf.

Wenn unter TForm2.FormActivate die API-Methode SetWindowPos mit dem Parameter SWP_FRAMECHANGED aufgerufen wird, tritt das Problem nicht mehr auf. In komplexeren Fenstern führt das aber zu einem unschönen Flackern. Gibt es einen eleganteren Weg, den Fehler zu umgehen oder handelt es sich dabei um einen Bug in Delphi? pmAuto führt generell an verschiedenen Stellen zu Problemen (siehe https://stackoverflow.com/questions/...bug-workaround), was auch so in der Dokumentation steht, wird aber in unserer Anwendung benötigt, damit TCommonDialoge, sowie die dynamische Vorschau in der Windows-Taskleiste korrekt funktionieren.
Delphi-Quellcode:
program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas{Form1},
  Unit2 in 'Unit2.pas{Form2};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.ModalPopupMode := pmAuto;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.
Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Unit2;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal;
end

end.
Delphi-Quellcode:
unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.TitleBarCtrls;

type
  TForm2 = class(TForm)
    TitleBarPanel1: TTitleBarPanel;
    procedure FormActivate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  protected
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

uses
Unit1;

procedure TForm2.FormActivate(Sender: TObject);
begin
  SetWindowPos(Handle, 0, Left, Top, Width, Height, SWP_FRAMECHANGED); // Diese Zeile behebt das Problem
end;

end.
Miniaturansicht angehängter Grafiken
doppeltetitlebar.png  
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
672 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto

  Alt 21. Mär 2024, 12:06
Bei der Verwendung von TTitleBarPanel in Forms, die mit ShowModal aufgerufen werden, ist mir ein merkwürdiges Verhalten aufgefallen. Wenn Application.ModalPopupMode := pmAuto gesetzt ist (was ja bei neueren Delphi-Anwendungen standardmäßig der Fall ist), wird die Custom Titlebar beim zweiten Aufruf des Fensters nicht über die normale Titlebar gezeichnet, sondern darunter, als wäre sie nicht richtig zugewiesen (siehe Anhang). Beim ersten Aufruf des Fensters sieht alles korrekt aus.

Reproduzieren lässt sich der Fehler mit zwei Forms und einer Titlebar in Form2. Die Titlebar wird über  CustomTitlebar.Control := TitleBarPanel1 und CustomTitlebar.Enabled := True in Form2 zugewiesen. Öffnet man über den Button in Form1 nun Form2, schließt Form2 wieder und öffnet es dann nochmal, tritt der Fehler wie auf dem Bild auf.

Wenn unter TForm2.FormActivate die API-Methode SetWindowPos mit dem Parameter SWP_FRAMECHANGED aufgerufen wird, tritt das Problem nicht mehr auf. In komplexeren Fenstern führt das aber zu einem unschönen Flackern. Gibt es einen eleganteren Weg, den Fehler zu umgehen oder handelt es sich dabei um einen Bug in Delphi? pmAuto führt generell an verschiedenen Stellen zu Problemen (siehe https://stackoverflow.com/questions/...bug-workaround), was auch so in der Dokumentation steht, wird aber in unserer Anwendung benötigt, damit TCommonDialoge, sowie die dynamische Vorschau in der Windows-Taskleiste korrekt funktionieren.
Es ist wohl ein Bug aber der beste workaround wäre meiner Meinung nach, modal genutzte Forms nicht in die autocreate-Liste aufzunehmen sondern nach Bedarf zu erzeugen und danach auch sofort wieder zu zerstören. Man braucht dann auch keine Form-Variable, die läßt sich sozusagen "internalisieren" wenn man der Formklasse eine public class function nach dem folgenden Muster spendiert:

Delphi-Quellcode:
class function TFormXYZ.Execute(aFormdata: TFormXYZData): boolean;
var
  LInstance: TFormXYZ;
begin
  LInstance := TFormXYZ.Create(nil);
  try
    LInstance.Initialize(aFormData);
    Result := LInstance.ShowModal := mrOK;
    if Result then
      LInstance.GetUserInput(aFormData);
  finally
    LInstance.Free;
  end;
end;
TFormXYZData ist dabei ein Objekt das die Daten enthält, die das Form anzeigen bzw. entgegennehmen soll. Man kann auch einen record verwenden, dann muß der Parameter für Execute aber ein Var-Parameter sein.

Auf diese Weise kommt man auch nicht in Versuchung, eine Form als Datenspeicher zu mißbrauchen.
Peter Below
  Mit Zitat antworten Zitat
VCLVirtuoso

Registriert seit: 12. Mär 2024
3 Beiträge
 
Delphi 12 Athens
 
#3

AW: Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto

  Alt 22. Mär 2024, 09:10
Es ist wohl ein Bug aber der beste workaround wäre meiner Meinung nach, modal genutzte Forms nicht in die autocreate-Liste aufzunehmen sondern nach Bedarf zu erzeugen und danach auch sofort wieder zu zerstören. Man braucht dann auch keine Form-Variable, die läßt sich sozusagen "internalisieren" wenn man der Formklasse eine public class function nach dem folgenden Muster spendiert

Auf diese Weise kommt man auch nicht in Versuchung, eine Form als Datenspeicher zu mißbrauchen.
Das wäre wahrscheinlich der richtige Weg und würde auch viele andere Probleme ersparen. Unsere Legacy-Software macht allerdings genau den Fehler an so vielen Stellen, dass sich der Code leider nicht ohne Weiteres refaktorieren lässt.

Mit SetWindowPos im TForm2.FormShow funktioniert es schon besser, weil das Fenster ja noch nicht gezeigt wird. Das ist aber natürlich immer noch ein Hack, den ich eigentlich gerne anders lösen würde. Lässt sich das pmAuto vielleicht umgehen? Ich habe die Dokumentation allerdings schon so verstanden, dass das die "empfohlene" Variante ist. Aber wenn es tatsächlich ein Bug ist, muss es wahrscheinlich erstmal bei dem SetWindowPos-Workaround bleiben.
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
672 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto

  Alt 22. Mär 2024, 11:20
Es ist wohl ein Bug aber der beste workaround wäre meiner Meinung nach, modal genutzte Forms nicht in die autocreate-Liste aufzunehmen sondern nach Bedarf zu erzeugen und danach auch sofort wieder zu zerstören. Man braucht dann auch keine Form-Variable, die läßt sich sozusagen "internalisieren" wenn man der Formklasse eine public class function nach dem folgenden Muster spendiert

Auf diese Weise kommt man auch nicht in Versuchung, eine Form als Datenspeicher zu mißbrauchen.
Das wäre wahrscheinlich der richtige Weg und würde auch viele andere Probleme ersparen. Unsere Legacy-Software macht allerdings genau den Fehler an so vielen Stellen, dass sich der Code leider nicht ohne Weiteres refaktorieren lässt.

Mit SetWindowPos im TForm2.FormShow funktioniert es schon besser, weil das Fenster ja noch nicht gezeigt wird. Das ist aber natürlich immer noch ein Hack, den ich eigentlich gerne anders lösen würde. Lässt sich das pmAuto vielleicht umgehen? Ich habe die Dokumentation allerdings schon so verstanden, dass das die "empfohlene" Variante ist. Aber wenn es tatsächlich ein Bug ist, muss es wahrscheinlich erstmal bei dem SetWindowPos-Workaround bleiben.
Du kannst für jedes Form individuell den PopupMode ändern oder z. B. explizit den PopupParent auf das aktive Form setzen, bevor Du ShowModal aufrufst, aber selbst wenn das funktioniert erfordert es natürlich auch eine entsprechende Änderung an vielen Stellen der existierenden Anwendung.

Ansonsten bleibt nur, die verantwortliche Stelle im VCL-Kode zu suchen und zu fixen. Tritt das Problem auch in Delphi 11.x auf? Falls nicht würde ich die Änderungen am VCL-Kode für "moderneres" Erscheinungsbild von MDI-Anwendungen im Verdacht haben; da wurde einiges verschlimmbessert, was auch nicht-MDI Anwendungen torpedieren kann.
Peter Below
  Mit Zitat antworten Zitat
VCLVirtuoso

Registriert seit: 12. Mär 2024
3 Beiträge
 
Delphi 12 Athens
 
#5

AW: Verwendung von TTitleBarPanel mit ModalPopupMode := pmAuto

  Alt 5. Apr 2024, 08:48
Du kannst für jedes Form individuell den PopupMode ändern oder z. B. explizit den PopupParent auf das aktive Form setzen, bevor Du ShowModal aufrufst, aber selbst wenn das funktioniert erfordert es natürlich auch eine entsprechende Änderung an vielen Stellen der existierenden Anwendung.

Ansonsten bleibt nur, die verantwortliche Stelle im VCL-Kode zu suchen und zu fixen. Tritt das Problem auch in Delphi 11.x auf? Falls nicht würde ich die Änderungen am VCL-Kode für "moderneres" Erscheinungsbild von MDI-Anwendungen im Verdacht haben; da wurde einiges verschlimmbessert, was auch nicht-MDI Anwendungen torpedieren kann.
Tatsächlich funktioniert es, sobald man
Code:
pmAuto
nicht nur global setzt sondern nochmal für jedes Fenster einzeln. Das ist etwas Aufwand, aber deutlich besser als der vorherige Hack. In der Zwischenzeit sind durch das globale
Code:
pmAuto
noch weitere Fehler aufgetreten, weil die Window Handles jedes Mal neu erzeugt werden (zB leere ComboBoxes, wenn die nicht bei jedem Form-Aufruf neu beschrieben werden).
In der Dokumentation zu PopupMode steht auch etwas dazu, das ich überlesen habe:
Zitat:
Die Eigenschaft PopupMode wird beim Aufruf der Methode ShowModal automatisch auf pmAuto gesetzt. Dies verursacht aber eine Neuerstellung des Fenster-Handle, was in der Regel nicht wünschenswert ist. Um die Neuerstellung von Fenster-Handles zu vermeiden, muss die Eigenschaft PopupMode vor dem Aufruf der Methode ShowModal explizit auf pmAuto gesetzt werden (z.B. zur Entwurfszeit).
Damit ist das Thema nun gelöst. Danke für die Hilfe!
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:36 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