AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

AlwaysOnTop mit mehreren Formularen

Ein Thema von Dalai · begonnen am 8. Mai 2020 · letzter Beitrag vom 14. Mai 2020
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#11

AW: AlwaysOnTop mit mehreren Formularen

  Alt 9. Mai 2020, 22:47
Das wird nur gehen, wenn die anderen Anwendungen nicht dasselbe vorhaben und ihre eigenen Fenster auch als TOPMOST deklarieren.
Wie ich bereits schrieb, ist mir das "Highlander-Prinzip" in diesem Fall bekannt. Ist das Problem denn mit meinem Testprogramm nachvollziehbar, wenn die beiden Formulare nebeneinander positioniert sind? Denn wie gesagt interessiert mich nicht, ob Formular 2 der Anwendung über Formular 1 derselben Anwendung liegt, denn das passiert nicht und das teste ich auch nicht. Wichtig für mich ist ausschließlich, dass beide Formulare meiner Anwendung (die immer nebeneinander liegen) über den Fenstern anderer Anwendungen (ohne TOPMOST) liegen. Es geht da auch um nichts Großes, das eine Formular ist 65x31 Pixel, das andere ~170x20 Pixel.

Zwischenzeitlich hab ich das zweite Form in eine eigene Anwendung überführt (weil ich für ein anderes Projekt fix eine Lösung brauchte), aber ich bin dennoch an einer Lösung innerhalb einer Anwendung interessiert.

Grüße
Dalai
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#12

AW: AlwaysOnTop mit mehreren Formularen

  Alt 9. Mai 2020, 23:18
siehe #5 ?

[edit]
Hab's aber grad nochmal probiert ... ich glaub Delphi bzw. die VCL ist Schuld.

Vorhin falsch geguckt, denn so ist es aktuell in Windows 10 + Delphi 10.3:
* das zweite Fenster ist immer über dem Ersten
* wären Beide gleich (StayOnTop oder nicht), müsste jeweils das Aktive oben sein
* vermutlich irgendwas in Richtung PopupMode, aber das steht (standardmäßig) eigentlich auf pmNone :grueble:

[edit2]
Delphi-Quellcode:
procedure TCustomForm.CreateParams(var Params: TCreateParams);
...
        case LPopupMode of
          pmNone:
            begin
              if Application.MainFormOnTaskBar then
              begin
                // FCreatingMainForm is True when the MainForm is
                // being created, Self = Application.MainForm during CM_RECREATEWND.
                if FCreatingMainForm or (Self = Application.MainForm) then
                  WndParent := 0
                else
                  if Assigned(Application.MainForm) and Application.MainForm.HandleAllocated then
                  begin
                    WndParent := Application.MainFormHandle;
                    if WndParent = Application.MainForm.Handle then
                    begin
                      if Application.MainForm.PopupChildren.IndexOf(Self) < 0 then
                        Application.MainForm.PopupChildren.Add(Self); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                      FreeNotification(Application.MainForm);
                    end;
                  end
                  else
                    WndParent := Application.Handle;
              end
              else
              begin
                WndParent := Application.Handle;
                SetWindowLong(WndParent, GWL_EXSTYLE, GetWindowLong(WndParent, GWL_EXSTYLE) and not WS_EX_TOOLWINDOW);
              end;
            end;
          pmAuto:
            begin
              if FCreatingMainForm then
                WndParent := 0 // A main form can't be parented to another form
              else
Keine Ahnung wer auf diese bescheuerte Idee gekommen ist auch bei NONE etwas zu machen.

Lösung:
Und statt OnActivate, ist sowieso CreateWnd besser. (auch wenn Beides geht)
Delphi-Quellcode:
type
  TForm3 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure CreateWnd; override;
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.CreateWnd;
begin
  inherited;
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  PopupMode := TPopupMode(9);
end;
[Edit3]
Oder Application.OnGetMainFormHandle benutzen und dort HWND(-1) zurückgeben.
$2B or not $2B

