Suporte a temas escuros e claros em aplicativos Win32
O Windows dá suporte aos temas Claro e Escuro como uma opção de personalização nas configurações do Windows. O Windows usa o modo Claro por padrão, mas os usuários podem escolher o modo Escuro, que altera grande parte da interface do usuário para uma cor escura. Os usuários podem preferir essa configuração porque é mais fácil para os ambientes com menos luz eles podem simplesmente preferir uma interface mais escura em geral. Além disso, as interfaces do usuário coloridas podem reduzir o uso da bateria em alguns tipos de monitores de computador, como os que têm telas OLED.
Estamos trabalhando para ampliar o suporte para o modo Escuro sem interromper os aplicativos existente. Para isso, estamos fornecendo diretrizes técnicas para atualizar um aplicativo de Windows da área de trabalho do Win32 para dar suporte aos modos Claro e Escuro.
Modo escuro vs. Modo claro
O Modo de Cor nas configurações (que inclui os modos Claro e Escuro) é uma configuração que define as cores gerais do primeiro plano e da tela de fundo para o sistema operacional e os aplicativos.
Mode | Descrição | Exemplo |
---|---|---|
Claro | Uma tela de fundo clara com um primeiro plano escuro em contraste. No Modo Claro, você geralmente verá texto preto ou escuro em telas de fundo brancas ou claras. |
|
Escuro | Uma tela de fundo escura com um primeiro plano claro em contraste. No modo Escuro, você geralmente verá texto em branco ou claro em telas de fundo pretas ou escuras. |
Observação
A razão pela qual usamos "preto ou escuro" e "branco ou claro" é porque há cores adicionais, como a de ênfase, que podem diferenciar várias cores de primeiro plano e de tela de fundo. Portanto, você pode, de fato, ver texto azul claro em uma tela de fundo azul escuro em algumas partes da interface do usuário, e isso ainda seria considerado aceitável para a interface do usuário no modo escuro.
Devido à ampla diversidade da interface do usuário em diferentes aplicativos, o modo de cor e as cores de primeiro plano e de tela de fundo são mais uma diretriz direcional do que uma regra rígida:
- Os elementos no primeiro plano, realces e texto devem estar mais próximos da cor de primeiro plano do que da cor da tela de fundo.
- Áreas da tela de fundo grandes e sólidas e telas de fundo com texto geralmente devem estar mais próximas da cor da tela de fundo do que da cor de primeiro plano.
Na prática, isso significa que, no modo Escuro, a maior parte da interface do usuário será escura e, no modo Claro, a maior parte da interface do usuário será clara. O conceito de uma tela de fundo no Windows é a grande área de cores em um aplicativo ou a cor da página. O conceito de primeiro plano no Windows é a cor do texto.
Dica
Se você achar confuso que a cor de primeiro plano é clara no modo escuro e escura no modo claro, pode ajudar a pensar na cor de primeiro plano como "a cor do texto padrão".
Habilitar o suporte para alternar modos de cor
Há muitas abordagens para implementar o suporte ao modo escuro em um aplicativo. Alguns aplicativos contêm dois conjuntos de interfaces do usuário (um com uma cor clara e outro com uma cor escura). Algumas estruturas de interface do usuário do Windows, como o WinUI 3, detectam automaticamente o tema de um sistema e ajustam a interface do usuário para seguir o tema do sistema. Para dar suporte total ao modo Escuro, a totalidade da superfície de um aplicativo deve seguir o tema escuro.
Há duas coisas principais que você pode fazer em seu aplicativo Win32 para dar suporte a temas claros e escuros.
Saber quando o modo Escuro está habilitado
Saber quando o modo escuro está habilitado nas configurações do sistema pode ajudar você a saber quando alternar a interface do usuário do aplicativo para uma interface do usuário com tema do modo escuro.
Habilitar uma barra de título do modo Escuro para aplicativos Win32
Nem todos os aplicativos Win32 dão suporte ao modo Escuro, portanto, o Windows dá aos aplicativos Win32 uma barra de título clara por padrão. Se você estiver preparado para dar suporte ao modo Escuro, poderá solicitar que Windows desenhe a barra de título escura quando o modo escuro estiver habilitado.
Observação
Este artigo fornece exemplos de maneiras de detectar alterações de tema do sistema e solicitar uma barra de título clara ou escura para a janela do aplicativo Win32. Ele não aborda detalhes de como repintar e renderizar a interface do usuário do aplicativo usando um conjunto de cores do modo escuro.
Saber quando o modo Escuro está habilitado
A primeira etapa é acompanhar a própria configuração do modo de cor. Isso permitirá que você ajuste o código de pintura e renderização do aplicativo para usar um conjunto de cores do modo Escuro. Fazer isso requer que o aplicativo leia a configuração de cores na inicialização e saiba quando a configuração de cor é alterada durante uma sessão de aplicativo.
Para fazer isso em um aplicativo Win32, use Windows::UI::Color e detecte se uma cor pode ser classificada como clara ou escura. Para usar Windows::UI::Color
, você precisa importar (no pch.h
) o cabeçalho Windows.UI.ViewManagement
do winrt.
#include <winrt/Windows.UI.ViewManagement.h>
Inclua também esse namespace em main.cpp
.
using namespace Windows::UI::ViewManagement;
No main.cpp
, use essa função para detectar se uma cor pode ser classificada como clara.
inline bool IsColorLight(Windows::UI::Color& clr)
{
return (((5 * clr.G) + (2 * clr.R) + clr.B) > (8 * 128));
}
Essa função executa um cálculo rápido do brilho percebido de uma cor e leva em consideração maneiras que diferentes canais em um valor de cor RGB contribuem para o quão brilhante é a sua aparência para o olho humano. Ela usa matemática de inteiro para aceleração em CPUs típicas.
Observação
Isso não é um modelo para análise real de brilho de cor. É bom para cálculos rápidos que exigem que você determine se uma cor pode ser classificada como clara ou escura. As cores do tema geralmente podem ser claras, mas não brancas puras, ou escuras, mas não pretas puras.
Agora que você tem uma função para verificar se uma cor é clara, você pode usar essa função para detectar se o modo Escuro está habilitado.
O modo Escuro é definido como uma tela de fundo escura com um primeiro plano de luz em contraste. Como IsColorLight
verifica se uma cor é considerada clara, você pode usar essa função para ver se o primeiro plano é claro. Se o primeiro plano for claro, o modo Escuro estará habilitado.
Para fazer isso, você precisa obter o tipo de cor da interface do usuário do primeiro plano das configurações do sistema. Use este código no main.cpp
.
auto settings = UISettings();
auto foreground = settings.GetColorValue(UIColorType::Foreground);
UISettings obtém todas as configurações da interface do usuário incluindo a cor. Chame UISettings.GetColorValue(UIColorType::Foreground) para obter o valor da cor de primeiro plano das configurações da interface do usuário.
Agora você pode executar uma verificação para ver se o primeiro plano é considerado claro (no main.cpp
).
bool isDarkMode = static_cast<bool>(IsColorLight(foreground));
wprintf(L"\nisDarkMode: %u\n", isDarkMode);
- Se o primeiro plano for claro, então
isDarkMode
avaliado como 1 (true
), o que significa que o modo Escuro está habilitado. - Se o primeiro plano for escuro, então
isDarkMode
avaliado como 0 (false
), o que significa que o modo Escuro não está habilitado.
Para acompanhar automaticamente quando a configuração do modo Escuro é alterada durante uma sessão de aplicativo, você pode encapsular suas verificações assim.
auto revoker = settings.ColorValuesChanged([settings](auto&&...)
{
auto foregroundRevoker = settings.GetColorValue(UIColorType::Foreground);
bool isDarkModeRevoker = static_cast<bool>(IsColorLight(foregroundRevoker));
wprintf(L"isDarkModeRevoker: %d\n", isDarkModeRevoker);
});
Seu código completo deve ter esta aparência.
inline bool IsColorLight(Windows::UI::Color& clr)
{
return (((5 * clr.G) + (2 * clr.R) + clr.B) > (8 * 128));
}
int main()
{
init_apartment();
auto settings = UISettings();
auto foreground = settings.GetColorValue(UIColorType::Foreground);
bool isDarkMode = static_cast<bool>(IsColorLight(foreground));
wprintf(L"\nisDarkMode: %u\n", isDarkMode);
auto revoker = settings.ColorValuesChanged([settings](auto&&...)
{
auto foregroundRevoker = settings.GetColorValue(UIColorType::Foreground);
bool isDarkModeRevoker = static_cast<bool>(IsColorLight(foregroundRevoker));
wprintf(L"isDarkModeRevoker: %d\n", isDarkModeRevoker);
});
static bool s_go = true;
while (s_go)
{
Sleep(50);
}
}
Quando esse código é executado:
Se o modo Escuro estiver habilitado, isDarkMode
será avaliado como 1.
A alteração da configuração do modo Escuro para o modo Claro fará com que isDarkModeRevoker
seja avaliado como 0.
Habilitar uma barra de título do modo Escuro para aplicativos Win32
O Windows não sabe se um aplicativo pode dar suporte ao modo Escuro, portanto, ele pressupõe que não, por motivos de compatibilidade com versões anteriores. Algumas estruturas de desenvolvimento do Windows, como o SDK do Aplicativo Windows, dão suporte ao modo Escuro nativamente e alteram determinados elementos de interface do usuário sem nenhum código adicional. Os aplicativos Win32 geralmente não dão suporte ao modo Escuro, portanto, o Windows dá aos aplicativos Win32 uma barra de título clara por padrão.
No entanto, para qualquer aplicativo que use a barra de título padrão do Windows, você poderá habilitar a versão escura da barra de título quando o sistema estiver no modo Escuro. Para habilitar a barra de título escura, chame uma função DWM (Gerenciador de Janelas da Área de Trabalho) chamada DwmSetWindowAttribute em sua janela de nível superior, usando o atributo de janela DWMWA_USE_IMMERSIVE_DARK_MODE. (O DWM renderiza atributos para uma janela.)
Os exemplos a seguir pressupõem que você tenha uma janela com uma barra de título padrão, como a criada por esse código.
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Primeiro, você precisa importar a API do DWM, assim.
#include <dwmapi.h>
Em seguida, defina as macros DWMWA_USE_IMMERSIVE_DARK_MODE
acima da sua função InitInstance
.
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
…
Por fim, você pode usar a API do DWM para definir que a barra de título use uma cor escura. Aqui, você cria um BOOL
chamado value
e o define como TRUE
. Esse BOOL
é usado para disparar essa configuração de atributo do Windows. Em seguida, você usa DwmSetWindowAttribute
para alterar o atributo de janela para usar cores do modo Escuro.
BOOL value = TRUE;
::DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
Veja uma explicação adicional do que essa chamada faz.
O bloco de sintaxe de DwmSetWindowAttribute tem essa aparência.
HRESULT DwmSetWindowAttribute(
HWND hwnd,
DWORD dwAttribute,
[in] LPCVOID pvAttribute,
DWORD cbAttribute
);
Depois de passar hWnd
(o identificador para a janela que você deseja alterar) como seu primeiro parâmetro, você precisa passar DWMWA_USE_IMMERSIVE_DARK_MODE
como o parâmetro dwAttribute
. Essa é uma constante na API do DWM que permite que o quadro do Windows seja desenhado em cores do modo Escuro quando a configuração do sistema do modo escuro estiver habilitada. Se você alternar para o modo Claro, precisará alterar DWMWA_USE_IMMERSIVE_DARK_MODE
de 20 para 0 para que a barra de título seja desenhada em cores do modo claro.
O parâmetro pvAttribute
aponta para um valor de tipo BOOL
(e é por isso que você criou o valor BOOL
anteriormente). Você precisa que pvAttribute
seja TRUE
para honrar o modo Escuro da janela. Se pvAttribute
for FALSE
, a janela usará o modo Claro.
Por fim, cbAttribute
precisa ter o tamanho do atributo que está sendo definido em pvAttribute
. Para fazer isso facilmente, passamos sizeof(value)
.
Seu código para desenhar uma barra de título de janelas escuras deve ter essa aparência.
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
BOOL value = TRUE;
::DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Quando esse código é executado, a barra de título do aplicativo deve estar escura:
Confira também
Windows developer