Dziwne zachowanie się aplikacji w trybie pełnoekranowym

0

Podczas zabawy/testów zauważyłem pewne dziwne/nietypowe zachowanie. Aby to zweryfikować, stworzyłem specjalną aplikację testową, której cały kod sprowadzał się do obsługi OnCreate w następujący sposób:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.FormStyle:= fsStayOnTop;
  Form1.BorderStyle:= bsNone;
  Form1.Left:= 0;
  Form1.Top:= 0;
  Form1.Width:= Screen.Width;
  Form1.Height:= Screen.Height;
end;

Jak można się domyślić - powyższy kod ma zmienić ustawienia okienka tak, aby było ono bez obramowania, miało wielkość całego ekranu, a do tego pozostawało zawsze na wierzchu, czyli nawet przy próbie przełączenia się (chociażby przez Alt+Tab) na inną aplikację moja była nadal widoczna.

Teraz dziwne zachowanie, które udało mi się stwierdzić:

  • aplikacja skompilowana w Lazarus 2.0 64-bit na Win10: mogę przełączać się na inne aplikacje, ten fsStayOnTop jakby nie ma zastosowania
  • aplikacja skompilowana w Delphi 10.2: działa poprawnie na Win10 oraz WinXP
  • aplikacja skompilowana na Lazarus 2.0 32-bit: Win10 oraz WinXP ten sam objaw, pozostawienie okna na wierzchu nie działa.

Czy macie jakieś pomysły, o co tu chodzi? Podejrzewam, że to jakaś głupota, ale czasami człowiek tak ma, że się zafiksuje na jakiś tok myślenia i cięzko z niego wyskoczyć/spojrzeć na sprawę pod innym kątem ;)

4

w lazarusie użyj FormStyle:=fsSystemStayOnTop; i będzie ok

2

A próbowałeś fsSystemStayOnTop?

1

Nie znam się na Lazarusie, ale znalazłem coś takiego: http://wiki.freepascal.org/Lazarus_0.9.30_release_notes#LCL_Changes
I cytat:

TCustomForm.FormStyle added fsSystemStayOnTop.Meaning is same as with fsStayOnTop except that fsStayOnTop is form on app top, so when application deactivates fsStayOnTop is not on top of other application(s), fsSystemStayOnTop is always on top.

Przyznam, że ten cytat jest dla mnie niejasny, ale ostatecznie wydaje się wprowadzać jakąś różnicę, więc może coś pomoże jako ukonkretnienie uogólnienie tego, co @Paweł Dmitruk oraz @kAzek napisali.

0

Dopiero wieczorem będę mógł sprawdzić, ale o ile mnie pamięć nie myli, to "systemOnTop" też robiłem i dawało taki sam efekt (a właściwie jego brak). Tylko nie pamiętam, czy to ustawiałem z poziomu kodu, czy inspektora.

Taka ciekawostka - do zauważenia tego efektu doszło, gdy robiłem śledztwo w sprawie niedzialajacego na Linuksie "ShowModal". Za to "fsStayOnTop" tam działało bez zarzutów... Grrrr ;)

3
cerrato napisał(a):

Jak można się domyślić - powyższy kod ma zmienić ustawienia okienka tak, aby było ono bez obramowania, miało wielkość całego ekranu, a do tego pozostawało zawsze na wierzchu, czyli nawet przy próbie przełączenia się (chociażby przez Alt+Tab) na inną aplikację moja była nadal widoczna.

Pamiętaj tylko, że czego byś nie zrobił, to i tak nie ma możliwości utrzymania okna aplikacji zawsze na wierzchu. Systemowe okienka, takie jak np. menedżera zadań czy tooltipy z paska zadań zawsze będą wyświetlane ponad oknem Twojego programu. No i jeśli inna aplikacja też ma ustawiony taki sam enum (fsSystemStayOnTop), to najprawdopodobniej też będzie mogła wskoczyć na wierzch.

Dodam jeszcze, że jeśli ktoś potrzebuje stworzyć okno w taki sposób, aby było rozciągnięte na pełen ekran i jedynie przykrywało systemowy pasek zadań, to nie trzeba zmieniać właściwości FormStyle. Wystarczy domyślny fsNormal, bo system pozwoli formularzowi wskoczyć nad pasek zadań. Ale to tylko w przypadku, gdy okno nie ma obramowania – to podstawowy warunek.

