Mendukung tema Gelap dan Terang di aplikasi Win32

Windows mendukung tema Terang dan Gelap sebagai opsi personalisasi di pengaturan Windows. Windows menggunakan mode Terang secara default, tetapi pengguna dapat memilih Mode gelap, yang mengubah sebagian besar UI menjadi warna gelap. Pengguna mungkin lebih suka pengaturan ini karena lebih mudah di mata di lingkungan cahaya bawah, atau mereka mungkin lebih suka antarmuka yang lebih gelap secara umum. Selain itu, warna UI yang lebih gelap dapat mengurangi penggunaan baterai pada beberapa jenis tampilan komputer, seperti layar OLED.

A split image of an app in light theme on the left, and dark theme on the right.

Kami bekerja keras untuk memperluas dukungan untuk mode Gelap tanpa merusak aplikasi yang ada, dan untuk itu kami memberikan panduan teknis untuk memperbarui aplikasi Windows desktop Win32 untuk mendukung mode Terang dan Gelap.

Mode gelap vs. Mode terang

Mode Warna dalam pengaturan (yang mencakup mode Terang dan Gelap) adalah pengaturan yang menentukan warna latar depan dan latar belakang keseluruhan untuk sistem operasi dan aplikasi.

Mode Deskripsi Contoh
Cahaya Latar belakang terang dengan latar depan gelap yang kontras.

Dalam Mode Terang, Anda umumnya akan melihat teks hitam atau gelap pada latar belakang putih atau terang.
A screenshot of the Alarms & Clock app in light mode
Gelap Latar belakang gelap dengan latar depan cahaya yang kontras.

Dalam mode Gelap, Anda umumnya akan melihat teks putih atau terang pada latar belakang hitam atau gelap.
A screenshot of the Alarms & Clocks app in Dark mode

Catatan

Alasan kita menggunakan "hitam atau gelap" dan "putih atau terang" adalah karena ada warna tambahan seperti warna Aksen yang dapat mewarnai berbagai warna latar depan dan latar belakang. Jadi Anda mungkin sebenarnya melihat teks biru muda pada latar belakang biru gelap di beberapa bagian UI, dan itu masih akan dianggap sebagai UI mode Gelap yang dapat diterima.

Karena keragaman UI yang luas di berbagai aplikasi, mode warna, dan warna latar depan dan latar belakang dimaksudkan sebagai lebih dari pedoman arah daripada aturan keras:

  • Elemen latar depan, sorotan, dan teks harus lebih dekat ke warna latar depan daripada warna latar belakang.
  • Area latar belakang besar dan solid dan latar belakang teks umumnya harus lebih dekat ke warna latar belakang daripada warna latar depan.

Dalam praktiknya, ini berarti bahwa dalam mode Gelap, sebagian besar UI akan gelap, dan dalam mode Terang sebagian besar UI akan terang. Konsep latar belakang di Windows adalah area besar warna dalam aplikasi, atau warna halaman. Konsep latar depan di Windows adalah warna teks.

Tip

Jika Anda merasa bingung bahwa warna latar depan adalah terang dalam mode Gelap dan gelap dalam mode Terang, mungkin membantu menganggap warna latar depan sebagai "warna teks default".

Mengaktifkan dukungan untuk beralih mode warna

Ada banyak pendekatan untuk menerapkan dukungan Mode gelap dalam aplikasi. Beberapa aplikasi berisi dua set UI (satu dengan warna terang dan satu dengan warna gelap). Beberapa kerangka kerja Windows UI, seperti WinUI 3, secara otomatis mendeteksi tema sistem dan menyesuaikan UI untuk mengikuti tema sistem. Untuk sepenuhnya mendukung mode Gelap, keseluruhan permukaan aplikasi harus mengikuti tema gelap.

Ada dua hal utama yang dapat Anda lakukan di aplikasi Win32 untuk mendukung tema Terang dan Gelap.

  • Mengetahui kapan Mode gelap diaktifkan

    Mengetahui kapan Mode gelap diaktifkan dalam pengaturan sistem dapat membantu Anda mengetahui kapan harus mengalihkan antarmuka pengguna aplikasi Anda ke antarmuka pengguna bermasalah mode Gelap.

  • Mengaktifkan bilah judul Mode gelap untuk aplikasi Win32

    Tidak semua aplikasi Win32 mendukung mode Gelap, sehingga Windows memberi aplikasi Win32 bilah judul terang secara default. Jika Anda siap untuk mendukung mode Gelap, Anda dapat meminta Windows untuk menggambar bilah judul gelap sebagai gantinya ketika mode Gelap diaktifkan.

