Создание многооконных приложения с дочерними окнами.Подход автора. М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 классы.
|