Problem ze stylowaniem okna z ustawionym Parent na inne okno.

0

Sprawa jest bardzo prosta (przynajmniej w zakresie opisywania problemu, nie wiem, czy rozwiązanie też będzie także trywialne).

Kod wygląda następująco:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2:= TForm2.Create(Form1);
  //Form2.Parent:= Form1;
  Form2.Show;
end;  

Jeśli linia numer 4 jest zakomentowana, czyli nie wskazujemy rodzica, to Form2 nie jest ograniczona do obszaru okna Form1, ale jednocześnie jest tak samo ostylowane, jak Form1 - w sposób zgodny z wyglądem Windows 10.

screenshot-20191209185917.png

Jeśli jednak chcę "zamknąć" drugie okienko w pierwszym, to usuwam komentarz i wskazuję rodzica. Wtedy wprawdzie nie ma możliwości wyjechania przez Form2 poza obszar Form1, ale efektem ubocznym jest zmiana stylu okna-dziecka. Widać to na drugim screenie.
Próbowałem cwaniakować i podmienić wartość parent podczas działania, ale niczego to nie zmieniło. W chwili przełączania okienko na ułamek sekundy znika, a potem pojawia się już z nowym wyglądem.

Pytanie - czemu tak się dzieje i czy mogę coś z tym zrobić?

screenshot-20191209185958.png

1

IMO takiego czegoś nie powinieneś robić – do tworzenia okienek osadzonych służy przecież MDI. ;)

Nie wiem co jest problemem, ale za renderowanie obramowania i zawartości okien odpowiedzialne są mechanizmy systemowe, które wykorzystuje bieżący widgetset. Tak więc nie powinno być to problemem po stronie LCL, choć nie chce mi się wierzyć, że powłoka systemu jest tak skopana. Z drugiej strony, technologia MDI z tego co mi wiadomo została porzucona, więc Win10 może faktycznie go nie wspierać i takie cuda powodować.

0

No ale to tym bardziej się nie trzyma kupy - piszesz, że do tego powinno się korzystać z MDI, a potem że MDI jest wycofane :P

1

No bo tak to wygląda – MDI zostało zdeprecjonowane daaawno temu, ale że API jest wstecznie kompatybilne, to nadal można z niego korzystać. W Lazarusie możesz sobie stworzyć pełnoprawną aplikację MDI, ale na najnowszych systemach mogą i będą się pojawić problemy.

PS: zobacz na ten wątek – MDI window title in Windows 10 – ten sam problem, choć apka pisana w Delphi/VS.

0

To co się stosuje zamiast MDI w nowoczesnych aplikacjach?

0

Zakładki. ;)

0

Tego się obawiałem... A masz jakiś inny pomysł?

1

Innego sposobu system nie obsługuje, więc albo źle renderowane okna MDI, albo SDI, albo zakładki.


Ewentualnie możesz skorzystać z kontrolek grupujących (np. TPanel) do imitacji okien i renderować ich tło za pomocą metod obiektu ThemeServices, tak aby wyglądały jak osadzone okna. Możesz bez problemu malować zarówno obramowanie dla odpowiedniego stanu (aktywne lub nieaktywne), jak i przyciski widniejące na belce po prawej stronie.

Jednak sporo kodu będziesz musiał oprócz tego napisać, tak aby móc sobie takie niby-okienka organizować – przesuwać, maksymalizować, minimalizować, rozciągać, układać itd. Zastanów się czy warto.

0

No właśnie chciałem uniknąć samodzielnego rysowania, ale obawiam się, że na tym się skończy :(

0

Wbrew pozorom nie jest to trudne – po prostu trzeba napisać raptem tysiąc linijek kodu, czyli poświęcić dniówkę. ;)

0

No może nie dniówkę, ale 2-3 dni (żeby to zrobić porządnie, zaimplementować skórki, przetestować itp.). Tylko podobnie jest z kupnem samochodu - bierzesz wersję podstawową. Potem dokładasz lepsze radio, dwustrefową klimę i podgrzewane fotele i okazuje się, że już masz cenę pakietu "premium", który oferuje znacznie więcej, niż golas - więc zmieniasz na premium. Ale jeszcze bierzesz lepszą nawigację i bagażnik na pilota oraz adaptacyjne zawieszenie. I za chwilę się okazuje, że płacisz 2x tyle, ile chciałeś pierwotnie.