Catatan

Artikel ini menyediakan contoh cara mendeteksi perubahan tema sistem, dan meminta bilah judul terang atau gelap untuk jendela aplikasi Win32 Anda. Ini tidak mencakup spesifik tentang cara mengecat ulang dan merender UI aplikasi Anda menggunakan set warna Mode gelap.

Mengetahui kapan Mode gelap diaktifkan

Langkah pertama adalah melacak pengaturan mode warna itu sendiri. Ini akan memungkinkan Anda menyesuaikan kode lukisan dan penyajian aplikasi Anda untuk menggunakan set warna Mode gelap. Melakukan ini mengharuskan aplikasi membaca pengaturan warna saat startup dan mengetahui kapan pengaturan warna berubah selama sesi aplikasi.

Untuk melakukan ini dalam aplikasi Win32, gunakan Windows::UI::Color dan deteksi apakah warna dapat diklasifikasikan sebagai terang atau gelap. Untuk menggunakan Windows::UI::Color, Anda perlu mengimpor (dalam pch.h) Windows.UI.ViewManagement header dari winrt.

#include <winrt/Windows.UI.ViewManagement.h>

Sertakan juga namespace layanan tersebut di main.cpp.

using namespace Windows::UI::ViewManagement;

Dalam main.cpp, gunakan fungsi ini untuk mendeteksi apakah warna dapat diklasifikasikan sebagai terang.

inline bool IsColorLight(Windows::UI::Color& clr)
{
    return (((5 * clr.G) + (2 * clr.R) + clr.B) > (8 * 128));
}

Fungsi ini melakukan perhitungan cepat tentang kecerahan warna yang dirasakan, dan mempertimbangkan cara-cara bahwa saluran yang berbeda dalam nilai warna RGB berkontribusi pada seberapa cerah tampilannya ke mata manusia. Ini menggunakan matematika all-integer untuk kecepatan pada CPU biasa.

Catatan

Ini bukan model untuk analisis nyata kecerahan warna. Ada baiknya untuk perhitungan cepat yang mengharuskan Anda menentukan apakah warna dapat diklasifikasikan sebagai terang atau gelap. Warna tema sering kali bisa terang tetapi tidak putih murni, atau gelap tetapi tidak hitam murni.

Sekarang setelah Anda memiliki fungsi untuk memeriksa apakah warna terang, Anda dapat menggunakan fungsi tersebut untuk mendeteksi apakah mode Gelap diaktifkan.

Mode gelap didefinisikan sebagai latar belakang gelap dengan latar depan cahaya yang kontras. Karena IsColorLight memeriksa apakah warna dianggap ringan, Anda dapat menggunakan fungsi tersebut untuk melihat apakah latar depan ringan. Jika latar depan terang, maka Mode gelap diaktifkan.

Untuk melakukan ini, Anda perlu mendapatkan jenis warna UI latar depan dari pengaturan sistem. Gunakan kode ini di main.cpp.

auto settings = UISettings();
    
auto foreground = settings.GetColorValue(UIColorType::Foreground);

UI Pengaturan mendapatkan semua pengaturan UI termasuk warna. Panggil UI Pengaturan. GetColorValue(UIColorType::Foreground) untuk mendapatkan nilai warna latar depan dari pengaturan UI.

Sekarang Anda dapat menjalankan pemeriksaan untuk melihat apakah latar depan dianggap ringan (dalam main.cpp).

bool isDarkMode = static_cast<bool>(IsColorLight(foreground));

wprintf(L"\nisDarkMode: %u\n", isDarkMode);
  • Jika latar depan terang, maka isDarkMode akan mengevaluasi ke 1 (true) yang berarti Mode gelap diaktifkan.
  • Jika latar depan gelap, maka isDarkMode akan mengevaluasi ke 0 (false) yang berarti Mode gelap tidak diaktifkan.

