Создание многооконных приложения с дочерними окнами.Подход автора. МDI Application создать просто - File/New/Other.../Projects/МDI Application и все, но...! Окна MDI приложения, при таком подходе, не связаны друг с другом и неуправляемы из основного окна. Нет возможности задавать индивидуальные свойства для окон и т.д. Поставим целью создать на базе SDI Aplication многооконное приложения с дочерними окнами - приложение, которое при старте запускает окно в котором можно разместить заставку программы и автономно - по нажатию, например, различных кнопок SpeedButton - запускает рабочие дочерние окна в которох будут размещаться отдельные программы. При старте любой программы окно заставка закрываться, а при закрытии всех программ заставка будет появляться. В качестве примера такого приложения можно посмотреть программу Jeep. Приступим к созданию такого приложения: Создаем (File/New/Application) основное окно приложения (при старте Builder формируется автоматически, если не изменены настройки по умолчанию). Это окно родитель - оно будет служить для запуска других окон приложения - дочерних. В свойстве FormStyle инспектора объектов для формы (F11 - Proporties/FormStyle) устанавливаем fsMDIForm. Сохраняем проект и файлы приложения в выбранной директории с любыми понравившимися именами. О том как избавиться от мусора в файле прокта .bpr - в другой раз, но в принципе (хотя это и не мешает и ничего не портит) можно удалить из файла .bpr все с текстом "Project1". В пределах созданного приложения создаем новую форму, которая будет являться дочерним окном. File/New/Form Сохраняем новую форму с тем именем, под которым она будет использоваться. File/Save As.../Например View.cpp Перейти к отображению основной формы и включить в проект созданную для дочернего окна форму: File/Include UnitHDR../ В окошке Use Unit выбрать модуль View Перейти к созданной форме и дать ей имя, например Views F11 Инспектор Объектов Name / Views Перейти в меню Borlanda View и выбрать опцию Project Manajer и в ней файл основного проекта и в функции WinMain удалить строку: Application->CreateForm(__classid(TViews), &Views); Проверить, что там появилась строка в заголовке: USEFORM("View.cpp", Views); Перейти к основному окну и проверить в заголовочном раздели файла .cpp должна появиться опция: #include "View.h" Этуже строку скопируем в файл .h основной формы. Перейти в файл View.h и убирать в нем строку. extern PACKAGE TViews *Views; На этом этапе создан класс TViews, запоминаем для себя его имя: class TViews : public TForm В инспекторе объектов устанавливаем следушие Properties: WindowState - wsMaximized FormStyle - fsMDIChild Вновь переходим к форме основного окна и создаем средства для вызова дочернего окна. Это можно сделать для заставки через обработку события OnTimer, естественно поместив на форму компонент TTimer(вкладка System): void __fastcall TViews::Timer1Timer(TObject *Sender) { if(!fView) { fView=true; Views = new TViews(Application); HWND H1=Handle; Views->SendHwnd(H1); } } Для всех следующих создаваемых классов окон (естественно создаваемых таким же образом как и class TViews : public TForm) изменится только имя класса - окна новой программы, но принцип взаимодействия и последовательность операций создания не изменится. Пусть последующие окна для программ запускаются по нажатию кнопок, (из вкладки Additional компонент SpeedButton) в обработчике события нажатия кнопки (2 левых клика на кнопке) будем записывать примерно такой же код (где fViewN - номер флага, для контроля открытого очередного окна, а окна для следующих программ будут ViewsN): void __fastcall TViews::SpeedButton1Click(TObject *Sender) { if(!fView1) { SpeedButton1->Enabled=false; fView1=true; Views1 = new TViews1(Application); HWND H1=Handle; Views1->SendHwnd(H1); } } Здесь, в обоих случаях, создается новый объект класса TViewsN и ему отсылается для запоминания HWND приложения, который понадобится для того, чтобы сообщить основному приложению о закрытии дочернего окна. В файле .h основного окна естественно должен быть определен флаг и определение объекта: bool fViews; bool fViews1; bool fViews2; ..... TViews* Views; TViews1* Views1; TViews2* Views2; ...... При создании формы основного окна флагу должно быть присвоено значение false, например в FormCreate. После добавления необходимого кода файл View.h для создаваемых окон будет выглядеть следующим образом (аналог для всех окон): class TViews : public TForm { __published: private: HWND Hwnd; public: virtual __fastcall TViews(TComponent* Owner); void __fastcall SendHwnd(HWND H); }; А в файле Viev.cpp должен присутствовать и отсутствовать следующие элементы: 1. В заголовке убрана или закоментирована строка: //TViews *Views; 2. Написано тело функции: void __fastcall TViews::SendHwnd(HWND H1) { Hwnd=H1; }2. В функции закрытия дочернего окна или обработки события OnClose: SendMessage(Hwnd,WM_USER+1,0,0); Action = caFree; Заключительный штрих - Оформить реакцию на закрытия дочернего окна в основном окне. Для этого в файле .h основного окна дописываем. private: ............. void __fastcall OtvetN(TMessage &Message); public: ............. BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_USER+N, TMessage,OtvetN) END_MESSAGE_MAP(TForm) Для каждого следующего окна - WM_USER+N, OtvetN. В функции .cpp void __fastcall TOperStat::OtvetN(TMessage &Message) { SpeedButtonN->Enabled=true; fViewsN=false; } С этого момента при старте создается дочернее окно с заставкой (куда можно поместить рисунок) или по нажатию кнопок (например SpeedButtonN) - если еще создано несколько форм - создаются дочерние окна и после его закрытия можно вновь его создать. Естественно в обработчике события OnTimer необходим учет всех открытых окон. if(!fView && !fView1 && !fView2 ....) { fView=true; Views = new TViews(Application); HWND H1=Handle; Views->SendHwnd(H1); } Результат - в создаваемом приложении можно добавлять сколь угодно много программ, каждая из которых будет работать в своем дочернем окне. Для того, чтобы избежать дублирование общих для разных программ функций,
достаточно объявлять классы дочерних окон как friden классы.
|