A magazintémától a projektgyakorlatig
A bejegyzéshez tartozó szolgáltatási és technikai oldalak
Akinek VCL-alkalmazásai futnak modern Windows-klienseken, előbb vagy később ugyanabba a tünetbe ütközik: az ikonok 125%/150%/200% esetén elmosódottnak, szálkásnak tűnnek vagy szürke peremet kapnak. Pont itt válik a VCL High-DPI ikonok témája gyakorlativá: nem azért, mert a High-DPI új lenne, hanem mert a problémák általában csak a napi üzem során jelentkeznek — terminálszervereken, notebook dokkolásnál vagy amint monitoronként eltérő DPI-k lépnek fel.
Az alapvető probléma szinte sosem az, hogy „a PNG tönkrement“, hanem a pipeline: honnan származik az ikon (Ressource, Datei, SVG, Font), milyen méretben szolgáltatják, hogyan kerül a TImageList-be és ki mikor hogyan skáláz. A VCL-ben több fogalom találkozik, amelyeket el kell különíteni: DPI-Awareness (hogy Windows vagy az alkalmazás maga skáláz-e), Per-Monitor-DPI (minden monitor eltérhet) és ImageList-stratégia (több Auflösungen előtartása vagy futásidőben raszterezés).
Ebben a cikkben szándékosan nem az UI-design vitákról van szó, hanem egy tiszta, üzembiztos megközelítésről: ikonok futásidőbeli skálázásáról úgy, hogy ne legyenek pixelmásszá, hogy az Alpha-Kanäle sértetlenek maradjanak és hogy a DPI‑váltások villogás vagy hibás képméretek nélkül működjenek. Emellett ismertetünk csapdákat, hibakeresési javaslatokat és egy őszinte értékelést arról, mikor éri meg a többletmunka.
Miért alakul ki pixelmaszat: a VCL skálázási láncának megértése
A homályos ikonok leggyakoribb oka egy egyszeri le-/felméretezés a rossz időpontban. Klasszikus menetrend Legacy‑VCL esetén:
- Az alkalmazás csak 16×16 vagy 24×24 ikonokat ad.
- Windows vagy a VCL skáláz 20×20 / 32×32 / 48×48 értékekre.
- A skálázó interpolációt használ, ami fényképekhez rendben van, de pixelgrafikánál elmoshatja a kontúrokat.
- Ráadásul az átlátszóság (Alpha) maszklogikába kényszerül vagy többször konvertálódik.
Különösen kellemetlen, ha több skálázás követi egymást: például amikor az ImageList már egy skálázott bitmapot ad, és Windows DPI-unaware vagy rendszer‑DPI miatt még egyszer átskáláz. Eredmény: dupla elmosás.
Egy másik, projektekben alulértékelt tényező a skálázás időzítése. Per-Monitor-DPI (PMv2, azaz Per-Monitor-DPI-Awareness v2) esetén a hatékony DPI megváltozhat, ha egy ablak monitort vált vagy ha egy Remote-Desktop kliens dinamikusan állítja a DPI-t. Ha ekkor egy TImageList vagy egy cache nincs helyesen újraépítve, hirtelen hibás méretű vagy rossz raszterű ikonokat látunk.
TImageList alatt High‑DPI esetén: tipikus csapdák valódi alkalmazásokban
A TImageList történelmileg kis bitmapokhoz készült, rögzített méretekkel, indexekkel és viszonylag merev tárolási logikával. High-DPI környezetben ebből gyakorlati csapdák adódnak:
1) Fixre bekötött Width/Height
Sok VCL-űrlap beállítja az ImageList.Width/Height értékét design-time-ban és így is hagyja. 150% esetén Windows például inkább a 16×16-ból 24×24-et szeretne készíteni. Ha a lista 16×16 marad, akkor vagy levágás (clipping) történik, vagy máshol történik a skálázás — egyik sem esztétikus.
2) PNG-alfa és maszkolási logika
Az Delphi-verziótól és a VCL-komponensektől függően könnyen keveredésbe kerülhetsz: az alfa-csatornás PNG-ket belsőleg néha 32-bites bitmapként, néha Mask+Color formátumban tartja a rendszer. Amint többször konvertálsz (PNG -> Bitmap -> ImageList -> Draw), szürke aurák vagy kemény élek jelennek meg. A hatás gyakran a háttértől függ: egy sötét eszköztáron rosszabbul látszik, mint egy világos panelen.
3) DPI-váltás futásidőben: cache-ek, handle-ök, OwnerDraw
Néhány komponens cache-eli a képmegjelenítést, vagy átveszi az ImageList-handle-öket olyan időpontban, amikor a DPI még nem végleges. Különösen toolbareknál, TreeViews/ListViews-nál és OwnerDraw-szcenáriókban DPI-váltás után időnként hibás képméreteket vagy „üres” ikonokat látsz, amíg meg nem történik egy Repaint vagy RecreateWnd.
4) Terminalserver és Remote-Desktop mint valóságteszt
Ha az alkalmazást RDP-n keresztül használják, a DPI-váltások és session-reconnectok nem ritkák. Pont ott csap vissza egy nem robusztus ImageList-stratégia: a felhasználó a reconnect után elmosódott ikonokat vagy rosszul skálázott eszköztárakat lát, még ha lokálisan minden rendben volt is.
Tiszta megközelítés: több felbontás szolgáltatása a brutális felskálázás helyett
A legfontosabb döntés koncepcionális: futtatás közben egyetlen alapgrafikából szeretnél-e felskálázni (például 16×16 -> 32×32), vagy több natív felbontást kínálsz, és DPI-től függően választod ki a megfelelőt?
Gyakorlatban szinte mindig a több felbontás megközelítés a nyerő. Felskálázást akkor érdemes alkalmazni, ha a forrás vektoralapú (SVG, icon-font), vagy ha valóban csak mérsékelt skálafaktorokra van szükség. Amint egy kis raszterképet erősen felskálázol, elveszíted az élek minőségét, és ezt a modern kijelzőkön azonnal látni fogod.
A VCL világában ma ehhez elsősorban két építőelem releváns:
- TImageCollection: konténer a képek több méretben/variánsban történő tárolásához.
- TVirtualImageList: ebből futásidőben létrehoz egy ImageList-et a jelenleg szükséges méretben, és reagál a DPI-változásokra.
Ez nem szüntet meg minden problémát, de a problémát a megfelelő helyre helyezi: tisztán definiálod a képeket, és a skálázás/selektálás konzisztensen történik.
VCL High-DPI ikonok futásidőbeli skálázása: mikor érdemes (és mikor nem)
Vannak jogos indokok, hogy ikonokat futásidőben skálázz:
- Dinamikusan töltöd be az ikonokat (például egy plugin-mappából, ügyfél-specifikus branding-csomagokból, konfigurációs csomagokból).
- Egységes pipeline-t szeretnél különböző forrásokhoz (ICO, PNG, SVG), és nem akarod a minden variánst build-időben kötni.
- Programból generálsz ikonokat (állapotjelzők, overlay-ek, összetett szimbólumok).
A futásidejű méretezés nem ésszerű, ha valójában csak klasszikus eszköztár-ikonokat használsz egy rögzített készletből. Ilyenkor a legkevesebb karbantartást igénylő megoldás: több felbontás gondos kiszolgálása, és a VCL-re bízni a választást.
Ha futásidejű méretezést alkalmazol, akkor egyértelmű szabályok szerint:
- Soha ne skálázz újra egy már egyszer skálázott bitmapot. Mindig egy master-forrásból indulj ki (ideális esetben vektor alapú vagy nagyfelbontású).
- Gyorsítótár célméretenként és DPI-nként, különben minden Paint során újraskálázol — ez CPU-t fogyaszt és akadozást okozhat.
- Alpha megtartása: minimalizáld a konverziókat, használj 32 bites RGBA-t, a háttér ne legyen raszterizálva.
Pragmatikus architektúra: ikon-pipeline mint külön komponens
Nagyobb alkalmazásoknál érdemes a témát nem szétoszlatni, hanem egy kis pipeline-t építeni. Nem kell belőle framework — inkább egy világos felelősségi kör:
- Ikon-forrás: honnan származnak a master-assetek (erőforrások, fájlok, adatbázis, API)?
- Rasterizer/Scaler: hogyan állítjuk elő a célméretet a masterből (interpoláció, szükség esetén SVG-renderelés)?
- Cache: kulcs (Icon-ID, célpixel, DPI, Theme) és életciklus (invalidálás DPI-váltásnál, Theme-váltásnál, csomagváltásnál).
- Consumer-Adapter: hogyan kerül az eredmény a VCL-struktúrákba (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?
Előny: a DPI-hibákat reprodukálhatóan egy helyen tudod debugolni, ahelyett hogy 40 űrlapon keresnéd, hol történik még egyszer a skálázás.
DPI-váltás helyes kezelése: Ereignisse, Rebuild, Repaint
A Windows alatt a DPI-váltások saját életciklust jelentenek. A VCL-ben verziótól és DPI-tudatosságtól függően több esemény/mechanizmus létezik, de az alapelv ugyanaz:
- Ha az ablak DPI-je megváltozik, a pixelen pontosnak szánt kép alapú erőforrásokat újra kell előállítani.
- Ha dinamikusan töltöd az ImageList-eket, egy puszta Invalidate gyakran nem elég — szükséged van a képek újraépítésére az új célméretben.
Egy gyakorlatias minta: DPI-változáskor (pl. Form-Scale/monitorváltás) invalidálod az ikon-cache-t az adott DPI-re, és újraépíted a érintett ImageList-eket. Fontos, hogy ne a Paint-eseményekben skálázz, hanem egy kontrollált update-blokkban (Toolbar.BeginUpdate/EndUpdate, ListView-Redraw kikapcsolva, majd vissza). Így elkerülöd a villogást és a félkész UI-állapotokat.
Miért lesz a TImageList olyan gyakran életlen: Interpolation, DPI-Rundung, Kanten
Ha egyszer megérted, hogy nem a DPI a probléma, hanem az interpoláció plusz kerekítés, sok effektus megmagyarázható:
Ha raszteres ikonjaid vannak, sok csapatnál bevett gyakorlat, hogy célméretenként külön PNG-ket szállítanak (16/20/24/32/40/48). Soknak hangzik, de gyakran kevesebb munka, mint éveken át azt hibakeresni, hogy „miért néz ki furán ezen a monitoron“.
Hibakeresés: a pixeles elmosódás reprodukálhatóvá tétele a megérzés szerinti javítás helyett
High-DPI hibák gyakran véletlenszerűnek tűnnek. Néhány ellenőrzéssel determinisztikussá tehetők:
1) DPI és ImageList-méretek futásidőben naplózása
Naplózd indításkor és DPI-váltáskor: a Form CurrentPPI-ját, a Screen.PixelsPerInch-et (figyelem: ez lehet a rendszer DPI-je), valamint az érintett listák ImageList.Width/Height értékeit. Ha monitorváltás után még mindig 16d716-t látsz, pedig 32-t várnál, az ok világos: hiányzik a Rebuild vagy túl későn történik.
2) Ikonok látható nagyítása
Egy gyors teszt, ha a toolbar-ikonokat ideiglenesen 48 px-re állítod. A rossz skálázás azonnal feltűnik. Jó pipeline-ok még 48 px-en is élesek maradnak, mert megfelelő forrásból rasztereznek.
3) Téma- és háttérváltások tesztelése
A szélén látható halo gyakran alpha/premultiply probléma. Tesztelj világos/sötét témán és színátmenetes felületeken. Ha az él a háttértől függően másként néz ki, akkor a transzparencia-kezelés nincs rendben.
4) Remote Desktop / monitorváltás mint tesztszkript
Készíts egy rövid tesztszkriptet a QA számára: indítsd az alkalmazást A monitoron (100%), helyezd az ablakot B monitorra (150%), vissza, majd RDP újracsatlakozás. Ha ez stabil, sok ügyfélprobléma már megoldódik.
Migráció meglévő alkalmazásokban: lépésenként a Big-Bang helyett
Gyarapodó Delphi-VCL alkalmazásokban az ikonlogika gyakran sok helyen jelenik meg: menük, toolbárok, ActionLists, TreeViews, státuszsávok. Egy Big-Bang átépítés kockázatos. Bevált egy lépésenkénti megközelítés:
- Leltár: Milyen ImageList-ek vannak? Mely controllok használják őket? Milyen méreteket várnak el?
- Prioritás: Először a legszembetűnőbb felületek (főeszköztár, navigáció, kontextusmenük).
- Egységes forrás: Ikonokat centralizálni (ImageCollection vagy saját loader), ahelyett, hogy formonként külön fájlokat töltenének be.
- DPI-váltás tesztelése: Az első átalakított modultól kezdve következetesen futtass DPI-váltás teszteket.
Fontos: Ha párhuzamosan üzemeltetsz régi és új pipeline-t, dokumentálj világos szabályokat. Ellenkező esetben kevert környezet alakul ki, amelyben néhány ikon éles, míg mások szemmel láthatóan homályosnak tűnnek.
Teljesítmény és memória: Futásidejű skálázás mellékhatások nélkül
A skálázás CPU-t és memóriát igényel. Egy üzleti szoftvernél ez ritkán látszik tétlen állapotban, de amikor az ablakot új monitorra húzod vagy sok Forms-szal indítod az alkalmazást, akadozás jelentkezhet. Három gyakorlati vezérelv:
- Cache-méret korlátozása: Ne tartsd örökké minden átmeneti állapotot. Ha csak 100% és 150% kell, tárold cache-ben csak ezeket.
- Késleltetett generálás: Az ikonokat csak akkor raszteresítsd, amikor a képernyő valóban igényli őket. Nagy menük esetén ez indítási időt takarít meg.
- Csoportos újragenerálás: DPI-váltásnál ne indíts egyenként minden Controlt. Egy központi rebuild megelőzi a redundáns skálázást.
Ha TVirtualImageList-t használsz, sok ezek közül koncepcionálisan már megvan, de ügyelj rá, hogy ne építs rá még egy saját skálázási réteget.
Fallback-Strategien: Was tun, wenn nicht alle Icon-Größen vorliegen?
A gyakorlatban nem mindig vannak meg az összes eszköz minden méretben. Ilyenkor világos fallback-stratégiára van szükség, hogy elkerüld a véletlenszerű eredményeket:
- Lehetőleg lefelé skálázás: Inkább skálázd le a 64 px-et 32 px-re, mint hogy egy 16 px-est felskálázz 32 px-re.
- Határozd meg a szinteket: Rögzítsd, mely célméreteket támogatod ténylegesen (pl. 16/20/24/32/40/48) és térképezd rá a DPI-t tisztán.
- Transzparencia tesztelése: Fallbackoknál különösen az alfa-csatornára ügyelj — pont ott keletkezhetnek halo-k a széleken.
Tipikus hiba, ha egyszerűen valamilyen következő méretet választasz. Ettől az ikonok élessége méretenként változik. Jobb egy szigorú, dokumentált mapping-terv.
Mikor éri meg a ráfordítás?
Három egyértelmű indikátor mutatja, hogy megéri egy átgondolt High‑DPI ikon-pipeline:
- A felhasználóid vegyes monitorokkal dolgoznak (laptop + külső) vagy sokan RDP-n keresztül használják.
- Az alkalmazás hosszú életű és éveken át karbantartásra kerül — a UI-észlelés az elfogadás része.
- Amúgy is modernizációs lépések előtt állsz (DPI-érzékenység emelése, Controls cseréje, Toolbar-elrendezés felülvizsgálata).
Ha viszont az app csak egy fix kioskrendszeren fut azonos felbontással, akkor minimalizálhatod a témát: biztosíts egy megfelelő ikonméretet, állítsd be helyesen a DPI-érzékenységet, és kész.
Fazit: High‑DPI nem kozmetikai részlet, hanem egy renderelési döntés
VCL-ben az életlen ikonok ritkán izolált hibák; általában a források, a skálázás és a cache láncolatának nem tiszta működésére utalnak. A legrobosztusabb megoldás, ha több felbontásban adod meg az ikonokat és egy központi pipeline-on keresztül (pl. ImageCollection/VirtualImageList vagy egy saját ikonréteg) konzisztensen szolgáltatod őket. Futásidejű skálázás akkor indokolt, ha dinamikus forrásaid vagy összetett szimbólumaid vannak — de csak mesterforrással, DPI-alapú cache-sel és egyértelmű rebuild-szabályokkal.
Ha konkrét tüneteket tapasztalsz (DPI-váltás tönkreteszi az ikonokat, halo a széleken, hibás méretek RDP után), érdemes a problémát célzottan izolálni és mint kis architekturális elemet kezelni, ahelyett hogy formonként workaroundokat halmoznál. Ha támogatásra van szükséged a hibakeresésben vagy lépésenkénti modernizációban, itt találod a megfelelő belépést: Kapcsolat a Net-Base Software GmbH.
Ehhez a témához a Timagelist High Dpi és Delphi Vcl Dpi-Awareness is fontos. A cikk ezeket a szempontokat érthetően rendszerezi, és bemutatja, mi számít a mindennapi gyakorlatban.
Projekt vagy modernizációs terv megbeszélése a Net-Base segítségével.
Következő lépés
Ha a téma valós projektté válik, az architektúrát, a meglévő rendszert és az üzemeltetést már korán együtt kell értékelni.
Nemcsak egyedi kérdésekben támogatunk, hanem akkor is, amikor forráskódrészletekből, örökölt rendszerekkel kapcsolatos témákból vagy portálötletekből robusztus vállalati projektet kell kialakítani.
- A jelenlegi állapotot, a célállapotot és a műszaki kockázatokat együttesen értékeljük.
- REST, az adathozzáférés, a portálok és a Rollout nem kerülnek utólagos teendőkként elhalasztásra.
- Már korán láthatja, melyik út gazdaságilag és üzemeltetési szempontból életképes.