Strona 1 z 1

Problem z programem typu MDI

Nowy postNapisane: poniedziałek, 14 lipca 2008, 09:28
przez kask18
Cześć wszystkim, to na dzień dobry mam taki oto problem. Tworzę aplikacje typu MDI. Służy on do otwierania obrazów. Chciałbym zrobić w tym projekcie 2 rzeczy:

1. By tworzone okienka miałby BorderStyle identyczne jak Form1 (podstawowa forma) czyli
bsToolWindow.

2. kiedy przesuwam obrazek już wczytany po przestrzeni formy głównej to i dochodze do
krawędzi formy to pojawia się na dole Scroll. Chciałbym zrobić tak by krawędzie głównej
formy ograniczały mi przestrzeń przesuwania obrazka.


link do programu:
Program

z góry dzięki za pomoc :-)

Re: Problem z programem typu MDI (kask18)

Nowy postNapisane: poniedziałek, 14 lipca 2008, 09:29
przez Cyfrowy Baron
Co do pierwszego pytania, to jedyne co udało mi się uzyskać to okienko Child typu dialog poprzez zmianę stylu BorderStyle, niestety nie działa na ToolWindow, a ręczne ustawianie stylu z wykorzystaniem klasy TCreateParams też nic nie daje.

Co do drugiego pytania, to należy cały kod ograniczający obszar poruszania formularza Form2 po Form1 umieścić w zdarzeniu OnPaint dla formularza głównego czyli Form1:

Kod: Zaznacz cały
void __fastcall TForm1::FormPaint(TObject *Sender)
{
TRect R = Rect(0, 0, ClientWidth - Form2->Width - 4,
                 ClientHeight - Form2->Height - 4);

if(Form2->Left >= R.Right) Form2->Left = R.Right;
if(Form2->Left <= 0) Form2->Left = 0;

if(Form2->Top >= R.Bottom) Form2->Top = R.Bottom;
if(Form2->Top <= 0) Form2->Top = 0;
}

Re: Problem z programem typu MDI (kask18)

Nowy postNapisane: wtorek, 15 lipca 2008, 22:33
przez kask18
mógł byś podać to na przykładzie mojego programu ?? Rozwiązanie które podałeś sprawdza się dla jednego okienka typu MDIChild natomiast w moim programie tworzone są dynamiczne te okienka i może być ich kilka. Jeśli da rade coś z tym fantem zakombinować było by fajnie. I dzięki za pomoc udzieloną droga mailową :)

Re: Problem z programem typu MDI (kask18)

Nowy postNapisane: wtorek, 15 lipca 2008, 23:06
przez Cyfrowy Baron
Fakt tworzenia dynamicznie formularza nic nie zmienia. Przedstawiony kod odwołuje się do nazwy formularza, więc wystarczy podać właściwą nazwę, wymaga to oczywiście, żeby formularze były deklarowane jako globalne, co w przypadku aplikacji MDI może faktycznie stanowić problem.

Dziś już chce mi się spać więc nic nie wymyślę, ale jutro sprawdzę, czy nie dałoby się umieścić tego kodu w oknie CHILD a nie MDI, wtedy działałby niezależnie od formularz głównego (MDI).

Od razu dodam, że umieszczenie tego kodu w zdarzeniu OnPaint okna CHILD nie wywoła pożądanego efektu, gdyż to zdarzenie jest wywoływane tylko podczas odrysowywania okna, a więc nie podczas jego przesuwania, ale dopiero po zakończeniu ruchu.

Myślę że rozwiązaniem problemu będzie funkcja przechwytująca komunikaty i można tutaj stworzyć własną mapę komunikatów, lub posłużyć się komponentem TApplicationEvent, ale o tym jutro...

Rozwiązanie: Problem z programem typu MDI

Nowy postNapisane: środa, 16 lipca 2008, 12:42
przez Cyfrowy Baron
Tak więc mam rozwiązanie tego problemy, z wykorzystaniem komponentu TApplicationEvents, który znajdziesz na zakładce Additional.
Można by się posłużyć mapą komunikatów, ale to tylko skomplikowało by kod, w tym znaczeniu, że byłoby go więcej.

Umieść komponent ApplicationEvents1 na formularzu okna potomnego (Child), następnie utwórz dla niego zdarzenie OnMessage.
W pliku nagłówkowym (np. ChildWin.h) w sekcji public zadeklaruj obiekt typu TForm, posłuży on do śledzenia położenia i rozmiarów okna głównego (MDIForm).
Kod: Zaznacz cały
private:
   TForm *MyControl;

następnie w pliku źródłowym (np. ChildWin.cpp) w konstruktorze klasy trzeba podłączyć obiekt MyControl do formularz głównego programu (MDIForm):
Kod: Zaznacz cały
__fastcall TMDIChild::TMDIChild(TComponent *Owner)
   : TForm(Owner)
{
  MyControl =  Application->MainForm;
}

teraz w utworzonym wcześniej zdarzeniu OnMessage komponentu ApplicationEvents1 umieszczamy kod ograniczający obszar przemieszczania się okna:
Kod: Zaznacz cały
void __fastcall TMDIChild::ApplicationEvents1Message(tagMSG &Msg,
      bool &Handled)
{
try{
TRect R = Rect(0, 0, MyControl->ClientWidth - this->Width - GetSystemMetrics(SM_CXEDGE)*2,
         MyControl->BoundsRect.Bottom);

  if(this->Left >= R.Right) this->Left = R.Right;
  if(this->Left <= 0) this->Left = 0;

  if(this->Top + MyControl->Top + this->Height >= R.Bottom)
   this->Top = MyControl->ClientHeight - this->Height - GetSystemMetrics(SM_CYEDGE)*2 - 49;
  if(this->Top <= 0) this->Top = 0;
}catch(...){;}
}




Krótkie wyjaśnienie:

Funkcja GetSystemMetrics pobiera grubość ramki okna zdefiniowaną w systemie i odejmuje ją od wymiarów formularza głównego.
Struktura MyControl->BoundsRect.Bottom zwraca położenie okna głównego w odniesieniu do dołu ekranu. Jest to potrzebne gdyż występuje problem z obliczeniem obszaru poruszania się okna potomnego po oknie głównych, ze względu na to, że na oknie głównym mogą znajdować się komponenty ToolBar i StatusBar, które nie są uwzględniane przez funkcję ClientHeight, dlatego zrezygnowałem z użycia tej funkcji do obliczania obszaru roboczego okna.
W kodzie występuje jawnie określona wartość 49, jest to suma szerokości komponentów ToolBar (u mnie 30) i StatusBar (u mnie 19). Jeżeli więc u Ciebie występują lub nie jakieś komponenty na formularzu okna głównego (MDIForm) ograniczające obszar przemieszczania się okna potomnego to musisz odpowiednio zmodyfikować tą wartość.

Można by się pokusić o automatyczne określanie szerokości obszaru roboczego okna głównego, ale wymagałoby to stworzenia odrębnego algorytmu, więc jeżeli można określić ten wymiar jawnie, to nie ma sensu komplikować kodu.

Ograniczanie obszaru przemieszczania się formularza potomnego po głównym z wykorzystaniem przechwytywania komunikatów, nie zawsze może działać prawidłowo, gdyż przy większym obciążeniu systemu, do programu mogą nie dotrzeć komunikaty i w efekcie kod nie zadziała.