Implementação de janelas normais em Delphi
Resumo Na biblioteca VCL da Delphi, para a conveniência de uso e implementação, o aplicativo de objeto de aplicativo cria uma janela oculta para o processamento de respostas das mensagens. É essa janela que faz com que os programas desenvolvidos com o VCL pareçam um pouco deformados, como não conseguir organizar e ladrilhos normalmente com outras janelas. Através da análise aprofundada do VCL, este artigo fornece uma solução que pode resolver o problema modificando apenas 3 linhas de código para o arquivo de projeto do aplicativo, sem alterações no método de programação original.
Palavra -chave VCL, janela normal, normalização
1 Introdução
Os aplicativos do Windows escritos na biblioteca da classe VCL fornecidos pela Delphi têm um recurso distinto que é obviamente diferente da janela do Windows padrão - o menu do sistema da janela principal é diferente do menu do sistema na barra de tarefas. De um modo geral, o menu do sistema na janela principal possui seis itens de menu, enquanto o menu do sistema de barra de tarefas possui apenas três itens de menu. No uso real, descobrimos que os programas desenvolvidos com a VCL têm o seguinte constrangimento:
1) Não é bonito o suficiente. Isso é certo, se não corresponder aos padrões, naturalmente parecerá um pouco deformado.
2) Não há efeito de animação quando a janela principal é minimizada.
3) A janela não pode ser organizada e ladrilhos normalmente com outras janelas.
4) O menu do sistema da barra de tarefas tem a maior prioridade. Na presença de uma janela modal, todo o programa ainda pode ser minimizado, ao contrário do design da janela modal.
O problema de minimizar os efeitos da animação na janela principal foi resolvido pela função ShowWinNoanimate nos formulários. Embora isso não tenha impacto na aplicação na maioria dos casos, é realmente inaceitável em algumas situações em que os efeitos profissionais são perseguidos. Como o C ++ Builder e o Delphi usam o mesmo conjunto de bibliotecas de classes, os problemas acima também existem nos aplicativos Windows escritos usando o C ++ Builder.
Eu discuti essa questão em artigos anteriores (pode ser encontrada na casa de Forrest Gump), e a narrativa da época parecia basicamente um truque, e eu achei esse método por acaso. A tarefa deste artigo é analisar a biblioteca da classe VCL para explicar o princípio de fazer isso e, em seguida, fornecer um método que usa apenas 3 linhas de código para resolver completamente o problema dessa "janela anormal" em Delphi.
2 Princípio
2.1 Processo de criação de aplicativos
Aqui está um arquivo típico do Application Delphi Project.
Projeto Projeto1;
usos
Formas,
Unidade1 em 'unidade1.pas' {form1};
{$ R *.res}
Começar
Application.initialize;
Application.CreatEform (TForm1, Form1);
Application.run;
fim .
A janela oculta é criada pelo objeto Aplicativo, então de onde vem o objeto de aplicativo? Pressione e segure Ctrl na janela de edição de código da Delphi e clique em Aplicativo, você descobrirá que o objeto de aplicativo é um dos vários objetos globais definidos na unidade de formulários. Isso não é suficiente, o que queremos saber é onde o objeto de aplicativo foi criado, porque uma instância da classe Tapplication deve ser criada com sucesso antes que possamos nos referir a ele.
Pense nisso, existe algum código que será executado antes do aplicativo.initialize? A propósito, é o código no segmento de código de inicialização. Depois de depurar cuidadosamente o código -fonte da VCL, você pode saber que muitas unidades no VCL possuem segmentos de código de inicialização. Todas as ações de inicialização.
Pesquisando no diretório de código -fonte VCL com a palavra -chave "tapplication.create", encontramos o código para criar o objeto de aplicativo na unidade Controls.PAS. No segmento de código de inicialização da unidade controles.
Controles unitários ;
...
Inicialização
...
Initcontrols;
procedimento initcontrols;
Começar
...
Mouse: = tmouse.create;
Tela: = tscreen.create ( nil );
Aplicação: = tapplication.create ( nil );
...
fim ;
OK, neste momento nossa análise concluiu a primeira etapa, porque, para resolver o problema das janelas anormais, devemos fazer uma coisa antes de inicializar o objeto de aplicativo, por isso é muito importante entender o processo de inicialização do aplicativo.
2.2 Variáveis ilibricas
A variável islibrary é uma das variáveis de sinalizador global definidas na unidade System.PAS. Se o valor da Islibrary for verdadeiro, significa que o módulo do programa é uma biblioteca de link dinâmica, caso contrário, é um programa executável. Alguns processos na biblioteca de classes VCL completam diferentes ações com base em diferentes valores dessa variável de sinalizador. Ou seja, essa variável desempenha um papel fundamental na solução do problema anormal da janela de Delphi.
Como mencionado anteriormente, por conveniência, uma janela invisível foi criada quando o objeto de aplicativo foi inicializado (ou seja, a janela com "tappplication" como o nome da classe visto com ferramentas como Spy ++), mas também é por causa disso invisível que a janela faz Os programas desenvolvidos com Delphi mostram muitas anormalidades. Ok, se pudermos remover esta janela invisível (e remover o menu do sistema da barra de tarefas ao mesmo tempo) e substituí -lo pela janela principal do nosso aplicativo, não seria resolvido todos os problemas?
É simples dizer, mas é necessário uma grande cirurgia para implementar o código -fonte VCL? Não seria um pouco de colocar o carrinho diante do cavalo? É claro que a resposta é não, caso contrário, este artigo não estaria disponível. O que eu quero dizer aqui é que, na próxima análise, veremos que o chamado "The Way of Programming está em uma mente", a prática do plantio não intencional de Willow no design de tapplication realmente nos deixa com a solução para esse problema . Se você não fizer análise de código -fonte, talvez seja necessário dar a volta em círculos, mas na verdade veremos que o design genial nos deixa sem mais ou menos, apenas certo.
Abra a criação do construtor da classe de tapplication e encontraremos essa linha de código.
Constructor Tapplication.create (AOWNER: TComponent);
Começar
...
se não for ilibrado, então criehandle;
...
fim ;
O que é dito aqui é que, se o módulo do programa não for uma biblioteca dinâmica de links, execute o CreateHandle e o trabalho realizado por CreateHandle é o seguinte na ajuda: "Se não houver janela de aplicativo, crie um programa de aplicativos" aqui "aqui" Janela "é a janela invisível mencionada acima, que é o culpado. Na classe de tapplication, a variável Fhandle é usada para salvar sua alça de janela. Isso é para concluir ações diferentes de acordo com o valor da Islibrary, porque nas bibliotecas dinâmicas de links, os loops de mensagens geralmente não são necessários, mas para usar objetos de aplicativo para desenvolver bibliotecas de link dinâmicas com VCL, então aqui está o design. OK, só precisamos enganar o objeto de aplicativo, atribuir islibrary ao verdadeiro antes de ser criado e filtrar a execução do CreateHandle e remover esta janela irritante.
O código atribuído à Islibrary deve obviamente ser colocado no segmento de código de inicialização de uma determinada unidade. O objeto de aplicativo é criado, no arquivo do projeto, devemos colocar a unidade que contém o código de atribuição antes da unidade de formulários, como segue (assumindo que a unidade seja denominada UnitDllexe.PAS):
modelo de programa ;
usos
Unitdllexe em 'unitdllexe.pas',
Formas,
FormMain em 'formmain.pas' {mainform},
...
A lista de código unitdllexe.pas é a seguinte:
unidade unitdllexe;
interface
Implementação
Inicialização
Islibrary: = true;
// Diga ao objeto ApplCiation que esta é uma biblioteca de link dinâmica e não precisa criar janelas ocultas.
fim .
Ok, compilar e executá -lo. Windows. Mas o problema é que a janela não pode ser minimizada. O que está acontecendo? Ainda é o jeito antigo, siga -o.
2.3 Minimização da janela principal
A minimização pertence a comandos do sistema e, finalmente, deve ser chamada de função da API DefWindowProc para minimizar a janela, por isso encontramos a função WMSySCommand em tcustomform que responde à mensagem WM_SYSCOMAND sem nenhuma dificuldade, que claramente grava para redirecionar a mensagem minimizada para .WndProc para manusear:
procedimento tcustomform.wmsysCommand (var mensagem var : twmSysCommand);
Começar
com a mensagem
Começar
if (cmdtype e $ fff0 = sc_minimize) e (application.mainform = self) então
Application.WndProc (TMessage (Mensagem))
...
fim ;
fim ;
No Application.WndProc, o método minimize de aplicação é chamado em resposta à mensagem minimizada; portanto, o cerne do problema deve estar no processo de minimizar.
procedimento TapPplication.WndProc ( Var Mensagem: TMessage);
...
Começar
...
com a mensagem
caso msg de
WM_SYSCOMAND:
caso wparam e $ fff0 de
Sc_minimize: minimize;
Sc_restore: restauração;
outro
Padrão;
...
fim ;
Por fim, encontre o Tapplication.Minimize e você entenderá tudo. A chamada para a função DEFWindowProc aqui não produz nenhum efeito, por quê? Como enganamos o objeto do aplicativo antes, filtramos a chamada do CreateHandle e não criamos a janela necessária para responder à mensagem do objeto de aplicativo, o manipulador Fhandle é 0 e a chamada não é bem -sucedida. Se você puder apontar o Fhandle para a nossa janela principal do aplicativo, ele resolverá o problema.
procedimento tapplication.minimize;
Começar
...
DEFWindowProc (Fhandle, wm_sysCommand, sc_minimize, 0);
// O valor Fhandle aqui é 0
...
fim ;
3 implementação
O design não intencional dos gênios de Borland mais uma vez nos permitiu resolver o problema. A partir da análise anterior, sabemos que na biblioteca dinâmica de links desenvolvida com o VCL, não há janela oculta para receber mensagens do Windows (CreateHandle não é executado), mas na biblioteca dinâmica de links, se você deseja exibir a janela, precisa uma janela dos pais. Como resolver esse problema? O designer da VCL projeta a variável FHandle que mantém a janela invisível como gravável, para que possamos simplesmente atribuir um valor ao Fhandle para fornecer uma janela pai para a janela da criança que precisa ser exibida. Por exemplo, em um plug-in da biblioteca dinâmica de links para exibir um formulário, geralmente passamos o identificador do objeto de aplicativo através de uma função da biblioteca de link dinâmica no arquivo executável do módulo principal e o atribuímos ao aplicativo.Handle da dinâmica Biblioteca de link no arquivo executável do módulo principal e atribua -o ao aplicativo.Handle da biblioteca de link dinâmica no aplicativo.
Procedimento setApplicationHandle (MainAppWnd: HWND)
Começar
Application.Handle: = MainAppWnd;
fim ;
OK, já que a aplicação. A Handle é na verdade apenas uma janela que é usada internamente para responder às mensagens, e a janela invisível que deveria ter sido criada foi removida por nós, precisamos apenas dar uma janela para substituir que não É o suficiente para apenas esconder a alça da janela originalmente desnecessária? Onde posso encontrar uma janela assim? A janela principal do aplicativo é a melhor opção; portanto, o código a seguir está disponível.
modelo de programa ;
usos
Unitdllexe em 'unitdllexe.pas',
Formas,
FormMain em 'formmain.pas' {mainform};
{$ R *.res}
Começar
Application.initialize;
Application.CreatEform (TFormMain, FormMain);
Application.Handle: = FormMain.Handle;
Application.run;
fim .
Então, todos os problemas foram resolvidos. Você não precisa fazer modificações no código -fonte VCL e não precisa fazer modificações no programa original. de três linhas de código para tornar sua janela de aplicativo exatamente tão normal quanto qualquer janela padrão do Windows.
1) A barra de tarefas e a barra de título da janela têm menus consistentes do sistema.
2) Há um efeito de animação quando a janela principal é minimizada.
3) A janela pode ser organizada e ladrilho normalmente com outras janelas.
4) Quando há uma janela modal, ela não pode operar na janela dos pais.
O código de implementação acima é usado em todas as versões do Delphi.