Ativação de múltiplos aplicativos do aplicativo não está funcionando corretamente

StackOverflow https://stackoverflow.com/questions/802279

  •  03-07-2019
  •  | 
  •  

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.

  1. Clique em outro aplicativo, clique no formulário principal, o formulário principal permanece focado. (Comportando -se como esperado.)

  2. 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!

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top