Ativação de múltiplos aplicativos do aplicativo não está funcionando corretamente
Pergunta
Eu tenho um aplicativo Delphi que possui um navegador de documentos como o formulário principal. Quando o usuário abre um documento, abrimos uma janela do editor. Queremos ter cada editor com um botão na barra de tarefas, bem como no formulário principal. Apliquei o código normal para fazer isso (abaixo), mas quando clico no formulário principal depois de usar a janela do editor, o editor está sendo deixado na parte superior, enquanto o foco está no formulário principal. Não consigo descobrir o que está causando esse comportamento.
Configuração do estágio: Abro o formulário principal e um formulário de documento.
Clique em outro aplicativo, clique no formulário principal, o formulário principal permanece focado. (Comportando -se como esperado.)
Clique no formulário do documento, clique no formulário principal, o formulário do documento volta à frente, mas mostrado inativo. (Imagem mostra o resultado)
TEXTO DE ALT HTTP://www.matthew-jones.com/temp_xfer/titlebarfailure.jpg
Primeiro passo, este é Delphi 2007, e eu tenho no projeto:
Application.MainFormOnTaskBar := True;
Para o formulário principal, não tenho código adicional.
Para o formulário do documento, eu tenho
procedure TCommonEditForm.CreateParams(var params: TCreateParams);
begin
inherited;
params.WndParent := 0; // GetDeskTopWindow; no diff
end;
Eu tentei descobrir se houver uma mensagem que esteja fazendo isso acontecer, mas não consegue localizar nada apropriado. Eu procurei no código por qualquer coisa a ver com "ativar". Pistas são bem -vindas!
Solução
Meu aplicativo funciona da maneira que você descreve. Aqui está a abordagem que adotei. Eu gostaria de encontrar uma abordagem mais simples, mas nunca o fiz.
Comecei lendo esses artigos. Este primeiro é uma ótima redação de Peter abaixo:
http://groups-beta.google.com/group/borland.public.delphi.winapi/msg/e9f75ff48ce960eb?hl=en
Outras informações também foram encontradas aqui, no entanto, isso não provou ser uma solução válida: para meu uso: http://blogs.teamb.com/deepakshenoy/archive/2005/04/26/4050.aspx
Eventualmente, aqui está o que eu acabei.
Minha tela de respingo funciona como o formulário principal do aplicativo. O formulário principal tem um lance especial com o objeto de aplicação. Usar todas as formas secundárias me dá o comportamento que eu estava procurando.
De cada forma, eu quero na barra de tarefas, substituo o createParams. Eu faço isso nos meus formulários de edição e o que os usuários vê como a "forma principal"
procedure TUaarSalesMain.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := GetDesktopWindow;
end;
Minha forma "principal", no que diz respeito a Delphi, carrega a verdadeira forma principal em sua função de atividades. Eu uso uma variável de membro para acompanhar a primeira ativação. Então, no final da função, escondo a forma de respingo, mas não a fecho. Isso foi importante para mim, porque se o usuário estivesse editando um documento e fechou o formulário principal, eu não queria que as telas de edição fossem forçadas ao mesmo tempo. Dessa forma, todas as formas visíveis são tratadas da mesma forma.
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;
Mas ainda há um problema. Você precisa da janela principal/salpicada para fechar quando todos os outros formulários estiverem fechados. Eu tenho uma verificação extra em minhas rotinas próximas para os pais <> nil porque eu uso formulários como plugins (formam meus propósitos que eles funcionam melhor do que os quadros).
Eu realmente não gostei de usar o evento ocioso, mas não percebo que isso é um arrasto na CPU.
{
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;
Isso me serviu bem até agora. Eu fiz uma pequena mudança para o Vista porque o ícone da minha tela "principal/splash" ainda estava aparecendo. Não me lembro do que era isso. Provavelmente não preciso definir largura, altura, habilitada e enviar a mensagem Ocultar na tela Splash. Eu só queria ter certeza de que não apareceu :-).
Lidar com os eventos próximos era necessário. Se bem me lembro, isso era necessário quando o Windows enviou uma mensagem de desligamento. Eu acho que apenas o formulário principal recebe essa mensagem.
Outras dicas
Desculpe se isso é realmente estúpido, mas você não tem o FormStyle definido para fSStayontop, não é? Isso explicaria esse comportamento.
talvez adicione isso nos creameparams
Params.ExStyle := Params.ExStyle OR WS_EX_APPWINDOW;
Ou tente isso em qualquer lugar do código. Eu o uso pretendido nos formulários. Encontro.
SetWindowLong(Wnd, GWL_EXSTYLE,
GetWindowLong(Wnd, GWL_EXSTYLE) or WS_EX_APPWINDOW) ;
A desvantagem disso é que, se a forma principal for minimizada, as outras formas se escondem também, mas restauram quando a forma principal o fizer.