Ajakirjateemast projektipraktikasse
Sobivad teenuse- ja tehnilised lehed postituse jaoks
Kes töötab VCL-rakendustega kaasaegsetel Windows-klientidel, satub varem või hiljem sama sümptomiga kokku: ikoonid näivad 125%/150%/200% juures uduse, kulunud või saavad halli äärise. Täpselt siin muutub teema VCL High-DPI Icons praktiliseks: mitte seetõttu, et High-DPI oleks uus, vaid seetõttu, et probleemid ilmnevad enamasti alles igapäevases kasutuses — terminaliserverites, sülearvuti dokkimisel või siis, kui monitoride DPI-d erinevad.
Põhiprobleem pole peaaegu kunagi „PNG on katki“, vaid töövoog: kust ikoon pärineb (ressurss, fail, SVG, font), millises suuruses see esitatakse, kuidas see jõuab TImageListi ja kes skaleerib millal ja kuidas. VCL-is käivad selle juurde mitu mõistet, mida tuleb eristada: DPI-Awareness (kas Windows skaleerib rakendust või rakendus skaleerib end ise), Per-Monitor-DPI (iga monitor võib olla erinev) ja ImageList-Strategie (hoida mitu eraldusvõimet või rasteriseerida jooksvalt).
Selles artiklis ei käsitleta teadlikult UI-disaini arutelusid, vaid puhtalt töökindlat lähenemist: skaleerida ikoone jooksvalt nii, et need ei muutuks pikslimassiks, et alfa-kanalid jääksid puutumatuks ning et DPI-vahetused toimiksid ilma vilkumise või valede pildisuurusteta. Lisaks käsitletakse lõkse, debugimisvihjeid ja ausat hinnangut, millal lisatöö end õigustab.
Miks tekib pikslimass: VCL-i skaleerimisahelast aru saamine
Kõige sagedasem põhjus ähmaseks muutunud ikoonide puhul on üksikuline alla-/üleskaleerimine vale ajal. Legacy-VCL-i tüüpiline käik:
- Rakendus tarnib ikoone ainult suurustes 16×16 või 24×24.
- Windows või VCL skaleerib neid 20×20 / 32×32 / 48×48.
- Skaleerija kasutab interpoleerimist, mis fotode puhul sobib, kuid piksligraafika servad udustab.
- Lisaks surutakse transparentsus (Alpha) maskiloogikasse või konverteeritakse korduvalt.
Eriti halb on olukord, kui mitu skaleerimist toimuvad järjest: näiteks kui ImageList juba annab skaleeritud bitmapi ja Windows DPI-unaware või süsteemi-DPI tõttu skaleerib selle veel kord. Tulemuseks: topelt udusust.
Teine, projektides alahinnatud punkt on skaleerimise ajastus. Per-Monitor-DPI puhul (PMv2 ehk Per-Monitor-DPI-Awareness v2) võib efektiivne DPI muutuda, kui aken monitori vahetab või kui Remote-Desktop-klient DPI-d dünaamiliselt kohandab. Kui siis TImageList või vahemälu ei ehitata õigesti ümber, ilmuvad äkki ikoonid vales suuruses või vale rasteriga.
TImageList High-DPI tingimustes: tüüpilised lõksud reaalsetes rakendustes
TImageList on ajalooliselt mõeldud väikeste bitikaartide jaoks, fikseeritud mõõtude, indeksite ja suhteliselt jäiga salvestusloogikaga. High-DPI tingimustes tekivad sellest praktilised lõksud:
1) Kootud Width/Height
Paljud VCL-vormid määravad ImageList.Width/Height disaini ajal ja jätavad selle nii. 150% juures tahaks Windows näiteks 16×16 asemel pigem 24×24 kasutada. Kui loend jääb 16×16 juurde, lõigatakse pilti kas tükkideks või skaleeritakse seda mujal — mõlemad lahendused näevad kehvad välja.
2) PNG-alpha ja maskiloogika
Sõltuvalt Delphi-versioonist ja VCL-komponentidest satud kiiresti segarežiimi: alpha-ga PNG-id hoitakse sisemiselt mõnikord 32-bitise bitikaardina, mõnikord mask+värvina. Kui teed mitut konversiooni (PNG → Bitmap → ImageList → Draw), tekivad hallid halo-d või teravad servad. Efekt sõltub tihti taustast: tumedal tööriistaribal paistab see hullem kui heledal paneelil.
3) DPI-vahetus jooksval ajal: cachid, handlid, OwnerDraw
Mõned komponendid vahemällu salvestavad pildi representatsiooni või võtavad ImageList-handleid ajal, mil DPI pole veel lõplik. Eriti Toolbari, TreeView/ ListView ja OwnerDraw-situatsioonide puhul näeb DPI-vahetuste järel juhuslikult vales mõõdus pilte või tühje ikoone, kuni toimub Repaint või RecreateWnd.
4) Terminalserver ja Remote-Desktop kui reaalsustest
Kui rakendust kasutatakse RDP kaudu, pole DPI-vahetused ja sessiooni uuesti ühendused haruldased. Just seal kukub ebapüsiv ImageList-strateegia kiiresti välja: kasutaja näeb pärast reconnecti uduseid ikoone või valesti skaleeritud tööriistaribasid, kuigi lokaalselt oli kõik korras.
Puhas lähenemine: pakkida mitu lahutusvõimet, mitte jõhker üleskaldeerimine
Oluline otsus on kontseptuaalne: kas skaleerid ikoone jooksval ajal ühest baasgraafikast (nt. 16×16 → 32×32), või pakkud mitu natiivset lahutusvõimet ja valid DPI järgi sobiva?
Praktikas osutub peaaegu alati eelistatavamaks „mitu lahutusvõimet“. Upscale’i võib kasutada, kui allikas on vektoripõhine (SVG, ikoonifont) või kui vajad vaid mõõdukaid kordajaid. Kui skaleerid tugevalt väikesest rasterpildist, kaotad servade kvaliteedi ning see on kaasaegsetel ekraanidel kohe märgatav.
VCL-maailmas on selle lähenemise jaoks täna kaks olulist komponenti:
- TImageCollection: konteiner piltide jaoks mitmes suuruses/variandis.
- TVirtualImageList: genereerib sellest jooksval ajal ImageList-i hetkel vajaminevas suuruses ja reageerib DPI-muutustele.
See ei lahenda kõiki probleeme, kuid viib vastutuse õigesse kohta: määratled pildiallikad korrektselt ja skaleerimine/valik toimub järjepidevalt.
VCL High-DPI ikoonide skaleerimine jooksval ajal: millal see mõistlik on (ja millal mitte)
On eetilisi põhjuseid, miks ikoone jooksval ajal skaleerida:
- Laed ikoone dünaamiliselt (nt. plugin-kaustast, kliendispetsiifilistest brandingu-pakettidest, konfiguratsioonipakettidest).
- Tahad ühtset torujuhet eri allikatest (ICO, PNG, SVG) ja ei soovi kõiki variante build-ajal siduda.
- Generaadid ikoone programmiliselt (staatuse badge’id, overlay’d, koostatud sümbolid).
Laufzeit-skaleerimine ei ole mõttekas, kui sul on tegelikult ainult klassikalised tööriistaribaikoonid fikseeritud komplektist. Sellisel juhul on hoolduselt kõige odavam lahendus: tarnida mitu resolutsiooni korrektselt ja lasta VCL-il valida.
Kui rakendad jooksuaja skaleerimist, siis järgida selgeid reegleid:
- Ära kunagi skaleeri juba skaleeritud bitmapi uuesti. Alati alusta master-allikast (eelistatult vektorpõhine või kõrge eraldusvõimega).
- Puhverda iga sihtmõõtme ja DPI jaoks, muidu skaleerid iga paint’i ajal uuesti — see võtab CPU aega ja võib põhjustada tõmblusi.
- Alfa säilitada: vähenda konversioone, kasuta 32-bitist RGBA-d, ära rasteriseeri tausta.
Pragmatiline arhitektuur: ikoonipipeline eraldi komponendina
Suuremates rakendustes tasub teemat mitte üle kogu koodi laiali ajada, vaid ehitada väike pipeline. See ei pea olema raamistik — pigem selge vastutuspiirkond:
- Ikooniallikas: kust pärinevad master-assetid (ressursid, failid, andmebaas, API)?
- Rasterizer/Scaler: kuidas luuakse masterist sihtmõõt (interpolatsioon, vajadusel SVG-render)?
- Cache: võti (Icon-ID, siht-pikslid, DPI, Theme) ja elutsükkel (invalidatsioon DPI-vahetusel, Theme-vahetusel, paketivahetusel).
- Consumer-Adapter: kuidas jõuab tulemus VCL-struktuuridesse (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?
Eelis: saad DPI-vigu ühes kohas reprodutseeritavalt debugida, selle asemel et 40 vormi läbi otsida, kus jälle skaleeritakse.
DPI-vahetusi õigesti käsitleda: Ereignisse, Rebuild, Repaint
Under Windows on DPI-vahetustel oma elutsükkel. VCL-is on olenevalt versioonist ja DPI-awareness mitmeid sündmusi/mehhanisme, kuid põhiprintsiip jääb:
- Kui akna DPI muutub, tuleb pildipõhised ressursid, mis peavad olema pikslitäpsed, uuesti ette valmistada.
- Kui täidad ImageLists dünaamiliselt, ei piisa sageli lihtsalt Invalidate’ist — vajad Rebuildi piltide loomiseks uues sihtmõõdus.
Praktiline muster: DPI-muutusel (nt Form-Scale/monitori vahetus) invalidiseerid ikooni-puhvri selle DPI jaoks ja ehitad mõjutatud ImageLists uuesti üles. Oluline on mitte skaleerida Paint-sündmustes, vaid teha see kontrollitud uuendusbloki sees (Toolbar.BeginUpdate/EndUpdate, ListView-Redraw välja, siis uuesti sisse). Nii väldid vilkumist ja mittetäielikke UI-seisundeid.
Miks TImageList sageli udune on: Interpolation, DPI-ümardamine, servad
Kui sa oled aru saanud, et probleem ei ole DPI, vaid interpolatsioon koos ümardamisega, saab paljusid efekte selgitada:
- DPI-ümardus: 125% ei ole puhas kahekordistaja. 16 px muutub 20 px-ks (16 * 1,25). 24 px muutub 30 px-ks. Need on ebaselged väärtused, mis piksliservade täpsust halvendavad.
- Resampling-Filter: Bilinear/Bicubic pehmendavad servi. See sobib fotode puhul, ikoonide puhul sageli mitte.
- Subpixel-efektid: Windows kann je nach Renderpfad Subpixel-Antialiasing nutzen oder nicht. Bei Icons willst du kontrollierte Kanten und möglichst keine mehrfachen Filterstufen.
Wenn du Raster-Icons hast, ist es in vielen Teams gängige Praxis, pro Zielgröße eigene PNGs zu liefern (16/20/24/32/40/48). Klingt nach viel, ist aber oft weniger Aufwand als jahrelang zu debuggen, warum das auf diesem Monitor komisch aussieht.
Debugging: Pixelmatsch reproduzierbar machen statt nach Bauchgefühl zu fixen
High-DPI-Bugs wirken oft zufällig. Mit ein paar Checks werden sie deterministisch:
1) DPI und ImageList-Größen zur Laufzeit loggen
Logge bei Start und bei DPI-Wechsel: CurrentPPI des Forms, Screen.PixelsPerInch (Achtung: das kann System-DPI sein), sowie ImageList.Width/Height der betroffenen Listen. Wenn du nach einem Monitorwechsel noch 16 siehst, obwohl du 32 erwartest, ist die Ursache klar: Rebuild fehlt oder kommt zu spät.
2) Icons sichtbar vergrößern
Ein schneller Test ist, die Toolbar-Icons temporär auf 48 px zu setzen. Schlechte Skalierung springt dann sofort ins Auge. Gute Pipelines bleiben auch bei 48 px scharf, weil sie aus einer passenden Quelle rastern.
3) Theme- und Hintergrundwechsel testen
Halos am Rand sind oft Alpha-/Premultiply-Probleme. Teste auf hell/dunkel und auf Flächen mit Farbverlauf. Wenn die Kante je nach Hintergrund anders aussieht, stimmt die Transparenzbehandlung nicht.
4) Remote Desktop / Monitorwechsel als Testskript
Erstelle ein kurzes Testskript für die QS: App starten auf Monitor A (100%), Fenster auf Monitor B (150%), zurück, dann RDP reconnect. Wenn das stabil ist, sind viele Kundenprobleme bereits erschlagen.
Migration in bestehenden Anwendungen: Schrittweise statt Big Bang
In gewachsenen Delphi-VCL-Anwendungen steckt die Icon-Logik oft an vielen Stellen: Menüs, Toolbars, ActionLists, TreeViews, Statusanzeigen. Ein Big-Bang-Umbau bringt Risiko. Bewährt hat sich ein schrittweises Vorgehen:
- Inventur: Welche ImageLists gibt es? Welche Controls nutzen sie? Welche Größen werden erwartet?
- Priorisieren: Zuerst die prominentesten Flächen (Haupttoolbar, Navigation, Kontextmenüs).
- Einheitliche Quelle: Icons zentralisieren (ImageCollection oder eigener Loader), statt pro Form Einzeldateien zu laden.
- DPI-Wechsel testen: Ab dem ersten umgebauten Modul konsequent DPI-Wechsel-Tests fahren.
Oluline: kui jooksutad paralleelselt vana ja uut pipelinei, dokumenteeri selged reeglid. Vastasel juhul tekib segamaastik, kus mõned ikoonid on teravad ja teised nähtavalt udused.
Performance und Speicher: Laufzeit-Skalierung ohne Nebenwirkungen
Skaleerimine nõuab CPU-d ja mälu. Äritarkvaras ei paista see tavaliselt t fchikäigus silma, kuid akna teisaldamisel uuele monitorile või käivitamisel paljude vormidega võib esineda viivitusi. Kolm praktilist juhtjoont:
- Piira vahem e4lu suurust: Ära hoia iga vaheastet lõputult. Kui vajad ainult 100% ja 150%, hoia vahem e4lus ainult neid suurusi.
- Lazy Build: Rasteriseeri ikoonid alles siis, kui ekraan neid tegelikult vajab. Suurte men f00de puhul säästab see k e4ivitusaega.
- Batch-Rebuild: DPI-vahetusel f5nneks ei peaks iga kontrolli eraldi triggereerima. Keskne rebuild v e4ltib liigset skaleerimist.
Kui kasutad TVirtualImageListi, on paljuski see kontseptsioon juba olemas, kuid pead ikkagi tähele panema, et sa ei ehitaks lisaks oma skaleerimiskihte peale.
Fallback-Strategien: Was tun, wenn nicht alle Icon-Gr f6 dfen vorliegen?
Reaalsuses ei ole sul alati kõiki ressursse igas suuruses. Sel juhul vajad selget fallback-strateegiat, et v e4ltida juhuslikke tulemusi:
- Prefer Downscale: Parem on skaleerida 64 px-lt 32 px-le kui 16 px-lt 32 px-le fckselt e4 e4s e4 e4 e4 e4 e4.
- Definiere Stufen: M e4 e4ra, milliseid sihtsuurusi t e4iesti toetad (nt 16/20/24/32/40/48) ja kaardista DPI neile korrektselt.
- Transparenz testen: Fallbackide puhul p fcki eriti alfa-kanalile e4ra e4ra e4 e4; just seal tekivad sageli halod.
T fchine viga on lihtsalt „misiganes järgmine suurus“ kasutamine. See muudab tajutavat teravust ikooniti. Parem on range, dokumenteeritud kaardistamisplaan.
Wann lohnt sich der Aufwand wirklich?
On kolm selget indikaatorit, et puhast High-DPI-ikoonipipelinei tasub rakendada:
- Sinu kasutajad t f6 f6tavad segamonitoritega (sülearvuti + eksterne) või kasutavad palju RDPd.
- Rakendus on pikaealine ja seda hoitakse aastate jooksul; UI-taju on osa aktsepteerimisest.
- Sul on nagunii ees moderniseerimisetapid (DPI-awareness t f5stmine, kontrollide vahetamine, tööriistariba paigutuse fcmarvutamine).
Kui rakendus jookseb ainult fikseeritud kiosk-s f5steemil identse eraldusv e4 e4rdiga, saab teemat minimaalselt hoida: tarnida sobiv ikoonisuurus, seada DPI-awareness korrektselt ja see ongi kõik.
Fazit: High-DPI ist kein kosmetisches Detail, sondern eine Rendering-Entscheidung
Udused ikoonid VCLis ei ole tihti isoleeritud viga, vaid t f5end ebapuhtast ahelast: allikad, skaleerimine ja vahem e4lu. Robustseim lähenemine on pakkuda ikoone mitmes eralduses ja tarnida neid konsistentselt läbi keskse pipelini (nt ImageCollection/VirtualImageList või oma ikoonikiht). Laufzeit-skalierung on mõistlik neis olukordades, kus on d fcnamilised allikad või koostatud s fcmbolid — aga ainult koos master-allika, DPI-põhise vahem e4lu ja selgete rebuild-reeglitega.
Kui sul on konkreetsed sümptomid (DPI-vahetus rikub ikoone, halod servadel, vale suurus pärast RDPd), tasub teemat sihip e4rasesse isolatsiooni viia ja käsitleda kui väikest arhitektuurikomponenti, mitte kuhjata vormipõhiseid lahendusi. Kui vajad abi debugimisel või samm-sammult moderniseerimisel, leiad sobiva alguse siit: Kontakt zur Net-Base Software GmbH.
Selle teema puhul on olulised ka Timagelist High Dpi ja Delphi Vcl Dpi-Awareness. Artikkel paigutab need aspektid arusaadavalt konteksti ning näitab, millele igapäevatöös tähelepanu pöörata.
Arutage projekti või moderniseerimisettevõtmist Net-Base kaudu.
järgmine samm
Kui teemast saab reaalne projekt, tuleks arhitektuuri, olemasolevat keskkonda ja ekspluatatsiooni varakult koos vaadelda.
Me ei toeta ainult üksikute küsimuste lahendamist, vaid ka siis, kui lähtekoodilõikudest, pärandsüsteemidest või portaalikontseptsioonidest peab saama usaldusväärne ettevõtteprojekt.
- Olemasolev olukord, sihtpilt ja tehnilised riskid hinnatakse üheskoos.
- REST, andmejuurdepääs, portaalid ja juurutamine ei lükata hilisemateks tagajärgedeks edasi.
- Te näete varakult, milline tee on majanduslikult ja operatiivselt jätkusuutlik.