Untuk melacak secara otomatis saat pengaturan Mode gelap berubah selama sesi aplikasi, Anda dapat membungkus pemeriksaan seperti ini.

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);
});

Kode lengkap Anda akan terlihat seperti ini.

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);
    }
}

Ketika kode ini dijalankan:

Jika Mode gelap diaktifkan, isDarkMode akan mengevaluasi ke 1.

A screenshot of an app in dark mode.

Mengubah pengaturan dari mode Gelap ke mode Terang akan membuat isDarkModeRevoker evaluasi menjadi 0.

A screenshot of an app in light mode.

Mengaktifkan bilah judul Mode gelap untuk aplikasi Win32

Windows tidak tahu apakah aplikasi dapat mendukung Mode gelap, sehingga mengasumsikan bahwa aplikasi tidak dapat karena alasan kompatibilitas mundur. Beberapa kerangka kerja pengembangan Windows, seperti SDK Aplikasi Windows, mendukung mode Gelap secara asli dan mengubah elemen UI tertentu tanpa kode tambahan. Aplikasi Win32 sering tidak mendukung mode Gelap, sehingga Windows memberi aplikasi Win32 bilah judul terang secara default.

Namun, untuk aplikasi apa pun yang menggunakan bilah judul Windows standar, Anda dapat mengaktifkan versi gelap bilah judul saat sistem dalam mode Gelap. Untuk mengaktifkan bilah judul gelap, panggil fungsi Desktop Windows Manager (DWM) yang disebut DwmSetWindowAttribute di jendela tingkat atas Anda, menggunakan atribut jendela DWMWA_USE_IMMERSIVE_DARK_MODE. (DWM merender atribut untuk jendela.)

Contoh berikut mengasumsikan Anda memiliki jendela dengan bilah judul standar, seperti yang dibuat oleh kode ini.

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;
}

Pertama, Anda perlu mengimpor API DWM, seperti ini.

#include <dwmapi.h>

Kemudian, tentukan makro di DWMWA_USE_IMMERSIVE_DARK_MODE atas fungsi Anda InitInstance .

#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
…

Terakhir, Anda dapat menggunakan DWM API untuk mengatur bilah judul agar menggunakan warna gelap. Di sini, Anda membuat yang BOOL disebut value dan mengaturnya ke TRUE. Ini BOOL digunakan untuk memicu pengaturan atribut Windows ini. Kemudian, Anda menggunakan DwmSetWindowAttribute untuk mengubah atribut jendela untuk menggunakan warna Mode gelap.

BOOL value = TRUE;
::DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));

Berikut penjelasan selengkapnya tentang apa yang dilakukan panggilan ini.

Blok sintaks untuk DwmSetWindowAttribute terlihat seperti ini.

HRESULT DwmSetWindowAttribute(
       HWND    hwnd,
       DWORD   dwAttribute,
  [in] LPCVOID pvAttribute,
       DWORD   cbAttribute
);

Setelah meneruskan hWnd (handel ke jendela yang ingin Anda ubah) sebagai parameter pertama Anda, Anda perlu meneruskan DWMWA_USE_IMMERSIVE_DARK_MODEdwAttribute sebagai parameter . Ini adalah konstanta dalam API DWM yang memungkinkan bingkai Windows digambar dalam warna Mode gelap ketika pengaturan sistem Mode gelap diaktifkan. Jika Anda beralih ke mode Cahaya, Anda harus mengubah DWMWA_USE_IMMERSIVE_DARK_MODE dari 20 ke 0 agar bilah judul digambar dalam warna mode terang.

Parameter pvAttribute menunjuk ke nilai jenis BOOL (itulah sebabnya Anda membuat BOOL nilai sebelumnya). Anda harus pvAttributeTRUE menghormati mode Gelap untuk jendela. Jika pvAttribute adalah FALSE, jendela akan menggunakan Mode Cahaya.

Terakhir, cbAttribute perlu memiliki ukuran atribut yang diatur dalam pvAttribute. Untuk melakukan hal ini dengan mudah, kita meneruskan sizeof(value).

Kode Anda untuk menggambar bilah judul jendela gelap akan terlihat seperti ini.

#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;
}

Saat kode ini dijalankan, bilah judul aplikasi harus gelap:

A screenshot of an app with a dark title bar.

Baca juga