Nota: consulte as outras respostas, pois contêm técnicas muito valiosas. Minha resposta aqui apenas fornece advertências e avisos contra assumir que o reconhecimento de DPI é fácil.
Eu geralmente evito escalonamento com reconhecimento de DPI com TForm.Scaled = True
. A conscientização sobre DPI só é importante para mim quando se torna importante para os clientes que me ligam e estão dispostos a pagar por isso. A razão técnica por trás desse ponto de vista é que a consciência do DPI ou não, você está abrindo uma janela para um mundo de dor. Muitos controles VCL padrão e de terceiros não funcionam bem em Alta DPI. A notável exceção é que as partes VCL que envolvem os controles comuns do Windows funcionam muito bem em DPI alto. Um grande número de controles personalizados Delphi VCL de terceiros e internos não funcionam bem, ou de forma alguma, em alto DPI. Se você planeja ativar o TForm.Scaled, certifique-se de testar a 96, 125 e 150 DPI para cada formulário em seu projeto e cada terceiro e controle integrado que você usa.
O próprio Delphi é escrito em Delphi. Ele tem o sinalizador de conscientização de Alta DPI ativado, para a maioria dos formulários, embora até recentemente, como no Delphi XE2, os próprios autores do IDE tenham decidido NÃO ativar esse sinalizador de manifesto de Reconhecimento de Alto DPI. Observe que no Delphi XE4 e posterior, o sinalizador de reconhecimento de HIGH DPI é ativado e o IDE parece bom.
Eu sugiro que você não use TForm.Scaled = true (que é um padrão no Delphi então a menos que você o modifique, a maioria de seus formulários tem Scaled = true) com os sinalizadores de reconhecimento de alto DPI (como mostrado nas respostas de David) com Aplicativos VCL que são construídos usando o designer de formulário delphi integrado.
Eu tentei no passado fazer uma amostra mínima do tipo de quebra que você pode esperar ver quando TForm.Scaled for verdadeiro e quando o dimensionamento de formulário Delphi apresentar uma falha. Essas falhas nem sempre são acionadas apenas por um valor de DPI diferente de 96. Não consegui determinar uma lista completa de outras coisas, que inclui alterações de tamanho de fonte do Windows XP. Mas como a maioria dessas falhas aparecem apenas em meus próprios aplicativos, em situações bastante complexas, decidi mostrar algumas evidências que vocês mesmos podem verificar.
O Delphi XE se parece com isso quando você configura o DPI Scaling para "Fonts @ 200%" no Windows 7, e o Delphi XE2 apresenta problemas semelhantes no Windows 7 e 8, mas essas falhas parecem ter sido corrigidas no Delphi XE4:
Esses são principalmente controles VCL padrão que estão se comportando mal em DPI alto. Observe que a maioria das coisas não foi dimensionada, portanto, os desenvolvedores do Delphi IDE decidiram ignorar o reconhecimento de DPI, bem como desligar a virtualização de DPI. Uma escolha tão interessante.
Desative a virtualização de DPI apenas se desejar essa nova fonte adicional de dor e escolhas difíceis. Eu sugiro que você deixe para lá. Observe que os controles comuns do Windows geralmente parecem funcionar bem. Observe que o controle explorador de dados Delphi é um wrapper C # WinForms em torno de um controle comum de árvore do Windows padrão. Isso é uma falha pura do microsoft, e consertá-la pode exigir que o Embarcadero reescreva um controle de árvore .Net nativo puro para seu explorador de dados ou escreva algum código de verificação e modificação de propriedades de DPI para alterar a altura dos itens no controle. Nem mesmo os WinForms da Microsoft podem lidar com alto DPI de maneira limpa, automática e sem código kludge personalizado.
Atualização: Factóide interessante: Embora o IDE delphi pareça não ser "virtualizado", ele não está usando o conteúdo manifesto mostrado por David para obter "virtualização não-DPI". Talvez esteja usando alguma função da API em tempo de execução.
Atualização 2: em resposta a como eu daria suporte a 100% / 125% DPI, eu proporia um plano de duas fases. A fase 1 é inventariar meu código para controles personalizados que precisam ser corrigidos para alto DPI e, em seguida, fazer um plano para corrigi-los ou eliminá-los. A fase 2 seria pegar algumas áreas do meu código que são projetadas como formulários sem gerenciamento de layout e alterá-las para formulários que usam algum tipo de gerenciamento de layout para que as alterações de altura de fonte ou DPI possam funcionar sem cortes. Suspeito que esse trabalho de layout de "inter-controle" seria muito mais complexo na maioria dos aplicativos do que o trabalho de "intra-controle".
Atualização: Em 2016, o Delphi 10.1 Berlin mais recente está funcionando bem na minha estação de trabalho de 150 dpi.
SetProcessDPIAware
.Suas configurações no arquivo .dfm serão aumentadas corretamente, desde que
Scaled
estejamTrue
.Se você estiver definindo dimensões em código, será necessário dimensioná-las
Screen.PixelsPerInch
dividindo porForm.PixelsPerInch
. UseMulDiv
para fazer isso.Isso é o que a estrutura de persistência de formulário faz quando
Scaled
éTrue
.Na verdade, você pode apresentar um argumento convincente para substituir essa função por uma versão que codifica permanentemente um valor de 96 para o denominador. Isso permite que você use valores de dimensão absolutos e não se preocupe com a mudança de significado se acontecer de você alterar a escala da fonte em sua máquina de desenvolvimento e salvar novamente o arquivo .dfm. O motivo que importa é que a
PixelsPerInch
propriedade armazenada no arquivo .dfm é o valor da máquina na qual o arquivo .dfm foi salvo pela última vez.Portanto, continuando o tema, outra coisa a ser cautelosa é que se o seu projeto for desenvolvido em várias máquinas com diferentes valores de DPI, você descobrirá que a escala que o Delphi usa ao salvar arquivos .dfm resulta em controles que vagam por uma série de edições . No meu local de trabalho, para evitar isso, temos uma política rígida de que os formulários só sejam editados a 96dpi (escala 100%).
Na verdade, minha versão do
ScaleFromSmallFontsDimension
também permite a possibilidade da fonte do formulário diferir em tempo de execução daquela definida em tempo de design. Em máquinas XP, os formulários do meu aplicativo usam Tahoma 8pt. No Vista e acima, é usada a IU Segoe de 9pt. Isso fornece mais um grau de liberdade. A escala deve levar em conta isso porque os valores de dimensão absoluta usados no código-fonte são considerados relativos à linha de base de Tahoma de 8pt a 96dpi.Se você usar imagens ou glifos em sua IU, eles também precisam ser redimensionados. Um exemplo comum seriam os glifos usados em barras de ferramentas e menus. Você vai querer fornecer esses glifos como recursos de ícone vinculados ao seu executável. Cada ícone deve conter uma variedade de tamanhos e, em tempo de execução, você escolhe o tamanho mais apropriado e carrega-o em uma lista de imagens. Alguns detalhes sobre esse tópico podem ser encontrados aqui: Como carrego ícones de um recurso sem sofrer alias?
Outro truque útil é definir dimensões em unidades relativas, em relação a
TextWidth
ouTextHeight
. Então, se você quiser algo com cerca de 10 linhas verticais de tamanho, você pode usar10*Canvas.TextHeight('Ag')
. Esta é uma métrica muito aproximada e pronta porque não permite espaçamento entre linhas e assim por diante. No entanto, geralmente tudo o que você precisa fazer é organizar a escala correta da GUIPixelsPerInch
.Você também deve marcar seu aplicativo como tendo alto DPI . A melhor maneira de fazer isso é por meio do manifesto do aplicativo. Como as ferramentas de construção do Delphi não permitem que você personalize o manifesto que você usa, isso força você a vincular seu próprio recurso de manifesto.
O script de recurso tem a seguinte aparência:
onde
Manifest.txt
contém o manifesto real. Você também precisaria incluir a seção comctl32 v6 e definirrequestedExecutionLevel
comoasInvoker
. Em seguida, vincule esse recurso compilado ao seu aplicativo e certifique-se de que o Delphi não tente fazer o mesmo com seu manifesto. No Delphi moderno, você consegue isso definindo a opção de projeto Runtime Themes como Nenhum.O manifesto é a maneira certa de declarar que seu aplicativo reconhece alto DPI. Se você quiser apenas experimentar rapidamente, sem mexer no seu manifesto, ligue
SetProcessDPIAware
. Faça isso como a primeira coisa a fazer quando seu aplicativo é executado. De preferência, em uma das primeiras seções de inicialização da unidade, ou como a primeira coisa em seu arquivo .dpr.Se você não declarar que seu aplicativo tem reconhecimento de DPI alto, o Vista e superior irão renderizá-lo em um modo legado para qualquer escala de fonte acima de 125%. Isso parece muito terrível. Tente evitar cair nessa armadilha.
Atualização de DPI do Windows 8.1 por monitor
A partir do Windows 8.1, agora há suporte do sistema operacional para configurações de DPI por monitor ( http://msdn.microsoft.com/en-ca/magazine/dn574798.aspx ). Este é um grande problema para dispositivos modernos, que podem ter monitores diferentes conectados com recursos muito diferentes. Você pode ter uma tela de laptop com DPI muito alto e um projetor externo com DPI baixo. Apoiar tal cenário exige ainda mais trabalho do que o descrito acima.
fonte
Também é importante observar que honrar o DPI do usuário é apenas um subconjunto de seu trabalho real:
Por décadas, o Windows resolveu esse problema com a noção de execução de layout usando Dialog Units , em vez de pixels. Uma "unidade de diálogo" é definida para que o caractere médio da fonte seja
Delphi vem com uma noção (buggy) de
Scaled
, onde um formulário tenta se ajustar automaticamente com base noIsso não resolve o problema quando o usuário usa uma fonte diferente daquela com a qual você projetou o formulário, por exemplo:
6.21px x 13.00px
, em 96dpi)usuário executando com Tahoma 8pt (onde o caractere médio é
5.94px x 13.00px
, em 96dpi)Como era o caso de qualquer pessoa que desenvolvesse um aplicativo para Windows 2000 ou Windows XP.
ou
5.94px x 13.00px
, em 96dpi)6.67px x 15px
, em 96dpi)Como um bom desenvolvedor, você respeitará as preferências de fonte do usuário. Isso significa que você também precisa dimensionar todos os controles em seu formulário para corresponder ao novo tamanho da fonte:
Scaled
não vai cuidar disso para você.Piora quando:
10.52px x 25px
Agora você tem que dimensionar tudo
Scaled
não vai cuidar disso para você.Se você for inteligente, verá como honrar o DPI é irrelevante:
Você não deve olhar para a configuração de DPI do usuário, deve olhar para o tamanho da fonte . Dois usuários executando
estão executando a mesma fonte . DPI é apenas uma coisa que afeta o tamanho da fonte; as preferências do usuário são as outras.
StandardizeFormFont
Clovis notou que faço referência a uma função
StandardizeFormFont
que corrige a fonte em um formulário e o dimensiona para o novo tamanho de fonte. Não é uma função padrão, mas todo um conjunto de funções que realizam a tarefa simples que a Borland nunca realizou.O Windows possui 6 fontes diferentes; não há uma única "configuração de fonte" no Windows.
Mas sabemos por experiência que nossos formulários devem seguir a configuração da fonte do título do ícone
Uma vez que sabemos o tamanho da fonte que irá dimensionar a forma de , obtemos a altura da fonte atual do formulário ( em pixels ), e escalar por esse fator.
Por exemplo, se estou configurando o formulário para
-16
e o formulário está atualmente em-11
, precisamos dimensionar todo o formulário:A padronização acontece em duas fases. Primeiro dimensione o formulário de acordo com a proporção dos tamanhos de fonte novos: antigos. Em seguida, altere os controles (recursivamente) para usar a nova fonte.
Aqui está o trabalho de realmente dimensionar um formulário. Ele contorna bugs no próprio
Form.ScaleBy
método da Borland . Primeiro, ele deve desativar todas as âncoras no formulário, em seguida, realizar o dimensionamento e, em seguida, reativar as âncoras:e então temos que usar recursivamente a nova fonte:
Com as âncoras sendo desativadas recursivamente:
E as âncoras sendo reativadas recursivamente:
Com o trabalho de realmente alterar uma fonte de controle, deixou para:
Isso é muito mais código do que você pensou que seria; eu sei. O triste é que não há desenvolvedor Delphi na terra, exceto eu, que realmente faz seus aplicativos corretos.
fonte
Aqui está meu presente. Uma função que pode ajudá-lo com o posicionamento horizontal de elementos em seus layouts de GUI. Gratuito para todos.
fonte