Frå magasinetema til prosjektpraksis
Passande teneste- og tekniske sider til innlegget
Den som køyrer VCL-applikasjonar på moderne Windows-klientar, snublar tidleg eller seinare over same symptom: ikon verkar ved 125%/150%/200% som om dei er uskarpe, flisa eller får ein grå kant. Nett her blir temaet VCL High-DPI-ikoner praktisk: ikkje fordi High-DPI er nytt, men fordi problema oftast viser seg først i kvardagen — på terminalserverar, ved docking- og undocking av bærbar eller så snart ulike DPI per skjerm kjem inn i biletet.
Kjernen er nesten aldri at ein PNG er øydelagd, men pipelinen: kvar kjem ikonet frå (ressurs, fil, SVG, font), i kva oppløysing blir det levert, korleis endar det i TImageList og kven skalerer når på kva måte. I VCL kjem dessutan fleire omgrep saman som må skiljast: DPI-Awareness (om Windows skalerer appen eller appen skalerer seg sjølv), Per-Monitor-DPI (kvar skjerm kan vere ulik) og ImageList-strategi (ha fleire oppløysingar tilgjengelege eller rasterisere ved køyring).
I dette innlegget handlar det medvite ikkje om UI-design-debattar, men om ein rein, driftssikker tilnærming: skalere ikon ved køyring, men slik at dei ikkje blir pikselmos, at alpha-kanalar held seg intakte og at DPI-bytte fungerer utan flimring eller feil bileteoppløysingar. I tillegg kjem fallgruver, feilsøkingspeik og ei ærleg vurdering av når ekstra innsats lønner seg.
Kvifor pikselmjøl oppstår: forstå skaleringskjedja i VCL
Den vanlegaste årsaka til uskarpe ikon er ei ein gongs ned-/oppskalering til feil tidspunkt. Klassisk flyt i legacy-VCL:
- Applikasjonen leverer ikon berre i 16×16 eller 24×24.
- Windows eller VCL skalerer til 20×20 / 32×32 / 48×48.
- Skaleringa brukar ein interpolasjon som er grei for foto, men som viskar ut kantane i pixelgrafikk.
- I tillegg blir transparens (Alpha) pressa inn i ei maskelogikk eller konvertert fleire gonger.
Særleg uheldig blir det når fleire skaleringar skjer etter kvarandre: til dømes når ImageList allereie leverer eit skalert bitmap, og Windows på grunn av DPI-unaware eller system-DPI skalerer over att. Resultat: dobbel utglatting.
Eit anna, ofte undervurdert punkt i prosjekt er skaleringstidspunktet. Ved Per-Monitor-DPI (altså PMv2, altså Per-Monitor-DPI-Awareness v2) kan den effektive DPI endre seg når eit vindauge flyttar til ein annan skjerm eller når ein Remote-Desktop-klient justerer DPI dynamisk. Dersom ei TImageList eller ein cache ikkje blir bygd opp på nytt korrekt, ser ein plutseleg ikon i feil storleik eller med feil raster.
TImageList under High-DPI: typische Fallen in echten Anwendungen
TImageList er historisk meint for små bitmapar, med faste dimensjonar, indeksar og relativt stiv lagringslogikk. Under High-DPI oppstår det praktiske fallgruver:
1) Fastkopla Width/Height
Mange VCL-skjema set ImageList.Width/Height i design-tid og let det liggje. Ved 150% vil Windows t.d. heller gjere 16×16 om til 24×24. Dersom lista blir verande på 16×16, blir bileta anten klipte eller skalerte andre stader — begge delar er uheldige.
2) PNG-alpha og maske-logikk
Avhengig av Delphi-versjon og VCL-kontroller endar ein fort i eit hybridoppsett: PNG-ar med alpha blir internt til dels halde som 32-bit bitmap, til dels som Mask+Color. Så snart du konverterer fleire gonger (PNG -> Bitmap -> ImageList -> Draw), oppstår grå halos eller harde kantar. Effekten er ofte bakgrunnssensitiv: På ein mørk verktøylinje ser det verre ut enn på eit lyst panel.
3) DPI-bytte i køyringstid: cache, handles, OwnerDraw
Nokre kontroller cache-ar bilete eller overtek ImageList-handles på eit tidspunkt der DPI-en ikkje er endeleg. Særleg for verktøylinjer, TreeViews/ListViews og OwnerDraw-scenario ser ein etter DPI-bytte sporadisk feil bileteformat eller tomme ikon, inntil eit Repaint eller ein RecreateWnd skjer.
4) Terminalserver og Remote-Desktop som realitetstest
Dersom applikasjonen blir brukt over RDP, er DPI-bytte og session-reconnects vanlege. Det er nett der ein urobust ImageList-strategi svikter: Brukaren ser etter reconnect utoverflata eller feilskala verktøylinjer, sjølv om alt var OK lokalt.
Ryddig tilnærming: tilby fleire oppløysingar i staden for brutalt oppskalering
Den viktigaste avgjerda er konseptuell: Vil du skalere ikon i køyringstid frå ei einskild basisgrafikk (t.d. 16×16 -> 32×32), eller tilbyr du fleire native oppløysingar og vel etter DPI?
I praksis vinn nesten alltid fleire oppløysingar. Oppskalering kan nyttast når kjelda er vektorbassert (SVG, Icon-Font) eller når du verkeleg treng moderate faktorar. Når du sterkoppskalerer frå eit lite rasterbilete, mistar du kantkvalitet, og det ser ein umiddelbart på moderne skjermar.
I VCL-verda er to byggjelement relevante for denne tilnærminga:
- TImageCollection: behaldar for bilete i fleire storleikar/variantar.
- TVirtualImageList: genererer derfrå i køyringstid ei ImageList i den aktuell nødvendige storleiken og responderer på DPI-endringar.
Det fjernar ikkje alle problem, men flyttar ansvaret til rett nivå: Du definerer biletkjelder ryddig, og skalering/seleksjon skjer konsekvent.
Skalere VCL High-DPI-ikonar i køyringstid: når det gir meining (og når ikkje)
Det finst legitime grunnar til å skalere ikon i køyringstid:
- Du lastar ikon dynamisk (t.d. frå ein plugin-mappe, kundetilpassa branding-pakkar, konfigurasjonspakkar).
- Du vil ha ei einskapleg pipeline for ulike kjelder (ICO, PNG, SVG) og ønskjer ikkje å binde alle variantar ved byggetid.
- Du genererer ikon programmatisk (status-badges, overlays, samansette symbol).
Køyringstidsskalering gir lite meining når du eigentleg berre har klassiske toolbar-ikon frå eit fast sett. Då er den mest vedlikehaldsvenlege vegen: lever fleire oppløysingar og la VCL velje.
Hvis du brukar kjøretidsskalering, gjer det med klare reglar:
- Aldri skaler på nytt frå eit allereie skalert bitmap. Gå alltid ut frå ei masterkjelde (ideelt sett vektorbasert eller høgoppløyst).
- Cache per målstorleik og DPI, elles skalerer du ved kvart Paint på nytt — det kostar CPU og kan gi hakking.
- Behald alpha: minimér konverteringar, bruk 32-bit RGBA, ikkje rasteriser bakgrunnen.
Pragmatisk arkitektur: Icon-Pipeline som separat komponent
I større applikasjonar løner det seg å ikkje spreie temaet overalt, men byggje ei lita pipeline. Det treng ikkje vere eit rammeverk — snarare eit klart ansvarsområde:
- Icon-Kjelde: Kor kjem master-asseta frå (ressursar, filer, database, API)?
- Rasterizer/Scaler: Korleis blir målstorleiken laga frå master (interpolasjon, eventuelt SVG-render)?
- Cache: Nøkkel (Icon-ID, mål-pikslar, DPI, Theme) og livssyklus (invalidér ved DPI-skift, Theme-skift, pakkeskift).
- Consumer-Adapter: Korleis kjem resultatet inn i VCL-strukturane (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?
Fordel: Du kan feilsøkje DPI-bugs reproducerbart på éi stad, i staden for å leite i 40 Forms etter „kor blir det skalert igjen“.
DPI-skift korrekt handtert: Hendingar, Rebuild, Repaint
Under Windows er DPI-skift ein eigen livssyklus. I VCL finst det, avhengig av versjon og DPI-awareness, fleire hendingar/mekanismer, men hovudprinsippet står att:
- Når DPI-en til vindauget endrar seg, må biletebaserte ressursar som skal vere pikselnøyaktige, bli levert på nytt.
- Når du fyller ImageLists dynamisk, held ofte ikkje eit enkelt Invalidate — du treng eit Rebuild av bilda i den nye målstorleiken.
Eit praktisk mønster er: Ved DPI-endring (t.d. Form-Scale/monitorbytte) invalidiserer du ikon-cachen for denne DPI-en og byggjer opp dei påverka ImageLists på nytt. Viktig er å ikkje skalere i Paint-hendingar, men gjere det i ein kontrollert oppdateringsblokk (Toolbar.BeginUpdate/EndUpdate, ListView-Redraw av, så på att). Slik unngår du flimmer og halvferdige UI-tilstandar.
Kvifor TImageList så ofte blir uskarp: Interpolasjon, DPI-runding, kanter
Når du først har forstått at det ikkje er DPI i seg sjølv som er problemet, men interpolasjon pluss avrunding, kan mange effektar forklarast:
- DPI-avrunding: 125% er ikkje ein rein dobling. Frå 16 px blir det 20 px (16 * 1,25). Frå 24 px blir det 30 px. Det gir ujamne tal som gjer pikselkantar vanskelegare.
- Resampling-filter: Bilinear/Bicubic gjer kantane mjukare. Det er for bilete greitt, for ikon ofte ikkje.
- Subpikselseffekter: Windows kan, avhengig av rendervegen, nytte eller ikkje nytte subpixel-antialiasing. For ikon ønskjer du kontrollerte kanter — og helst ikkje fleire filtersteg.
Har du raster-ikon, er det i mange team vanleg praksis å levere eigne PNG-ar per målstorleik (16/20/24/32/40/48). Høyrast ut som mykje, men er ofte mindre arbeid enn å år etter år debuggje kvifor det ser rart ut på denne skjermen.
Debugging: Gjer pixelfeilen reproducerbar i staden for å fikse etter magekjensle
High-DPI-feil verkar ofte tilfeldige. Med nokre enkle sjekkar blir dei deterministiske:
1) DPI og ImageList-storleikar ved køyring logge
Logg ved oppstart og ved DPI-endreing: CurrentPPI til forma, Screen.PixelsPerInch (merk: dette kan vere system-DPI), samt ImageList.Width/Height for dei berørte listene. Ser du etter ein monitorendring framleis 16 px, sjølv om du ventar 32, er årsaka klar: gjenbygging manglar eller kjem for seint.
2) Gjere ikon synleg større
Eit raskt testgrep er å setje verktøylinje-ikon midlertidig til 48 px. Dårleg skalering synest då straks. Gode pipeline held seg skarpe også ved 48 px, fordi dei rasteriserer frå ei passande kjelde.
3) Theme- og bakgrunnsbyte teste
Haloar i kantane er ofte Alpha-/Premultiply-problem. Test på lyst/mørkt og på flatar med fargegradients. Sjå kantane forskjellege ut avhengig av bakgrunnen, tyder det på feil i transparenshandsaminga.
4) Remote Desktop / monitorbytte som testskript
Lag eit kort testskript for QA: start app på monitor A (100%), flytt vindauget til monitor B (150%), tilbake, så RDP-reconnect. Er dette stabilt, har du løydd mange kundeproblem.
Migrasjon i eksisterande applikasjonar: Trinnvis i staden for Big Bang
I vaksne Delphi-VCL-applikasjonar sit ikonlogikken ofte mange stadar: menyar, toolbars, ActionLists, TreeViews, statusindikatorar. Ein Big-Bang-ombygging inneber risiko. Eit trinnvis tilnærming har vist seg å fungere:
- Oppgjer: Kva ImageLists finst? Kva Controls brukar dei? Kva storleikar blir venta?
- Prioritere: Start med dei mest synlege flata (hovudverktøylinje, navigasjon, kontekstmenyar).
- Ein førebels kjelde: Sentralsier ikon (ImageCollection eller eigen loader) i staden for å laste enkeltfiler per form.
- DPI-endreingar teste: Frå og med det første ombygde modulen køyr konsekvente DPI-endreingstestar.
Viktig: Hvis du køyrer både gamal og ny pipeline parallelt, dokumenter klare reglar. Annars oppstår eit blandingslandskap der nokre ikon er skarpe og andre tydeleg verkar uskarpe.
Ytelse og minne: Kjøretidsskaling utan sideverknader
Skalering kostar CPU og minne. I ein forretningsapplikasjon merkar ein det sjeldan i tomgang, men ved å dra eit vindauge over på ein ny skjerm eller ved oppstart med mange Forms kan det hakke. Tre praktiske retningsliner:
- Begrens cache for grafikk: Ikkje behold kvar mellomstorleik i evig tid. Hvis du berre treng 100% og 150%, cache berre desse.
- Lazy Build: Rasteriser ikon først når skjermen verkeleg treng dei. Ved store menyar sparar dette starttid.
- Batch-Rebuild: Ved DPI-skifte, triggar ikkje kvar kontroll kvar for seg. Ein sentral rebuild forhindrar redundant skalering.
Når du arbeider med TVirtualImageList, er mykje av dette allereie tatt med i konseptet, men du må likevel passe på å ikkje byggje inn ein ekstra skaleringslag på toppen.
Fallback-strategiar: Kva gjere når ikkje alle ikonstorleikar føreligg?
I realiteten har du ikkje alltid alle assets i alle storleikar. Då trengst du ei klar fallback-strategi for å unngå tilfeldige resultat:
- Føretrekk nedskalering: Heller skaler ned frå 64 px til 32 px enn å forstørre frå 16 px til 32 px.
- Definer nivå: Fastset kva målstorleikar du reelt støttar (t.d. 16/20/24/32/40/48) og kartlegg DPI konsekvent mot desse.
- Test transparens: Ved fallbacks, ver særleg merksam på alfa-kanalen — det er der haloar oppstår.
Eit typisk feil er å ta den næraste grafikkstorleiken utan reglar. Det fører til variasjon i oppfatta skarheit frå ikon til ikon. Betre er ein streng, dokumentert mapping-plan.
Når lønner arbeidet seg verkeleg?
Det finst tre klare indikatorar på at ei rein High-DPI-ikon-pipeline er verd innsatsen:
- Brukarane dine nyttar blanding av skjermar (bærbar + ekstern) eller mykje via RDP.
- Applikasjonen er langlivet og vert vedlikehalden over år — UI-opplevinga er ein del av akseptansen.
- Du har uansett moderniseringssteg framfor deg (auke DPI-awareness, byte ut kontroller, gjennomarbeide toolbar-layout).
Hvis appen derimot køyrer på eit fast kiosk-system med identisk oppløysing, kan ein halde temaet på eit minimum: lever ei passende ikonstorleik, sett DPI-awareness korrekt, ferdig.
Fazit: High-DPI er ikkje eit kosmetisk detalj, men ei rendering‑avgjerd
Uskarpe ikon i VCL er sjeldan ein isolert feil, men eit symptom på ei ureint kjede av kjelder, skalering og caching. Den mest robuste tilnærminga er å tilby ikon i fleire oppløysingar og levere dei konsekvent via ei sentral pipeline (t.d. ImageCollection/VirtualImageList eller eit eige ikonlag). Kjøretidsskaling gir meining når du har dynamiske kjelder eller samansette symbol, men berre med ei master-kjelde, DPI-basert cache og klare rebuild-reglar.
Hvis du har konkrete symptom (DPI-skifte som øydelegg ikon, haloar i kanten, feil storleikar etter RDP), løner det seg å isolere temaet målretta og behandle det som ein liten arkitekturkomponent i staden for å stable workaround per form. Hvis du treng støtte til debugging eller ei gradvis modernisering, finn du her ein passande inngang: Kontakt zur Net-Base Software GmbH.
For dette temaet er òg Timagelist High Dpi og Delphi Vcl Dpi-Awareness viktige. Artikkelen set desse aspekta på ein forståeleg måte og viser kva som er viktig i det daglege.
neste steg
Når temaet blir eit reelt prosjekt, bør arkitektur, eksisterande system og drift tidleg saman vurderast.
Vi støttar ikkje berre ved enkeltspørsmål, men òg når korte kildekodesnuttar, legacy-tema eller portalidéar skal utviklast til eit robust bedriftsprosjekt.
- Eksisterande tilstand, målbiletet og tekniske risikoar blir vurderast samla.
- REST, datatilgang, portalar og utrulling blir ikkje utsett til seinare fasar.
- De ser tidleg kva veg som er økonomisk og driftsmessig berekraftig.