Gdy ustawisz WindowState formy MDI child na wsMaximized, zauważysz, że forma nie jest od razu zmaksymalizowana. Początkowo jest ona rysowana normalnie i dopiero potem maksymalizowana. Wygląda to dość dziwnie. void __fastcall TCustomForm::AfterConstruction() { ... ... if (FFormState.Contains(fsVisible)) Visible = true; }Visible jest ustawiane w zależności od prywatnej zmiennej FFormState. Dla formy MDI child VCL ustawi zawsze fsVisible, ustawienie właściwości Visible w kodzie nic tutaj nie zmieni (IDE nie pozwoli Ci ustawić właściwości Visible na false dla formy MDI child). Przypisanie wartości do Visible powoduje wysłanie komunikatu CM_VISIBLECHANGING. Komunikat ten obsługiwany jest przez TWinControl, następuje wywołanie funkcji UpdateControlState, ta zaś wywołuje UpdateShowing. TWinControl::UpdateShowing wysyła kolejny komunikat, CM_SHOWINGCHANGED. TCustomForm przechwytuje ten komunikat. Tutaj zaczyna się wszystko rozjaśniać... void __fastcall TCustomForm::CMShowingChanged(TMessage &Message) { ... ... if (FormStyle == fsMDIChild) { if (FWindowState == wsMaximized) { SendMessage(Application.MainForm.ClientHandle, WM_MDIRESTORE, Handle, 0); ShowWindow(Handle, SW_SHOWMAXIMIZED); } }Winowajcą wydaje się być polecenie SendMessage. Wysłanie WM_MDIRESTORE do klienta MDI powoduje narysowanie formy MDI child w stanie niezmaksymalizowanym. Kiedy klient MDI otrzymuje ten komunikat wysyła inne z powrotem do formy MDI child. Wśród nich jest WM_MDIACTIVATE i komunikaty rysujące, to one właśnie powodują przedwczesne rysowanie się formy w stanie niezmaksymalizowanym. Rozwiązanie Zmiana tego co VCL robi wewnątrz CMShowingChanged byłaby trudna, ale możemy kazać Windows, żeby nie przerysowywał obszaru klienta MDI kiedy TCustomForm wysyła kłopotliwy komunikat WM_MDIRESTORE. Możemy zmusić okno klienta MDI, żeby zaprzestało rysowania, dopóki nie pozwolimy na to. Funkcja API LockWindowUpdate pozwoli nam zatrzymać rysowanie klienta MDI aż do powrotu z konstruktora formy. Oto przykład kodu: // ustaw WindowState na wsMaximized w fazie projektowania. LockWindowUpdate(Application->MainForm->ClientHandle); TMDIChild *child = new TMDIChild(Application); child->Caption = "Zmaksymalizowane MDI"; LockWindowUpdate(NULL);Uwaga: Można zablokować jedno okno w danym czasie. Argument HWND określa które okno zablokujemy. Przekazanie NULL powoduje dezaktywację blokady. Uwaga: Zauważ, że blokujemy okno klienta MDI, a nie główną formę programu. Właściwość ClientHandle TForm zwraca HWND okna klienta MDI. Właściwość ClientHandle jest ważna jedynie dla form, które mają ustawiony FormStyle na fsMDIForm. Uwaga: Jeżeli tworzysz okno MDI child z wnętrza MDI parent, możesz pominąć przedrostek Application->Mainform przed ClientHandle. Innymi słowy, możesz użyć funkcji LockWindowUpdate w ten sposób: LockWindowUpdate(ClientHandle);Uwaga: Kiedy forma MDI jest początkowo rysowana w postaci niezmaksymalizowanej, rozmiar okna nie jest określony przez właściwości Width i Height. System operacyjny sam określa rozmiar okna. Analizując TCustomForm::CreateHandle zobaczysz, że rozmiar i pozycja struktury TMDICreateStruct są inicjalizowane do CW_USEDEFAULT. Tak naprawdę właściwości Width, Height, Top, Left są ponownie obliczane po wysłaniu komunikatu WM_MDICREATE. Jeżeli chcesz zmienić te początkowe wartości możesz nadpisać CreateParams. Uwaga: Kilka innych funkcji jest również odpowiedzialnych za rysowanie MDI child w niezmaksymalizowanej postaci. Są one wywoływane po wysłaniu komunikatu WM_MDIRESTORE z TCustomForm::CMShowingChanged. Te funkcje to: WMMDIActivate, SetActive i MergeMenu. WM_MDIRESTORE wywołuje komunikat WM_MDIACTIVATE. Funkcja obsługująca WMMDIActivate wywołuje SetActive. SetActive wywołuje MergeMenu, ta zaś robi to: // przypuścimy, że MergeState ma wartość true int Size; if(MergeState && (FormStyle == fsMDIChild) && (WindowState = wsMaximized) { //{ zmusza MDI do przywrócenia systemowego menu // zmaksymalizowanej formy MDI child } Size = ClientWidth + (int(ClientHeight) << 16); SendMessage(Handle, WM_SIZE, SIZE_RESTORED, Size); SendMessage(Handle, WM_SIZE, SIZE_MAXIMIZED, Size); }Po wykonaniu tego kodu, okno MDI child jest cały czas w postaci niezmaksymalizowanej. Pierwszy komunikat WM_SIZE powoduje zakończenie rysowania okna w tej postaci. Cały ten kod jest wywoływany po pierwszym wykonaniu SendMessage w CMShowingChanged. |