Geändert von himitsu ( 9. Mai 2020 um 23:48 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#13

AW: AlwaysOnTop mit mehreren Formularen

  Alt 9. Mai 2020, 23:41
Es kommt drauf an, wie man es sieht/auslegt

TopMost = über ALLEM (da ginge nur Einer, so ala Highlander)
TopMost = über allem, was nicht TopMost ist
Wohl eher nicht wie man das sieht/auslegt, sondern wie MS das implementiert hat.

Zitat:
HWND_TOPMOST: Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
Um ein TOPMOST Fenster über alle anderen (auch TOPMOST) zu legen, kann man ein SetWindowPos mit HWND_TOP senden. Das platziert ein Fenster so weit vorn wie möglich - bei einem TOPMOST Fenster halt ganz nach vorn. Das hält aber auch nur solange bis ein anderes TOPMOST Fenster (z.B. einer anderen Anwendung) sich davor legt.

Man kann auch noch mit PopupParent experimentieren. Ist das nicht gesetzt, wird implizit das MainForm verwendet. Das hat aber nur Auswirkungen auf die eigenen Anwendung.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#14

AW: AlwaysOnTop mit mehreren Formularen

  Alt 10. Mai 2020, 00:09
Ja, "normal" war es so, dass bei mehreren TopMost beide vor allen anderen Nicht-TopMost blieb
und bei mehreren TopMost dort jeweils das ganz obe, was man zuletzt angeklickt/fokusiert hat.

Wenn man den "neuen" Mist im TCustomForm.CreateParams "repariert", dann ist es auch wieder so.
Wenn die Entwickler das Verhalten ändern wollen, dann dürfen sie gern pmAuto als Default festlegen, aber niemals pmNone kaputt machen.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#15

AW: AlwaysOnTop mit mehreren Formularen

  Alt 14. Mai 2020, 08:30
OK, nachdem ich wieder etwas Luft habe, hab mir das jetzt im Detail angeschaut. Leider musste ich an mehreren Stellen drehen, um einige Nebeneffekte zu unterbinden.


Lösung:
Und statt OnActivate, ist sowieso CreateWnd besser. (auch wenn Beides geht)
Wenn man die Fenster immer OnTop setzen will, dann mag das besser sein. Wenn man dem Nutzer die Wahl lassen will, ist das ungeeignet, denn CreateWnd wird vor dem FormCreate gefeuert, so dass man gar keine Möglichtkeit hat, etwas zu setzen. CreateWnd wird zwar offenbar vor dem OnShow nochmals gerufen, aber ich mag Eindeutigkeit (und werde daher beim OnActivate bleiben).

Zitat:
Delphi-Quellcode:
procedure TForm3.FormCreate(Sender: TObject);
begin
  PopupMode := TPopupMode(9);
end;
Wenn ich das richtig verstehe, zwingt das die Routine im TCustomForm.CreateParams dazu, keinen speziellen Code zur Bearbeitung des Window Parent auszuführen. Was bedeutet das genau?

Dummerweise hat das zur Folge, dass die Form2 im Beispiel einen eigenen Button in der Taskleiste bekommt. Das kann ich gar nicht brauchen.

Nach einigen Versuchen hab ich eine Lösung gefunden, aber ich frag lieber nach, ob das eine saubere Variante ist.

Unit1:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
    if bShowForm2 then begin
        Fform2:= TForm2.Create(nil);
        Fform2.BorderStyle:= bsNone;
        Fform2.PopupParent:= Self;
    end;
end;
Restliche Funktionen der Unit wie gehabt.

Unit2:
Delphi-Quellcode:
procedure TForm2.FormCreate(Sender: TObject);
begin
    Self.PopupMode:= TPopupMode(99);
end;
---

Eine andere Variante kam mir gerade aufgrund eines anderen Projektes in den Sinn.
Unit1: wie im OP.
[EDIT]Der Aufruf von TForm2.Create muss natürlich etwas anders aussehen, aber der Rest bleibt gleich.
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
    if bShowForm2 then begin
        Fform2:= TForm2.Create(nil, Self.Handle);
        Fform2.BorderStyle:= bsNone;
    end;
end;
[/EDIT]

Unit2:
Delphi-Quellcode:
type
  TForm2 = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    FWndParent: HWND;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(AOwner: TComponent; AWndParent: HWND); reintroduce; overload;
  end;
  
implementation
  
constructor TForm2.Create(AOwner: TComponent; AWndParent: HWND);
begin
    Self.FWndParent:= AWndParent;
    inherited Create(AOwner);
end;

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
    inherited;
    Params.WndParent:= Self.FWndParent;
end;

procedure TForm2.FormActivate(Sender: TObject);
begin
    uGUIHelper.AlwaysOnTop(True, Self.Handle);
end;
Vorteil: Kein Button erscheint für Form2 in der Taskleiste und ein Setzen des PopupMode entfällt, was den Nebeneffekt hat, dass es sogar im Delphi 5 funktioniert .

Meinungen zu den beiden Lösungsvarianten? Ist eine besser geeignet als die andere? Und wenn ja, warum?

Grüße
Dalai

Geändert von Dalai (14. Mai 2020 um 20:46 Uhr) Grund: Aufruf TForm2.Create angepasst
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 01:05 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