Tipy pro UI desktop aplikací - High DPI

Jan Holan       15.03.2012       WPF, WinForms       13739 zobrazení

V systému Windows je umožněno Zmenšit nebo zvětšit text a další položky (Make text and other items larger or smaller), jak se nyní tato volba jmenuje. Ve skutečnosti se jedná o změnu hodnoty zobrazení DPI (Dots per inch), která určuje počet zobrazovacích bodů - pixelů na jeden palec. Asi všichni víme, že pokud je toto nastavení změněno, způsobuje to problém s rozmístěním ovládacích prvků v aplikacích, které pracují přímo s pixely – tedy hlavně v nativním Win32 aplikacích a .NET Windows Forms aplikacích. Ty jsou pak leckde zobrazeny špatně a je nutné toto zobrazení ošetřit. V tomto článku si jak, jsem minule slíbil, povíme některé moje postřehy a doporučení jak právě UI Windows Forms aplikací přizpůsobit (ten kdo to někdy dělal ví, že to není vůbec jednoduché, navíc pak ještě pokud upravujeme již existující aplikaci).

Ve WPF je toto již řešeno jinak díky vektorovému přístupu a pozicování v jednotkách Device Independent Pixels – DIPs (abstrakce nad skutečnými pixely, jeden DIP je definován jako 1/96 palce). Více také zde. Zde WPF provede automatický přepočet na fyzické pixely a my se tedy o nastavení DPI nemusíme starat. Toto dnes považuji jako dost důležitou vlastnost WPF, pokud se tedy pro novou aplikaci rozhodujete zda použít technologii WinForms nebo WPF, toto rozhodně neberte na lehkou váhu.

(Někdy se může hodit převod zpět na pixely, například. při používání ElementHost controlu, postup je popsán zde.)

Proč je nutné podporovat vyšší DPI hlavně v systémech Windows 7?

Proč je dnes nutné, aby aplikace podporovali zobrazení v jiném než základním nastavení DPI - tj. vyšší hodnoty DPI než 96 DPI . Setkal jsem se s názory, že prostě napíšeme do dokumentace aplikace, že jiné zobrazení než 96 DPI aplikace nepodporuje. To šlo možná dříve, nyní je ale problém v tom, že v systémech Windows 7 (a do budoucna ve Windows 8) již neplatí, že by toto nastavení 96 DPI bylo výchozí (default). Pokud totiž např. nainstalujeme Windows 7 na počítač s LCD displejem s vyšším rozlišením než 1024x768 (který podporuje extended display identification data - EDID), Windows 7 automaticky nastaví optimální High DPI pro daný display tak, aby nastavení zobrazení co nejvíce odpovídalo fyzickému DPI zařízení (tím je zajištěna lepší čitelnost textů). Například tedy u 15.6” displeje notebooku, který podporuje HD nebo FullHD rozlišení (1920×1080) bude automaticky nastaveno 120 DPI (tj. nastavení 125% zvětšení).

DPI virtualization

Od Windows Vista je v systému také funkce nazvaná DPI virtualization (součástí DWMDesktop Windows Manager). Jedná se o funkci, která může starší aplikace (tzv. not DPI-aware aplikace) do jisté míry automaticky upravovat (automatic scaling). Ale rozhodně nedoporučuji na tuto funkci spoléhat. (Schválně kdo o této funkci vůbec věděl?) Důvodů je hned několik:

  • Aplikaci chceme provozovat i na starších systémech, např. Windows XP.
  • Funkce je možná pouze při zapnutém zobrazení Windows Aero. To sice dnes běžně bývá zapnuté, ale co například když se k počítači připojujeme přes internet pomoci Remote Desktop? Také na virtuálních prostředí Aero leckde nemáme.
  • Výsledek automatického roztažení zobrazení aplikace je rozmazaný, neostrý (blurred, fuzzy).
  • Windows Forms aplikace nemusí fungovat správně, např. DropDown ComboBoxů při otevření se zobrazují na jiném místě atd.

Proto naopak můžeme chtít tuto funkci vypnout. To se provede tak, že v manifestu naší aplikace uvedeme, že aplikace je DPI-aware tj. že aplikace si je vědoma toho, že může být používána v různých nastavení DPI a podporuje je. Tím zamezíme, aby DWM prováděl automatický scaling aplikace. Celý postup vytvoření manifestu ve Visual Studiu je popsán zde.

Pozn.: Druhou možností je volat Win32 API funkci SetProcessDPIAware.

Více o High DPI je také v této prezentaci nebo příspěvku zde.

Windows Forms aplikace

A nyní již k samotné úpravě designu Windows Forms aplikací. Odladit formuláře Windows Forms aplikace pro zobrazení při vyšších DPI není jednoduchý proces. Neexistuje zde žádný jednotný postup nebo způsob, jak správného zobrazení docílit. Díky vícero možných nastavení se také každá aplikace chova odlišně (i různé Microsoft aplikace se při zobrazení s vyšším DPI nechovají jednotně).