Podobnie będzie pewnie tutaj - niby 2 dni nie robią wielkiej tragedii, ale wolałbym tego uniknąć ;)

0
cerrato napisał(a):

No może nie dniówkę, ale 2-3 dni (żeby to zrobić porządnie, zaimplementować skórki, przetestować itp.).

Ty nie masz „implementować skórek”, a skorzystać z obiektu ThemeServices – to duża różnica. Namalowanie jednej części obramowania to kilka linijek kodu – to samo z pozostałymi częściami ramki oraz przyciskami systemowymi. ;)

Najlepiej by było zaimplementować takie okienko w formie komponentu. Przyciski systemowe również i je osadzić wewnątrz tego komponentu. Możesz też napisać jeszcze jeden komponent, w którym osadzone będą te niby-okienka i który to będzie pozwalał na ich organizowanie, tak samo jak formularz-rodzic w przypadku MDI.

Fajna robota i na pewno Ci się przyda, a w razie chęci zmiany zachowania któregokolwiek mechanizmu, zawsze będziesz mógł sobie poprawić kod – będziesz miał pełną kontrolę nad wszystkim.


Użycie obiektu ThemeServices jest bardzo proste:

  • najpierw woła się metodę GetElementDetails, podając enum dotyczący konkretnego elementu interfejsu w konkretnym jego stanie (np. belka tytułowa okna w postaci aktywnej to enum twCaptionActive),
  • następnie pobiera się preferowane wymiary elementu za pomocą metody GetDetailSize lub za pomocą GetSystemMetrix z modułu Windows (zależy od potrzeby),
  • na koniec maluje się element za pomocą metody DrawElement (do malowania elementów w postaci obrazków) lub DrawText (do renderowania tekstu, np. tytułu okna).

Brzmi na proste i w sumie to jest proste.


W razie gdybyś potrzebował sprawdzić których elementów dotyczą konkretne typy wyliczeniowe to do załączników dodaję aplikację testową, w której możesz sobie to szybko sprawdzić (w środku jest plik wykonywalny oraz źródła).

Nie pisałem jej sam – ktoś na forum Lazarusa napisał ją aby mieć ściągę do sprawdzania enumów i ją opublikował, a ja sobie ten program pobrałem, lekko zmodyfikowałem kod i to tyle. No, miłej zabawy. ;)

0

Tylko coś mi świta (temat zglebię przy okazji), że ThemeServices ma problemy z działaniem na Linuksach. Wprawdzie na razie tego nie potrzebuję, ale fajnie by było mieć rozwiązanie bardziej rozwojowe/z opcją nieskomplikowanej migracji na inny OS.

0
cerrato napisał(a):

Tylko coś mi świta (temat zglebię przy okazji), że ThemeServices ma problemy z działaniem na Linuksach.

Nic mi na ten temat nie wiadomo i wątpię aby to była prawda. Przecież komponenty wizualne dostępne w LCL korzystają z tego obiektu, więc gdyby jego metody nie działały prawidłowo to i wszystkie programy stworzone w Lazarusie (a nawet samo IDE) by wyglądało źle, a tak nie jest (przynajmniej w większości przypadków).

Co najwyżej któraś metoda może nie być zaimplementowana, ze względu na różnice w powłokach systemów. Albo jeśli jej nie zaimplementowano lub zaimplementowano częściowo (bo komuś się nie chciało lub z jakiegokolwiek innego powodu). W każdym razie najpierw sprawdź, a później ewentualnie marudź. ;)

0

W każdym razie najpierw sprawdź, a później ewentualnie marudź.

No własne sprawdziłem (fakt, że dość pobieżnie, do tematu przysiądę później) i pierwszy link z brzegu - https://forum.lazarus.freepascal.org/index.php?topic=12760.0

Is DrawEdge() implemented in QtThemes ?
[...]
It seems it is implemented only for Windows. Thanks anyway.

Oczywiście - temat wymaga głębszego zbadania, ale już na pierwszy rzut oka zauważyłem, że mogą być problemy na innych platformach niż Windows.

1

Przecież to wątek z 2011 roku… :/

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