Помогите обуздать родительское окно
Задача очень проста. Создается обычное приложение с одним главным (Form1) и одним дочерним окном (Form2). В этом случае при сворачивании главного окна сворачивается и дочерние. Чтобы дочернее окно не зависело от главного, в него добавляется специальная функция CreateParams(), которая представлена ниже. Данная функция делает родительским окном Form2 рабочий стол, а также для Form2 добавляет свою кнопку на панель задач. Теперь Form2 не зависит от Form1. Но! Есть проблема! Если из Form2 вызывается какое-либо специальное окно, например, OpenDialog, тогда Form2 проваливается под Form1, а этого нужно как-то избежать. Мучения к положительному результату не привели, а это критично для разрабатываемого приложения.
Form1
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Form2->Show();
}
//---------------------------------------------------------------------------
Form2
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::CreateParams(Controls::TCreateParams &Params)
{
TForm::CreateParams(Params);
// сделать родительским окном рабочий стол
Params.WndParent = GetDesktopWindow();
// создать кнопку в таскбаре для Form 2
Params.ExStyle = WS_EX_APPWINDOW;
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
OpenDialog1->Execute();
}
//---------------------------------------------------------------------------
Суть проблемы в том, что главное окно приложения (в C++ Builder всегда есть главное окно) активизируется на передний план при создании дочернего окна, поэтому мое отвязанное окно от главного окна и привязанное к рабочему столу, проваливается. По идеи это какое-то API свойство главного окна (свойство активизации при таких обстоятельствах), как бы сбросить его...
Проект прикреплен в аттаче (создан в C++ Builder XE).
Выполнение из Form2 следующего кода
TOpenDialog *OpenDialog1 = new TOpenDialog(this);
OpenDialog1->Execute();
delete OpenDialog1;
дало тот же самый результат.
Злобная какая-та проблема, хотя казалось бы ерунда.
Если делать так:
OpenDialog1->Execute();
SetForegroundWindow(Form2->Handle);
то Form2 провалится за Form1, а после закрытия OpenDialog вернется на передний план, но это все равно ерунда.
Дело в том, что это не учебный, а боевой проект. OpenDialog это только пример. На деле Form2 это редактор с Ribbon-интерфейсом, в котором вызываются различные второстепенные окошки типа выбора цвета, вставка таблицы путем заполнения кубиков и т.д. и впринципе нельзя, чтобы такие "полуокна" вызывали исчезновение Form2 хоть и на время.
Определяет, отображается ли данная
форма поверх других форм, для которых
данное свойство не имеет значение true.
this->TopMost = true;
Определяет, отображается ли данная
форма поверх других форм, для которых
данное свойство не имеет значение true.
this->TopMost = true;
Я не нашёл такого свойства, но как я понял по описанию это this->FormStyle = fsStayOnTop. В этом случае для Form2 будет вообще все плохо, оно хоть и не проваливается под Form1, но под него самого проваливается OpenDialog))
[COLOR="blue"]fsMDIForm[/COLOR] Эта форма является основным окном MDI приложения
[COLOR="blue"]fsNormal[/COLOR] Это обычная форма. Она не является ни родительским ни дочерним MDI окном
[COLOR="blue"]fsStayOnTop[/COLOR] Эта форма является самой верхней формой в приложении если стиль других форм не установлен в [COLOR="#ff8c00"]fsStayOnTop[/COLOR]
[COLOR="#006400"]Значение по умолчанию — fsNormal[/COLOR]
this->FormStyle = fsNormal;
// сделать родительским окном рабочий стол
[COLOR="red"]//[/COLOR] Params.WndParent = GetDesktopWindow();:confused:
Form2->FormStyle = fsNormal; //пробуем так
Form2->FormStyle = fsStayOnTop;
Я попытался даже перехватывать и блокировать сообщения приходящие в Form1, в надежде определить и заблокировать то сообщение, которое заставляет Form1 активизироваться. Попробовал блокировать по очереди все сообщения приходящие в Form1 после OpenDialog->Execute(), ничего не вышло, все равно лезет на передний план.
Вообще-то, за это время можно было бы всё 10 раз посмотреть отладчиком, собрав с отладочными DCU.
Помнится, VCL перещёлкивал окна внутренней служебной процедурой, описанной в Forms. Она называлась как-то вроде AlignTopMosts или как-то так. Уже не пишу на Delphi.
Это родовое пятно VCL -- отдельное окно нулевой размерности у Application -- именно его кнопка видна на панели задач. А главная форма окном приложения в терминах Windows не является. Видимо, даже в XE всё по-прежнему.
Давным-давно в какой-то программе мы делали интерфейс а-ля Office 2000. Упёрлись в то же самое. По-моему, всё решилось написанием своего аналога AlignTopMosts и кучей обходного кода, чтобы стандартный не вызывался. Или плюнули, не помню уже.
задается проблема тянется от сюда [COLOR="red"]Form2->Show();[/COLOR]
Вот еще
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
[COLOR="blue"]#include "Unit1.h"[/COLOR]
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::CreateParams(Controls::TCreateParams &Params)
{
TForm::CreateParams(Params);
// создать кнопку в таскбаре для Form 2
Params.ExStyle = WS_EX_APPWINDOW;
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
[COLOR="blue"] Form1->FormStyle = fsMDIForm;
Form2->FormStyle = fsMDIChild;[/COLOR]
OpenDialog1->Execute();
[COLOR="blue"]Form1->FormStyle = fsNormal;
Form2->FormStyle = fsStayOnTop;[/COLOR]
}
;(((
{
form2 = new Form2();[COLOR="red"] пробуйте так[/COLOR]
form2.Show();//метод для отображения второй формы
}
Да)
И создавать форму 2 пробовал самостоятельно. Все так же.
Только что удалось решить проблему!!!
В настройках проекта отключил автоматическое создание окон. Написал создание окон самостоятельно в сердце программы в Project.cpp.
{
try
{
Application->Initialize();
Application->MainFormOnTaskBar = true;
Form1 = new TForm1(Application);
Form2 = new TForm2(Application);
Form1->ShowModal();
Application->Run();
delete Form1;
delete Form2;
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//---------------------------------------------------------------------------
Пример работает, но пока не ясна корректность такого решения, т.к. программа выполняется фактически без
Application->Run();
т.к. Application->Run(); стартует только после закрытия Form1 и тут же завершается, и вообще если Run закомментировать, то все также работает. Что это за функция и зачем она нужна я пока не разобрался, возможно она выполняет тоже самое что я написал вокруг неё, а может и ещё что-то..
в help что пишет?
Попробую переписать что получилось в боевой проект, там будет сразу понятно есть какие-то проблемы с таким решением или все нормально, т.к. приложение достаточно большое и тяжелое с кучей окон и third-part компонентов (под Intel Core i5 2500k и SSD накопителем build занимает 1.35 минуты). По результатам отпишусь