Tady jsou asi ty nejhlavnější a nejvíce používané doporučení:

  • Editaci designu (zobrazení designera) provádějte vždy při nastavení základních 96 DPI (100%), pokud otevřete designer při jiném nastavení celý design formuláře bude uložen špatně (and no way back).
  • Každý formulář aplikace se musí zvlášť vyzkoušet při vyšším DPI, k tomu je doporučeno zkoušet rovnou při vývoji na jiném počítači, např. virtuálu. (Na tomto jiném počítači můžete spouštět přímo exe z vašeho vývojového bin\Debug adresáře.)

AutoScaleMode

  • K nastavení chování formuláře slouží vlastnost AutoScaleMode. Já používám nastavení na hodnotu DPI. Můžete zkusit i nastavení Font, mě se ale hlavně při kombinaci se změnou Windows fontů (viz. minule) formulář zobrazil moc roztažený.
  • Nastavení AutoScaleMode provádějte v designeru formuláře, aby se provedlo ve správnou dobu sestavování prvků formuláře. Nastavení v kódu např. před nebo po InitializeComponent vede na jiné výsledky.
  • Nastavení proveďte explicitně, nepoužívejte výchozí hodnoty. Ověřte také, že designer do souboru vloží tento řádek (nastavení 96 DPI při volbě AutoScaleMode DPI):
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
  • Všechny kontejnery musí mít stejné nastavení vlastnosti AutoScaleMode.

Design formulářů

  • U prvků Label, Checkbox apod. používejte kde to lze nastavení AutoSize.
  • Aby se prvky správně zarovnali je mnohdy nutné je umístit do layout kontejnerů TableLayoutPanelFlowLayoutPanel.
  • U prvku PictureBox, který zobrazuje obrázek, nastavte vlastnost SizeMode na hodnotu StretchImage.
  • Mějte správně nastavenou hodnotu vlastnosti TextAlign podle umístění prvku.
  • U tlačítek můžete využít nastavení vlastnosti AutoSizeMode na hodnotu GrowAndShrink.
  • Veškeré práce v kódu s velikostmi v konkrétních hodnotách pixelů je nutné upravit podle hodnoty nastavení DPI např. takto:
using (var graphics = this.CreateGraphics())
{
    width = (int)Math.Round((double)width * graphics.DpiX / 96);
    height = (int)Math.Round((double)height * graphics.DpiY / 96);
}
  • Sloupce kontrolu ListView nejsou správně roztaženy podle nastavení DPI, k jejich nastavení nám poslouží tato pomocná metoda:
/// <summary> 
/// Scale the columns of a listview by the Width scale factor
/// </summary> 
/// <param name="lvw">ListView</param> 
public static void ScaleListViewColumns(System.Windows.Forms.ListView lvw)
{
    using (var graphics = lvw.CreateGraphics())
    {
        foreach (ColumnHeader column in lvw.Columns)
        {
            column.Width = (int)Math.Round(column.Width * graphics.DpiX / 96);
        }
    }
}
  • Některé další kontroly (Multi-line TextBox, RichTextBox) nejsou roztaženy správně, k vlastní úpravě prvků v kódu slouží metoda ScaleControl, kterou můžeme na formuláři přetížit.

Více také zde nebo zde.

Pro lepší představu příklad jak vypadá formulář pro přihlášení v naší reálné aplikaci. Aplikace má v manifestu nastaveno DPI-aware. Formulář má nastaveno AutoScaleMode na hodnotu DPI, přitom je ale i zaměňován font na výchozí podle Windows systému (na Windows 7 ukázce je patrný větší font Segoe UI). Pro umístění Textboxů za labely Přihlášovací jméno a Heslo je použit kontejner TableLayoutPanel s dvěma řádky a sloupci. A horní obrázek musí mít nastaveno SizeMode na hodnotu StretchImage.
(Obrázky jsou v originální velikosti.)

LoginXP
Windows XP - 96 DPI

LoginWin7
Windows 7 - 96 DPI

LoginWin7HDPI
Windows 7 - 120 DPI (125%)

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Změna řezu systémového fontu

Dobrý den, předem se omlouvám za laický dotaz. Na konci článku jsou 3 obrázky s přihlašovacím oknem. Je možné úpravou registru nebo jinak jednoduše nastavit systémové písmo (v obrázkách černý text v šedivém poli) jako tučné, aby lépe vyniklo - bylo lépe čitelné beze změny velikosti fontu?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Obrazky jsou z Windows Forms .NET aplikace a ilustrují, jak se velikost okna změní při rozdílném systémovém nastavení velikosti DPI. Změnit font na bold samozřejmě jde při vývoji aplikace úpravou vlatností fontu (resp. Font.Style). Ale pokud se ptáte jak něčím nastavit veštěrý výchozí text ve Windows oknech na bold, tak to této možnosti nevím.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback