Некорректная активация нескольких приложений Windows
Вопрос
У меня есть приложение на Delphi, в котором в качестве основной формы используется браузер документов.Когда пользователь открывает документ, мы открываем окно редактора.Мы хотим, чтобы у каждого редактора была кнопка на панели задач, а также основная форма.Я применил обычный код для этого (ниже), но когда я нажимаю на основную форму после использования окна редактора, редактор остается сверху, в то время как основное внимание уделяется основной форме.Я не могу понять, что является причиной такого поведения.
Постановка сцены:Я открываю основную форму и форму документа.
Нажмите на другое приложение, нажмите на основную форму, основная форма остается сфокусированной.(Ведет себя так, как ожидалось.)
Нажмите на форму документа, нажмите на основную форму, появится форма документа задом наперед, но отображается неактивной.(На рисунке показан результат)
альтернативный текст http://www.matthew-jones.com/temp_xfer/titlebarfailure.jpg
Первый шаг, это Delphi 2007, и у меня есть в проекте:
Application.MainFormOnTaskBar := True;
Для основной формы у меня нет дополнительного кода.
Для формы документа у меня есть
procedure TCommonEditForm.CreateParams(var params: TCreateParams);
begin
inherited;
params.WndParent := 0; // GetDeskTopWindow; no diff
end;
Я пытался выяснить, есть ли сообщение, из-за которого это происходит, но не могу найти ничего подходящего.Я поискал в коде что-нибудь, связанное с "активировать".Подсказки приветствуются!
Решение
Мое приложение работает так, как вы описали.Вот подход, который я избрал.Я бы хотел найти более простой подход, но так и не нашел.
Я начал с чтения этих статей.Это первое из них - отличная статья Питера, приведенная ниже:
http://groups-beta.google.com/group/borland.public.delphi.winapi/msg/e9f75ff48ce960eb?hl=en
Здесь также была найдена другая информация, однако это не оказалось правильным решением:для моего использования: http://blogs.teamb.com/DeepakShenoy/archive/2005/04/26/4050.aspx
В конце концов, вот что у меня получилось.
Моя заставка служит одновременно основной формой приложения.Основная форма имеет специальную привязку к объекту Приложения.Использование всех вторичных форм дает мне поведение, которое я искал.
В каждой форме, которую я хочу получить на панели задач, я переопределяю CreateParams.Я делаю это в своих формах редактирования и в том, что пользователи считают "основной формой".
procedure TUaarSalesMain.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := GetDesktopWindow;
end;
Моя "Основная" форма, насколько это касается Delphi, загружает истинную основную форму в своей функции Activitate.Я использую переменную-член, чтобы отслеживать первую активацию.Затем в конце функции я скрываю форму заставки, но не закрываю ее.Это было важно для меня, потому что, если пользователь редактировал документ и закрывал основную форму, я не хотел, чтобы экраны редактирования были принудительно закрыты одновременно.Таким образом, все видимые формы обрабатываются одинаково.
if FFirstActivate = false then
exit;
FFristActivate := false;
/*
Main Load code here
Update Splash label, repaint
Application.CreateForm
etc.
*/
// I can't change visible here but I can change the size of the window
Self.Height := 0;
Self.Width := 0;
Self.Enabled := false;
// It is tempting to set Self.Visible := false here but that is not
// possible because you can't change the Visible status inside this
// function. So we need to send a message instead.
ShowWindow(Self.Handle, SW_HIDE);
end;
Но проблема все еще остается.Вам нужно, чтобы главное окно / заставка закрывалось, когда все остальные формы будут закрыты.У меня есть дополнительная проверка в моих процедурах закрытия для родителей <> ноль, потому что я использую формы в качестве плагинов (для моих целей они работают лучше, чем фреймы).
Мне не очень понравилось использовать событие Idle, но я не заметил, чтобы это тормозило работу процессора.
{
TApplicationManager.ApplicationEventsIdle
---------------------------------------------------------------------------
}
procedure TApplicationManager.ApplicationEventsIdle(Sender: TObject;
var Done: Boolean);
begin
if Screen.FormCount < 2 then
Close;
end;
{
TApplicationManager.FormCloseQuery
---------------------------------------------------------------------------
}
procedure TApplicationManager.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
var
i: integer;
begin
for i := 0 to Screen.FormCount - 1 do
begin
if Screen.Forms[i] <> self then
begin
// Forms that have a parent will be cleaned up by that parent so
// ignore them here and only attempt to close the parent forms
if Screen.Forms[i].Parent = nil then
begin
if Screen.Forms[i].CloseQuery = false then
begin
CanClose := false;
break;
end;
end;
end;
end;
end;
{
TApplicationManager.FormClose
---------------------------------------------------------------------------
}
procedure TApplicationManager.FormClose(Sender: TObject;
var Action: TCloseAction);
var
i: integer;
begin
for i := Screen.FormCount - 1 downto 0 do
begin
if Screen.Forms[i] <> self then
begin
// Forms that have a parent will be cleaned up by that parent so
// ignore them here and only attempt to close the parent forms
if Screen.Forms[i].Parent = nil then
begin
Screen.Forms[i].Close;
end;
end;
end;
end;
До сих пор это хорошо мне служило.Я внес небольшое изменение для Vista, потому что значок для моего экрана "Main / Splash" все еще отображался.Хотя я не помню, что это было.Вероятно, мне не нужно устанавливать ширину, высоту, значение включено и отправлять сообщение скрыть на заставке.Я просто хотел убедиться, что это не появилось :-).
Необходимо было разобраться с близкими событиями.Если я правильно помню, это было необходимо для того, чтобы Windows отправила сообщение о завершении работы.Я думаю, что только основная форма получает это сообщение.
Другие советы
Извините, если это действительно глупо, но у вас нет значения formstyle для fsStayOnTop, не так ли?Это объяснило бы такое поведение.
возможно, добавьте это в createparams
Params.ExStyle := Params.ExStyle OR WS_EX_APPWINDOW;
или попробуйте сделать это в любом месте кода.Я предварительно использую его в формах.Событие onCreate.
SetWindowLong(Wnd, GWL_EXSTYLE,
GetWindowLong(Wnd, GWL_EXSTYLE) or WS_EX_APPWINDOW) ;
недостатком этого является то, что если основная форма свернута, то другие формы также скрываются, но восстанавливаются, когда это делает основная форма.