Jak można się domyślić - powyższy kod ma zmienić ustawienia okienka tak, aby było ono bez obramowania, miało wielkość całego ekranu […]

Za dużo tego kodu – BorderStyle i FormStyle ustaw w oknie inspektora obiektów, a w konstruktorze wpisz to:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.BoundsRect := Screen.PrimaryMonitor.BoundsRect;
end;

Jeśli potrzebujesz wyświetlić okno na innym ekranie, też dopasowane do jego krawędzi, to skorzystaj z właściwości Screen.Monitors, wybierz który chcesz i ustaw obszar w ten sam sposób.

Głównie dla wygody (mniej kodu do pisania), ale też w celu uniknięcia możliwego jego migania – ustawia się pozycję i wymiary raz, a nie cztery razy, tak jak w przykładzie który podałeś. ;)

2

Atrybut okna "bycie na wierzchu" jest rozszerzonym stylem okna WS_EX_TOPMOST (teoretycznie do ustawienia za pomocą SetWindowLong z parametrem GWL_EXSTYLE).

Ale nie należy tego stylu ustawiać "ręcznie". Za wyświetlanie okna na pierwszym planie odpowiedzialna jest funkcja API SetWindowPos
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowpos

Pierwszym parametrem jest uchwyt okna, na którym chcemy wykonać operację.
Drugi parametr - to jest to co nas interesuje.
Jeśli jako drugi parametr jest HWND_TOPMOST, to okno będzie zawsze na wierzchu (pod warunkiem, że ostatni parametr nie będzie zawierał flagi SWP_NOZORDER).

Okno, dla którego wykonamy tę funkcję przykryje wszystkie inne okna (nawet systemowego Menedżera).
Jeśli funkcję wykonamy na dwóch lub więcej oknach, to te okna względem siebie działają tak, jakby tego atrybutu nie miały, natomiast względem innych będą zawsze na wierzchu.

Aby okno przestało być na wierzchu trzeba wykonać funkcję SetWindowPos z drugim parametrem HWND_NOTOPMOST.

Funkcja tez umożliwia ustawienie okna na dowolnym planie. Jako drugi parametr należy wtedy podać uchwyt okna względem którego chcemy ustawić nasze okno.

Tak to działa w API. Nie wiem jakich modyfikacji działania funkcji systemowych dokonuje ten program, w którym działacie.

Aby zmienić pozycję wielu okien bez migotania należy użyć funkcji DeferWindowPos:
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-deferwindowpos

0

Jeśli chodzi o zmianę pozycji czy z-order okna podczas działania programu to tak – można się wspomóc funkcjami API systemu. Chyba że piszemy apkę multiplatformową, to wtedy korzystamy z wrapperów z modułu LCLIntf, bo ich działanie zależne jest od platformy.

Natomiast jeśli mowa o początkowych ustawieniach formularza, to fsSystemStayOnTop jest tutaj odpowiedni.

1

Tak, jak podejrzewałem - chodziło o jakąś głupotę. W sumie to aż mi wstyd się przyznać, ale przyzwoitość względem osób, które brały udział w wątku nakazuje coś napisać na zakończenie ;)

W Lazarusie jest (jak pisaliście w postach, o czym zresztą także wiedziałem) poza fsStayOnTop jeszcze fsSystemStayOnTop. Kiedy pierwsza opcja nie działała, przełączyłem na drugą, ale nie zauważyłem różnicy. Tak jest, jak się człowiek spieszy, żona popędza bo zaraz musimy wychodzić. Wiecie, co odwaliłem? Przełączyłem na systemOnTop w inspektorze, ale jednocześnie nie wywaliłem Form1.FormStyle:= fsStayOnTop; z procedury OnCreate... Nie muszę chyba dodawać, jaki był tego efekt ;) Gdy do tematu usiadłem później, na spokojnie i na świeżo spojrzałem to od razu zauważyłem, w czym był problem. Lekko żenująca wpadka, przepraszam Was za zawracanie głowy :(

1 użytkowników online, w tym zalogowanych: 0, gości: 1