Tải bản đầy đủ - 0 (trang)
Hack 53. Use Global Anti-Aliased Fonts

Hack 53. Use Global Anti-Aliased Fonts

Tải bản đầy đủ - 0trang



classAAButtonextendsJButton{





publicvoidpaint(Graphicsg){







Graphics2Dg2=(Graphics2D)g;







g2.setRenderingHint(RenderingHints.KEY_











RenderingHints.VALUE_AN

super.paint(g2);





}



}



Thiswillwork,butitmeansyouhavetocreateacustom

subclassforeverycomponentinyourapplication.Notavery

appealingsolution.

MacOSXprovidesanti-aliasedrenderingthroughasystem

property,butthisonlyworksbecauseApplethoughtfullyadded

ittotheirJVM.Developersonotherplatformsareleftout.Java

5.0providesastandardsystempropertyforanti-aliasing,but

thatdoesn'thelpthemillionsof1.3and1.4JVMsoutthere.

Anotheroptionwouldbetousesomeformofcodeinjectionto

modifyeachpaintmethodatthebytecodelevel,butthis

requiresanAOPtool,custombuildscripts,andotherthingsthat

areprobablyoverkillforsuchasimplefeature.Therehastobe

abetterwayandthereactuallyis.

Along,longtimeago(inaresearchlabfar,faraway)Iworked

onascalableUItoolkitforJavacalledSubArctic.Oneofitskey

featureswasthatacomponentwouldpaintontoacanvas

objectcalledaDrawablewhatwewouldcallaGraphicsobjectin

Swing.ThisDrawablewouldbepassedfromparenttochildina

recursivetreetraversal.Drawablescouldbehackedtodoallsorts

ofcomplicatedthings,andsinceachildalwaysdrewonthe

Drawablefromitsparent,theparentcouldmakeachange

withoutthechildknowingaboutit.Thus,youcouldcreatea

parentpanelthatrotatedallgraphicsby45degreesanda

standardchildcomponent(likeabuttonorscrollbar)would



workwithoutmodification.Thisschemewasincrediblyflexible.

Wehadhacksfordropshadows,bit-leveloperations(blur,

sharpen,b/w),affinetransformations(rotate,shear),orjust

aboutanyothercrazyideayoucouldcomeupwith.Ihavelong

wantedtodothisinSwing,buttherehasalwaysbeenone

obstacle:inSwing,achild'spaint()methodisnotalwayscalled

byitsparent'spaintChildren()method.

Swingprovidesthreesub-paintmethods:paint()calls

paintBackground(),paintComponent(),andpaintChildren(),passinga

Graphicsobjecttoeach.Ideally,ifyouoverrodepaintChildren()in

acustompanelclasstoaddtherenderinghint,thenallofthe

childrenwoulddrawanti-aliasedtext.Thenyoucouldjustmake

thiscustompanelbetherootofyourframeandtherendering

hintwouldmagicallyapplytoallofthechildreninthewindow.

Thiswouldbeonechangeperframe,insteadofoneper

component(adefiniteimprovement).

Thatsoundsallniceandgood,exceptthatitdoesn'twork.The

assumptionthatachild'spaint()methodisalwayscalledbyits

parent'spaintChildren()methodiswrong.Swinglies!Inaneffort

tospeeduprendering,Swingtrackswhichcomponentshave

changedandneedredrawing.Theyare,inSwingparlance,

markedasdirty.Thesystemrepaintsallofthedirty

componentsandleavetheothersuntouched.IfSwingdetects

thatachildcomponentisdirty,butthatitsparentisnot,thenit

willjumpdirectlytothechild'spaint()method,bypassingthe

parent'spaintChildren()methodcompletely.Crummy,huh?

Youcouldworkaroundthisbymarkingeachcomponentwith

setOpaque(false).Then,Swingwouldhavenoguaranteethatthe

componentcoversitsparentcompletely,andtheparentwould

havetoberepaintedaswell.Unfortunately,setOpaque()was

reallymeantforcustomcomponents,andstandardwidgetslike

JButtonmaydrawerraticallyifopacitychanges.Tomakematters

worse,thisvariesbyL&F,somethingyoudon'twanttoaccount

for.Inaddition,youwouldhavetocallsetOpaque(false)onevery

componentintheapplication.Thisislessintrusivethan



subclassing,butstillahugeamountofwork.Nextoption,

please!

Whatyoureallywanttodoisjusthavetheentirecomponent

hierarchybemarkeddirtywhenanycomponentchanges.Then

thewholeframewillberepainted,andeachchild'spaint()

methodwillbecalledfromitsparent'spaintChildren()method,

makingtheanti-aliasedpanelideawork.Thekeytothis

strategyisalittle-knownclasscalledtheRepaintManager.

RepaintManagerisaSwingutilityclassusedtotrackthedirty



componentsinawindowandtotellSwingwhattorepaint.The

guysatSunMicrosystemsmadethisapublicclasstofacilitate

debugging,notforthestrangehackweareabouttoattempt,

butstrangehacksarethepointofthisbook,solet'sget

started.

RepaintManagerhasalotofmethods,butwe'reonlyinterestedin



oneofthem:addDirtyRegion(),whichiscalledeachtimea

componentwantstomakeaportionofitselfdirty.Theversion

seeninExample7-7willstillmarkitdirty,butthenitwillmark

theentireframedirtyaswell,triggeringafullrepaint().



Example7-7.TrickingRepaintManager

importjavax.swing.RepaintManager;

importjavax.swing.JComponent;

importjava.awt.Container;



publicclassFullRepaintManagerextendsRepaintManager{



publicvoidaddDirtyRegion(JComponentcomp,intx,int











inth){





super.addDirtyRegion(comp,x,y,w,h);





JComponentroot=getRootJComponent(comp);





//toavoidarecursiveinfiniteloop





if(comp!=root){























}







super.addDirtyRegion(root,0,0,root.getW



}

}

publicJComponentgetRootJComponent(JComponentcomp){



Containerparent=comp.getParent();



if(parentinstanceofJComponent){





returngetRootJComponent((JComponent)pa



}



returncomp;

}



TheaddDirtyRegion()implementationfirstcallsthesuperversion

andthenlooksforthehighestancestorthatisstillaninstance

ofJComponent(becauseyoudon'treallywanttheframeitself

markeddirty).Then,itcallsaddDirtyRegion()asecondtimeon

therootcomponent,markingtheentirewindowdirty.Oncethis

isdone,therepaintthreadwilltakeoverandrepainttheentire

window,ensuringthatanycustomJPanelhacks(inthiscase,

settingtheanti-aliasedrenderinghint)willbehandlednormally.

Bycreatingacustomrepaintmanagerlikethis,younowhavea

reusabletooltouseinotherhacks.

Nowthatwehaveourfullscreenrepainting,let'suseit.

Example7-8isthecodetoanAntiAliasedPanelalongwitha

simplemain()methodfortesting.



Example7-8.Testingoutanti-aliasingonaglobal

scale





publicclassAntiAliasedPanelextendsJPanel{















publicvoidpaintChildren(Graphicsg){



Graphics2Dg2=(Graphics2D)g;









g2.setRenderingHint(RenderingHints.KEY_











RenderingHints.VALUE_AN

super.paintChildren(g2);





}





publicstaticvoidmain(String[]args){







RepaintManager.setCurrentManager(newFu







JPanelpanel=newAntiAliasedPanel();







JFrameframe=newJFrame("Hack100:







frame.getContentPane().add(panel);

























JLabellabel=newJLabel("Thisisanti

label.setFont(label.getFont().deriveFon

panel.add(label);



















}







}



frame.pack();

frame.setVisible(true);



AntiAliasedPanelisjustastandardJPanelsubclasswiththe

paintChildren()methodoverriddentoturnonanti-aliasing.The

main()methodfirstsetsthecurrentRepaintManagertothecustom



version.ThenitcreatesaJFramewiththeAntiAliasedPanelasits

root,addingaJLabelwithlargetype.Figure7-18showswhat

theanti-aliasedlabellookslike.I'vealsoshownastandardlabel

inFigure7-19forcomparison.



Figure7-18.Withanti-aliasing



Figure7-19.Withoutanti-aliasing



Thedisadvantageofthisschemeisthatwehavedefeatedallof

Swing'sspeedoptimizations,butIthinkit'sworthitforthe

possibilitieswe'veopenedup.Thishackjustsetstheantialiasingrenderinghint,butwecouldalsousecustomJPanelsto

dootherthingswiththeGraphicsobject,suchasblurring,

rotation,oranimation.Formoreexamplesofthisapproach,

takealookatthepartiallytranslucentmenus[Hack#48]and

customtooltip[Hack#43]hacks.



Hack54.Anti-AliasedTextWithoutCode



Drawanti-aliasedtextwithoutanycodechangesatall

usingtwoclevertricksintroducedinJava5.0.

SinceJava1.2,UIprogrammerscandrawanti-aliasedtext.

Unfortunately,anti-aliasingmustbeenabledforeverySwing

componentbywritingafewlinesofcodeforeachofthem

[Hack#53].Thishackdescribesacleverwaytoturnonantialiasingforanentireframebyaddingacustomizedrepaint

manager.Aseveryprogrammerseeksforeffortlesssolutions,

wewilldiscoverhowtodothesamewithoutwritinganylinesof

code.



7.8.1.TheJava5.0Trick

SunMicrosystemsreleasedJava5.0,a.k.a.Tiger,inSeptember

2004.Amongmanyimprovements,likeanewthemeforthe

MetalL&F,thisreleaseofJ2SEpavesthewayforapplicationwidetextanti-aliasingsupportinMustang,theupcoming

releaseofJava.Tothisend,theSwingteamaddedaspecial

fieldinthehiddenclasscom.sun.java.swing.SwingUtilities2.Meant

forinternalpurposesonly,thisclassisleftundocumentedby

Sun'sengineeringteams.

Ifyoulookcloselyatitssourcecode,providedinsrc.zipwith

Sun'sJVM,you'lldiscoveraveryinterestingmethod:

drawTextAntialiased(JComponentc).Thismethodreturnsaboolean

valueusedbySwing'spaintingframeworktoknowwhetherthe

specifiedcomponentmustbedrawnwithanti-aliasedtext.Here

isitscompletesourcecode:

























privatestaticbooleandrawTextAntialiased(JComponentc



if(!AA_TEXT_DEFINED){





if(c!=null){







return((Boolean)c.getClientPro







AA_TEXT_PROPERTY_KEY





}





returnfalse;



}



returnAA_TEXT;

}



Asyoucansee,therearetwowaystoenableanti-aliasedtext.

Inthefirstcase,thestaticvariableAA_TEXT_DEFINEDissettofalse,

andacheckisperformedagainstthecomponent'sproperties.

Hence,acomponentinwhichthepropertyAA_TEXT_PROPERTY_KEYis

settotruewillbeanti-aliased.Youcansetthispropertytoa

givencomponentwiththefollowinglineofcode:







myComponent.putClientProperty(SwingUtilities2.AA_TEXT_P



newBoolean(true));



Addthislineofcodeinanyofyourapplications,compileit,and

launchitwithJ2SE5.0andyou'llseethemagichappen.While

extremelyuseful,thistrickisnotenoughsincewesuredon't

wanttodothatforeverycomponentinstanceinourUI.The

sourcecodeofdrawTextAntialiased()givesusacluetounderstand

howtogloballyenableanti-aliasedtext.WhenAA_TEXT_DEFINEDis

settotrue,thevalueAA_TEXTisreturned.Botharedefinedatthe

beginningofSwingUtilities2.java:









static{



fontCache=newLSBCacheEntry[CACHE_SIZE];



Objectaa=java.security.AccessController.doPr



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Hack 53. Use Global Anti-Aliased Fonts

Tải bản đầy đủ ngay(0 tr)

×