Vous êtes sur la page 1sur 12

24/12/2014

ASwingArchitectureOverview

SignIn/Register Help Country

Products
OracleTechnologyNetwork

Solutions

Communities

Downloads

Iama...

Store

Iwantto...

Support

Search

Training

Partners

About

OTN

Java

ASwingArchitectureOverview

TheInsideStoryonJFCComponentDesign
ByAmyFowler
MostSwingdevelopersknowbynowthatSwingcomponentshaveaseparablemodelandviewdesign.AndmanySwingusershaverunacross
articlessayingthatSwingisbasedonsomethingcalleda"modifiedMVC(modelviewcontroller)architecture."
ButaccurateexplanationsofhowSwingcomponentsaredesigned,andhowtheirpartsallfittogether,havebeenhardtocomebyuntilnow.
Thesilenceendswiththepublicationofthisarticle,amajorwhitepaperonSwingcomponentdesign.Itprovidesacomprehensivetechnical
overviewofSwing'smodifiedMVCstructureanddemystifiesmanyotherfacetsofSwingcomponentarchitectureaswell.
ThisdocumentpresentsatechnicaloverviewoftheSwingcomponentarchitecture.Inparticular,itcoversthefollowingareasindetail:
Designgoals
RootsinMVC
Separablemodelarchitecture
Pluggablelookandfeelarchitecture

DesignGoals

TheoverallgoalfortheSwingprojectwas:
TobuildasetofextensibleGUIcomponentstoenabledeveloperstomorerapidlydeveloppowerfulJavafrontendsforcommercialapplications.
Tothisend,theSwingteamestablishedasetofdesigngoalsearlyintheprojectthatdrovetheresultingarchitecture.Theseguidelinesmandated
thatSwingwould:
BeimplementedentirelyinJavatopromotecrossplatformconsistencyandeasiermaintenance.
ProvideasingleAPIcapableofsupportingmultiplelookandfeelssothatdevelopersandenduserswouldnotbelockedintoasinglelookand
feel.
EnablethepowerofmodeldrivenprogrammingwithoutrequiringitinthehighestlevelAPI.
AdheretoJavaBeansdesignprinciplestoensurethatcomponentsbehavewellinIDEsandbuildertools.
ProvidecompatibilitywithAWTAPIswherethereisoverlapping,toleveragetheAWTknowledgebaseandeaseporting.

RootsinMVC

Swingarchitectureisrootedinthemodelviewcontroller(MVC)designthatdatesbacktoSmallTalk.MVCarchitecturecallsforavisual
applicationtobebrokenupintothreeseparateparts:
Amodelthatrepresentsthedatafortheapplication.
Theviewthatisthevisualrepresentationofthatdata.
Acontrollerthattakesuserinputontheviewandtranslatesthattochangesinthemodel.
Earlyon,MVCwasalogicalchoiceforSwingbecauseitprovidedabasisformeetingthefirstthreeofourdesigngoalswithintheboundsofthe
lattertwo.
ThefirstSwingprototypefollowedatraditionalMVCseparationinwhicheachcomponenthadaseparatemodelobjectanddelegateditslookand
feelimplementationtoseparateviewandcontrollerobjects.
Thedelegate
Wequicklydiscoveredthatthissplitdidn'tworkwellinpracticaltermsbecausetheviewandcontrollerpartsofacomponentrequiredatight
coupling(forexample,itwasverydifficulttowriteagenericcontrollerthatdidn'tknowspecificsabouttheview).Sowecollapsedthesetwoentities
intoasingleUI(userinterface)object,asshowninthisdiagram:
(TheUIdelegateobjectshowninthispictureissometimescalledadelegateobject,orUIdelegate.TheUIdelegateusedinSwingisdescribedin
moredetailinthePluggablelookandfeelsectionofthisarticle,underthesubheading"TheUIdelegate".)
Asthediagramillustrates,SwingarchitectureislooselybasedbutnotstrictlybasedonthetraditionalMVCdesign.IntheworldofSwing,this
newquasiMVCdesignissometimesreferredtoaseparablemodelarchitecture.

Swing'sseparablemodeldesigntreatsthemodelpartofacomponentasaseparateelement,justastheMVCdesigndoes.ButSwingcollapses
theviewandcontrollerpartsofeachcomponentintoasingleUI(userinterface)object.
ToMVCornottoMVC?
Onenoteworthypointisthatasanapplicationdeveloper,youshouldthinkofacomponent'sview/controllerresponsibilitiesasbeinghandledby
thegenericcomponentclass(suchas.JButton,JTree,andsoon).Thecomponentclassthendelegatesthelookandfeelspecificaspectsof
thoseresponsibilitiestotheUIobjectthatisprovidedbythecurrentlyinstalledlookandfeel.
Forexample,thecodethatimplementsdoublebufferedpaintingisinSwing'sJComponentclass(the"mother"ofmostSwingcomponentclasses),
whilethecodethatrendersaJButton'slabelisinthebutton'sUIdelegateclass.Theprecedingdiagramillustratesthissubtle(andoften
confusing)point:

SoSwingdoeshaveastrongMVClineage.Butit'salsoimportanttoreiteratethatourMVCarchitectureservestwodistinctpurposes:
First,separatingthemodeldefinitionfromacomponentfacilitatesmodeldrivenprogramminginSwing.
Second,theabilitytodelegatesomeofacomponent'sview/controllerresponsibilitiestoseparatelookandfeelobjectsprovidesthebasisfor
Swing'spluggablelookandfeelarchitecture.
AlthoughthesetwoconceptsarelinkedbytheMVCdesign,theymaybetreatedsomewhatorthogonallyfromthedeveloper'sperspective.The
remainderofthisdocumentwillcovereachofthesemechanismsingreaterdetail.

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

1/12

24/12/2014

ASwingArchitectureOverview

Separablemodelarchitecture

Itisgenerallyconsideredgoodpracticetocenterthearchitectureofanapplicationarounditsdataratherthanarounditsuserinterface.Tosupport
thisparadigm,Swingdefinesaseparatemodelinterfaceforeachcomponentthathasalogicaldataorvalueabstraction.Thisseparationprovides
programswiththeoptionofpluggingintheirownmodelimplementationsforSwingcomponents.
ThefollowingtableshowsthecomponenttomodelmappingforSwing.

Component

ModelInterface

ModelType

JButton

ButtonModel

GUI

JToggleButton

ButtonModel

GUI/data

JCheckBox

ButtonModel

GUI/data

JRadioButton

ButtonModel

GUI/data

JMenu

ButtonModel

GUI

JMenuItem

ButtonModel

GUI

JCheckBoxMenuItem

ButtonModel

GUI/data

JRadioButtonMenuItem ButtonModel

GUI/data

JComboBox

ComboBoxModel

data

JProgressBar

BoundedRangeModel

GUI/data

JScrollBar

BoundedRangeModel

GUI/data

JSlider

BoundedRangeModel

GUI/data

JTabbedPane

SingleSelectionModel GUI

JList

ListModel

data

JList

ListSelectionModel

GUI

JTable

TableModel

data

JTable

TableColumnModel

GUI

JTree

TreeModel

data

JTree

TreeSelectionModel

GUI

JEditorPane

Document

data

JTextPane

Document

data

JTextArea

Document

data

JTextField

Document

data

JPasswordField

Document

data

GUIstatevs.applicationdatamodels
ThemodelsprovidedbySwingfallintotwogeneralcategories:GUIstatemodelsandapplicationdatamodels.
GUIstatemodels
GUIstatemodelsareinterfacesthatdefinethevisualstatusofaGUIcontrol,suchaswhetherabuttonispressedorarmed,orwhichitemsare
selectedinalist.GUIstatemodelstypicallyarerelevantonlyinthecontextofagraphicaluserinterface(GUI).Whileitisoftenusefultodevelop
programsusingGUIstatemodelseparationparticularlyifmultipleGUIcontrolsarelinkedtoacommonstate(suchasinasharedwhiteboard
program),orifmanipulatingonecontrolautomaticallychangesthevalueofanothertheuseofGUIstatemodelsisnotrequiredbySwing.Itis
possibletomanipulatethestateofaGUIcontrolthroughtoplevelmethodsonthecomponent,withoutanydirectinteractionwiththemodelatall.In
theprecedingtable,GUIstatemodelsinSwingarehighlightedinblue.
Applicationdatamodels
Anapplicationdatamodelisaninterfacethatrepresentssomequantifiabledatathathasmeaningprimarilyinthecontextoftheapplication,such
asthevalueofacellinatableortheitemsdisplayedinalist.ThesedatamodelsprovideaverypowerfulprogrammingparadigmforSwing
programsthatneedacleanseparationbetweentheirapplicationdata/logicandtheirGUI.FortrulydatacentricSwingcomponents,suchasJTree
andJTable,interactionwiththedatamodelisstronglyrecommended.Applicationdatamodelsarehighlightedinredinthetablepresentedatthe
beginningofthissection.
Ofcoursewithsomecomponents,themodelcategorizationfallssomewhereinbetweenGUIstatemodelsandapplicationdatamodels,
dependingonthecontextinwhichthemodelisused.ThisisthecasewiththeBoundedRangeModelonJSliderorJProgressBar.These
modelsarehighlightedinpurpleintheprecedingtable.
Swing'sseparablemodelAPImakesnospecificdistinctionsbetweenGUIstatemodelsandapplicationdatamodelshowever,wehaveclarified
thisdifferenceheretogivedevelopersabetterunderstandingofwhenandwhytheymightwishtoprogramwiththeseparablemodels.

Sharedmodeldefinitions
Referringagaintothetableatthebeginningofthissection,noticethatmodeldefinitionsaresharedacrosscomponentsincaseswherethedata
abstractionforeachcomponentissimilarenoughtosupportasingleinterfacewithoutovergenericizingthatinterface.Commonmodelsenable
automaticconnectabilitybetweencomponenttypes.Forexample,becausebothJSliderandJScrollbarusetheBoundedRangeModel
interface,asingleBoundedRangeModelinstancecouldbepluggedintobothaJScrollbarandaJSliderandtheirvisualstatewouldalways
remaininsync.

TheseparablemodelAPI
SwingcomponentsthatdefinemodelssupportaJavaBeansboundpropertyforthemodel.Forexample,JSliderusestheBoundedRangeModel
interfaceforitsmodeldefinition.Consequently,itincludesthefollowingmethods:
publicBoundedRangeModelgetModel()

publicvoidsetModel(BoundedRangeModelmodel)

AllSwingcomponentshaveonethingincommon:Ifyoudon'tsetyourownmodel,adefaultiscreatedandinstalledinternallyinthecomponent.
Thenamingconventionforthesedefaultmodelclassesistoprependtheinterfacenamewith"Default."ForJSlider,a
DefaultBoundedRangeModelobjectisinstantiatedinitsconstructor:
publicJSlider(intorientation,intmin,

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

2/12

24/12/2014

ASwingArchitectureOverview

intmax,intvalue)
{

checkOrientation(orientation)

this.orientation=orientation

this.model=
newDefaultBoundedRangeModel(value,0,min,max)

this.model.addChangeListener(changeListener)

updateUI()
}

IfaprogramsubsequentlycallssetModel(),thisdefaultmodelisreplaced,asinthefollowingexample:
JSliderslider=newJSlider()
BoundedRangeModelmyModel=

newDefaultBoundedRangeModel(){

publicvoidsetValue(intn){

System.out.println("SetValue:"+n)

super.setValue(n)

})
slider.setModel(myModel)

Formorecomplexmodels(suchasthoseforJTableandJList),anabstractmodelimplementationisalsoprovidedtoenabledevelopersto
createtheirownmodelswithoutstartingfromscratch.Theseclassesareprependedwith"Abstract".
Forexample,JList'smodelinterfaceisListModel,whichprovidesbothDefaultListModelandAbstractListModelclassestohelpthe
developerinbuildingalistmodel.

Modelchangenotification
Modelsmustbeabletonotifyanyinterestedparties(suchasviews)whentheirdataorvaluechanges.SwingmodelsusetheJavaBeansEvent
modelfortheimplementationofthisnotification.TherearetwoapproachesforthisnotificationusedinSwing:
Sendalightweightnotificationthatthestatehas"changed"andrequirethelistenertorespondbysendingaquerybacktothemodeltofindout
whathaschanged.Theadvantageofthisapproachisthatasingleeventinstancecanbeusedforallnotificationsfromaparticularmodelwhich
ishighlydesirablewhenthenotificationstendtobehighinfrequency(suchaswhenaJScrollBarisdragged).
Sendastatefulnotificationthatdescribesmorepreciselyhowthemodelhaschanged.Thisalternativerequiresaneweventinstanceforeach
notification.Itisdesirablewhenagenericnotificationdoesn'tprovidethelistenerwithenoughinformationtodetermineefficientlywhathas
changedbyqueryingthemodel(suchaswhenacolumnofcellschangevalueinaJTable).

Lightweightnotification
ThefollowingmodelsinSwingusethelightweightnotification,whichisbasedontheChangeListener/ChangeEventAPI:

Model
BoundedRangeModel
ButtonModel
SingleSelectionModel

Listener
ChangeListener
ChangeListener
ChangeListener

Event
ChangeEvent
ChangeEvent
ChangeEvent

TheChangeListenerinterfacehasasinglegenericmethod:
publicvoidstateChanged(ChangeEvente)

TheonlystateinaChangeEventistheevent"source."Becausethesourceisalwaysthesameacrossnotifications,asingleinstancecanbeused
forallnotificationsfromaparticularmodel.ModelsthatusethismechanismsupportthefollowingmethodstoaddandremoveChangeListeners:
publicvoidaddChangeListener(ChangeListenerl)

publicvoidremoveChangeListener(ChangeListenerl)

Therefore,tobenotifiedwhenthevalueofaJSliderhaschanged,thecodemightlooklikethis:
JSliderslider=newJSlider()
BoundedRangeModelmodel=slider.getModel()
model.addChangeListener(newChangeListener(){

publicvoidstateChanged(ChangeEvente){

//needtoquerythemodel

//togetupdatedvalue...

BoundedRangeModelm=

(BoundedRangeModel)e.getSource()

System.out.println("modelchanged:"+

m.getValue())

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

3/12

24/12/2014

ASwingArchitectureOverview

}
})

Toprovideconvenienceforprogramsthatdon'twishtodealwithseparatemodelobjects,someSwingcomponentclassesalsoprovidetheability
toregisterChangeListenersdirectlyonthecomponent(sothecomponentcanlistenforchangesonthemodelinternallyandthenpropagates
thoseeventstoanylistenersregistereddirectlyonthecomponent).Theonlydifferencebetweenthesenotificationsisthatforthemodelcase,the
eventsourceisthemodelinstance,whileforthecomponentcase,thesourceisthecomponent.
Sowecouldsimplifytheprecedingexampleto:
JSliderslider=newJSlider()
slider.addChangeListener(newChangeListener(){

publicvoidstateChanged(ChangeEvente){

//thesourcewillbe

//thesliderthistime..

JSliders=(JSlider)e.getSource()

System.out.println("valuechanged:"+

s.getValue())

}
})

Statefulnotification
ModelsthatsupportstatefulnotificationprovideeventListenerinterfacesandeventobjectsspecifictotheirpurpose.Thefollowingtableshowsthe
breakdownforthosemodels:

Model
ListModel
ListSelectionModel

Listener
ListDataListener
ListSelectionListener

Event
ListDataEvent
ListSelectionEvent

ComboBoxModel
TreeModel

ListDataListener
TreeModelListener

ListDataEvent
TreeModelEvent

TreeSelectionModel

TreeSelectionListener

TreeSelectionEvent

TableModel

Document

TableModelListener
TableColumnModel
Listener
DocumentListener

TableModelEvent
TableColumnModel
Event
DocumentEvent

Document

UndoableEditListener

UndoableEditEvent

TableColumnModel

TheusageoftheseAPIsissimilartothelightweightnotification,exceptthatthelistenercanquerytheeventobjectdirectlytofindoutwhathas
changed.Forexample,thefollowingcodedynamicallytrackstheselectediteminaJList:
Stringitems[]={"One","Two","Three")
JListlist=newJList(items)
ListSelectionModelsModel=list.getSelectionModel()
sModel.addListSelectionListener

(newListSelectionListener(){

publicvoidvalueChanged(ListSelectionEvente){

//getchangeinformationdirectly

//fromtheeventinstance...

if(!e.getValueIsAdjusting()){

System.out.println("selectionchanged:"+

e.getFirstIndex())

}
})

AutomaticViewUpdates
Amodeldoesnothaveanyintrinsicknowledgeoftheviewthatrepresentsit.(Thisrequirementiscriticaltoenablemultipleviewsonthesame
model).Instead,amodelhasonlyalistoflistenersinterestedinknowingwhenitsstatehaschanged.ASwingcomponenttakesresponsibilityfor
hookinguptheappropriatemodellistenersothatitcanappropriatelyrepaintitselfasthemodelchanges(ifyoufindthatacomponentisnot
updatingautomaticallywhenthemodelchanges,itisabug!).Thisistruewhetheradefaultinternalmodelisusedorwhetheraprograminstallsits
ownmodelimplementation.

Ignoringmodelscompletely
Asmentionedpreviously,mostcomponentsprovidethemodeldefinedAPIdirectlyinthecomponentclasssothatthecomponentcanbe
manipulatedwithoutinteractingwiththemodelatall.Thisisconsideredperfectlyacceptableprogrammingpractice(especiallyfortheGUIstate
models).Forexample,followingisJSlider'simplementationofgetValue(),whichinternallydelegatesthemethodcalltoitsmodel:
publicintgetValue(){

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

4/12

24/12/2014

ASwingArchitectureOverview

returngetModel().getValue()
}

Andsoprogramscansimplydothefollowing:
JSliderslider=newJSlider()
intvalue=slider.getValue()
//what'sa"model,"anyway?

Separablemodelsummary
Sowhileit'susefultounderstandhowSwing'smodeldesignworks,itisn'tnecessarytousethemodelAPIforallaspectsofSwingprogramming.
Youshouldcarefullyconsideryourapplication'sindividualneedsanddeterminewherethemodelAPIwillenhanceyourcodewithoutintroducing
unnecessarycomplexity.
Inparticular,werecommendtheusageoftheApplicationDatacategoryofmodelsforSwing(modelsforJTable,JTree,andthelike)because
theycangreatlyenhancethescalabilityandmodularityofyourapplicationoverthelongrun.

Pluggablelookandfeelarchitecture

Swing'spluggablelookandfeelarchitectureallowsustoprovideasinglecomponentAPIwithoutdictatingaparticularlookandfeel.TheSwing
toolkitprovidesadefaultsetoflookandfeelshowever,theAPIis"open"adesignthatadditionallyallowsdeveloperstocreatenewlookand
feelimplementationsbyeitherextendinganexistinglookandfeelorcreatingonefromscratch.AlthoughthepluggablelookandfeelAPIis
extensible,itwasintentionallydesignedatalevelbelowthebasiccomponentAPIinsuchawaythatadeveloperdoesnotneedtounderstandits
intricatedetailstobuildSwingGUIs.(Butifyouwanttoknow,readon...)
Whilewedon'texpect(oradvise)themajorityofdeveloperstocreatenewlookandfeelimplementations,werealizePL&Fisaverypowerful
featureforasubsetofapplicationsthatwanttocreateauniqueidentity.Asitturnsout,PL&FisalsoideallysuitedforuseinbuildingGUIsthatare
accessibletouserswithdisabilities,suchasvisuallyimpairedusersoruserswhocannotoperateamouse.
Inanutshell,pluggablelookandfeeldesignsimplymeansthattheportionofacomponent'simplementationthatdealswiththepresentation(the
look)andeventhandling(thefeel)isdelegatedtoaseparateUIobjectsuppliedbythecurrentlyinstalledlookandfeel,whichcanbechangedat
runtime.

ThepluggablelookandfeelAPI
ThepluggablelookandfeelAPIincludes:
SomesmallhooksintheSwingcomponentclasses.
SometoplevelAPIforlookandfeelmanagement.
AmorecomplexAPIthatactuallyimplementslookandfeelsinseparatepackages.
Thecomponenthooks
EachSwingcomponentthathaslookandfeelspecificbehaviordefinesanabstractclassintheswing.plafpackagetorepresentitsUIdelegate.
Thenamingconventionfortheseclassesistotaketheclassnameforthecomponent,removethe"J"prefix,andappend"UI."Forexample,
JButtondefinesitsUIdelegatewiththeplafclassButtonUI.
TheUIdelegateiscreatedinthecomponent'sconstructorandisaccessibleasaJavaBeansboundpropertyonthecomponent.Forexample,
JScrollBarprovidesthefollowingmethodstoaccessitsUIdelegate:
publicScrollBarUIgetUI()

publicvoidsetUI(ScrollBarUIui)

ThisprocessofcreatingaUIdelegateandsettingitasthe"UI"propertyforacomponentisessentiallythe"installation"ofacomponent'slookand
feel.
EachcomponentalsoprovidesamethodwhichcreatesandsetsaUIdelegateforthe"default"lookandfeel(thismethodisusedbythe
constructorwhendoingtheinstallation):
publicvoidupdateUI()

AlookandfeelimplementationprovidesconcretesubclassesforeachabstractplafUIclass.Forexample,theWindowslookandfeeldefines
WindowsButtonUI,aWindowsScrollBarUI,andsoon.WhenacomponentinstallsitsUIdelegate,itmusthaveawaytolookuptheappropriate
concreteclassnameforthecurrentdefaultlookandfeeldynamically.Thisoperationisperformedusingahashtableinwhichthekeyisdefined
programmaticallybythegetUIClassID()methodinthecomponent.Theconventionistousetheplafabstractclassnameforthesekeys.For
example,JScrollbarprovides:
publicStringgetUIClassID(){

return"ScrollBarUI"
}

Consequently,thehashtableintheWindowslookandfeelwillprovideanentrythatmaps"ScrollBarUI"to
"com.sun.java.swing.plaf.windows.WindowsScrollBarUI"
Lookandfeelmanagement
SwingdefinesanabstractLookAndFeelclassthatrepresentsalltheinformationcentraltoalookandfeelimplementation,suchasitsname,its
description,whetherit'sanativelookandfeelandinparticular,ahashtable(knownasthe"DefaultsTable")forstoringdefaultvaluesforvarious
lookandfeelattributes,suchascolorsandfonts.
EachlookandfeelimplementationdefinesasubclassofLookAndFeel(forexample,swing.plaf.motif.MotifLookAndFeel)toprovideSwing
withthenecessaryinformationtomanagethelookandfeel.
TheUIManageristheAPIthroughwhichcomponentsandprogramsaccesslookandfeelinformation(theyshouldrarely,ifever,talkdirectlytoa
LookAndFeelinstance).UIManagerisresponsibleforkeepingtrackofwhichLookAndFeelclassesareavailable,whichareinstalled,andwhich
iscurrentlythedefault.TheUIManageralsomanagesaccesstotheDefaultsTableforthecurrentlookandfeel.
The'default'lookandfeel
TheUIManageralsoprovidesmethodsforgettingandsettingthecurrentdefaultLookAndFeel:
publicstaticLookAndFeel

getLookAndFeel()

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

5/12

24/12/2014

ASwingArchitectureOverview

publicstaticvoid

setLookAndFeel(LookAndFeelnewLookAndFeel)

publicstaticvoid

setLookAndFeel(StringclassName)

Asadefaultlookandfeel,SwinginitializesthecrossplatformJavalookandfeel(formerlyknownas"Metal").However,ifaSwingprogramwants
tosetthedefaultLookandFeelexplicitly,itcandothatusingtheUIManager.setLookAndFeel()method.Forexample,thefollowingcode
samplewillsetthedefaultLookandFeeltobeCDE/Motif:
UIManager.setLookAndFeel(

"com.sun.java.swing.plaf.motif.MotifLookAndFeel")

Sometimesanapplicationmaynotwanttospecifyaparticularlookandfeel,butinsteadwantstoconfigurealookandfeelinsuchawaythatit
dynamicallymatcheswhateverplatformithappenstoberunningon(forinstance,the.WindowslookandfeelifitisrunningonWindowsNT,or
CDE/MotififitrunningonSolaris).Or,perhaps,anapplicationmightwanttolockdownthelookandfeeltothecrossplatformJavalookandfeel.
TheUIManagerprovidesthefollowingstaticmethodstoprogrammaticallyobtaintheappropriateLookAndFeelclassnamesforeachofthese
cases:
publicstaticString
getSystemLookAndFeelClassName()
publicstaticString
getCrossPlatformLookAndFeelClassName()
So,toensurethataprogramalwaysrunsintheplatform'ssystemlookandfeel,thecodemightlooklikethis:
UIManager.setLookAndFeel(

UIManager.getSystemLookAndFeelClassName())

DynamicallyChangingtheDefaultLookandFeel
WhenaSwingapplicationprogrammaticallysetsthelookandfeel(asdescribedabove),theidealplacetodosoisbeforeanySwingcomponents
areinstantiated.ThisisbecausetheUIManager.setLookAndFeel()methodmakesaparticularLookAndFeelthecurrentdefaultbyloadingand
initializingthatLookAndFeelinstance,butitdoesnotautomaticallycauseanyexistingcomponentstochangetheirlookandfeel.
RememberthatcomponentsinitializetheirUIdelegateatconstructtime,therefore,ifthecurrentdefaultchangesaftertheyareconstructed,they
willnotautomaticallyupdatetheirUIsaccordingly.Itisuptotheprogramtoimplementthisdynamicswitchingbytraversingthecontainment
hierarchyandupdatingthecomponentsindividually.(NOTE:SwingprovidestheSwingUtilities.updateComponentTreeUI()methodto
assistwiththisprocess).
ThelookandfeelofacomponentcanbeupdatedatanytimetomatchthecurrentdefaultbyinvokingitsupdateUI()method,whichusesthe
followingstaticmethodonUIManagertogettheappropriateUIdelegate:
publicstaticComponentUIgetUI(JComponentc)

Forexample,theimplementationofupdateUI()fortheJScrollBarlookslikethefollowing:
publicvoidupdateUI(){

setUI((ScrollBarUI)UIManager.getUI(this))
}

AndsoifaprogramneedstochangethelookandfeelofaGUIhierarchyafteritwasinstantiated,thecodemightlooklikethefollowing:
//GUIalreadyinstantiated,wheremyframe
//istoplevelframe
try{

UIManager.setLookAndFeel(

"com.sun.java.swing.plaf.motif.MotifLookAndFeel")

myframe.setCursor(

Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))

SwingUtilities.updateComponentTreeUI(myframe)

myframe.validate()
}catch(UnsupportedLookAndFeelExceptione){

}finally{

myframe.setCursor

(Cursor.getPredefinedCursor

(Cursor.DEFAULT_CURSOR))
}

Managinglookandfeeldata
TheUIManagerdefinesastaticclass,namedUIManager.LookAndFeelInfo,forstoringthehighlevelname(suchas."Metal")andparticular
classname(suchas"com.sun.java.swing.plaf.MetalLookAndFeel")foraLookAndFeel.Itusestheseclassesinternallytomanagetheknown
LookAndFeelobjects.ThisinformationcanbeaccessedfromtheUIManagerviathefollowingstaticmethods:
publicstaticLookAndFeelInfo[]

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

6/12

24/12/2014

ASwingArchitectureOverview

getInstalledLookAndFeels()

publicstaticvoid

setInstalledLookAndFeels(LookAndFeelInfo[]infos)

throwsSecurityException

publicstaticvoid

installLookAndFeel(LookAndFeelInfoinfo)

publicstaticvoid

installLookAndFeel(Stringname,StringclassName)

Thesemethodscanbeusedtoprogrammaticallydeterminewhichlookandfeelimplementationsareavailable,whichisusefulwhenbuildinguser
interfaceswhichallowtheendusertodynamicallyselectalookandfeel.
Thelookandfeelpackages
TheUIdelegateclassesprovidedinswing.plaf(ButtonUI,ScrollBarUI,andsoon)definethepreciseAPIthatacomponentcanuseto
interactwiththeUIdelegateinstance.(NOTE:Interfaceswereoriginallyusedhere,buttheywerereplacedwithabstractclassesbecausewefelt
theAPIwasnotmatureenoughtowithstandtheconcretecastingofaninterface.)TheseplafAPIsaretherootofalllookandfeelimplementations.
Eachlookandfeelimplementationprovidesconcretesubclassesoftheseabstractplafclasses.Allsuchclassesdefinedbyaparticularlookand
feelimplementationarecontainedinaseparatepackageundertheswing.plafpackage(forexample,.swing.plaf.motif,
swing.plaf.metal,andsoon).Alookandfeelpackagecontainsthefollowing:
TheLookAndFeelsubclass(forinstance,MetalLookAndFeel).
Alllookandfeel'sUIdelegateclasses(forexample,MetalButtonUI,MetalTreeUI,andthelike).
Anylookandfeelutilityclasses(MetalGraphicsUtils,MetalIconFactory,andsoon).
Otherresourcesassociatedwiththelookandfeel,suchasimagefiles.
InimplementingthevariousSwinglookandfeels,wesoondiscoveredthattherewasalotofcommonalityamongthem.Wefactoredoutthis
commoncodeintoabaselookandfeelimplementation(called"basic")whichextendstheplafabstractclassesandfromwhichthespecificlook
andfeelimplementations(motif,windows,andsoon.)extend.Thebasiclookandfeelpackagesupportsbuildingadesktoplevellookandfeel,
suchasWindowsorCDE/Motif.
Thebasiclookandfeelpackageisjustoneexampleofhowtobuildapluggablelookandfeelthearchitectureisflexibleenoughtoaccommodate
otherapproachesaswell.
Theremainderofthisdocumentwillshowhowalookandfeelpackageworksatthegenericlevel,leavingthedetailsonthebasicpackagefora
futuredocument.
WARNING:AllAPIsdefinedbelowtheswing.plafpackagearenotfrozeninthe1.0.XversionofSwing.WearecurrentlycleaningupthoseAPIs
fortheversionofSwingthatwillshipwithJDK1.2beta4,atwhichtimetheywillbecomefrozen.Soifyouaredevelopingyourownlookandfeel
implementationusingthe1.0.1API,thisislikelytoaffectyou.
TheLookAndFeelSubclass
TheLookAndFeelclassdefinesthefollowingabstractmethods,whichallsubclassesmustimplement:
publicStringgetName()

publicStringgetID()

publicStringgetDescription()

publicbooleanisNativeLookAndFeel()

publicbooleanisSupportedLookAndFeel()

ThegetName(),getID(),andgetDescription()methodsprovidegenericinformationaboutthelookandfeel.
TheisNativeLookAndFeel()methodreturnstrueifthelookandfeelisnativetothecurrentplatform.Forexample,MotifLookAndFeelreturns
trueifitiscurrentlyrunningontheSolarisplatform,andreturnsfalseotherwise.
TheisSupportedLookAndFeel()methodreturnswhetherornotthislookandfeelisauthorizedtorunonthecurrentplatform.Forexample,
WindowsLookAndFeelreturnstrueonlyifitisrunningonaWindows95,Windows98,orWindowsNTmachine.
ALookAndFeelclassalsoprovidesmethodsforinitializationanduninitialization:
publicvoidinitialize()

publicvoiduninitialize()

Theinitialize()methodisinvokedbytheUIManagerwhentheLookAndFeelismadethe"default"usingthe
UIManager.setLookAndFeel()method.uninitialize()isinvokedbytheUIManagerwhentheLookAndFeelisabouttobereplacedasthe
default.
TheDefaultsTable
Finally,theLookAndFeelclassprovidesamethodtoreturnthelookandfeel'simplementationoftheDefaultsTable:
publicUIDefaultsgetDefaults()

TheDefaultsTableisrepresentedbytheUIDefaultsclass,adirectextensionofjava.util.Hashtable,whichaddsmethodsforaccessing
specifictypesofinformationaboutalookandfeel.ThistablemustincludealltheUIClassIDtoclassnamemappinginformation,aswellasany
defaultvaluesforpresentationrelatedproperties(suchascolor,font,border,andicon)foreachUIdelegate.Forexample,followingisasampleof
whatafragmentofgetDefaults()mightlooklikeforahypotheticallookandfeelinapackagecalled"mine":
publicUIDefaultsgetDefaults(){

UIDefaultstable=newUIDefaults()

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

7/12

24/12/2014

ASwingArchitectureOverview

Object[]uiDefaults={

"ButtonUI","mine.MyButtonUI",

"CheckBoxUI","mine.MyCheckBoxUI",

"MenuBarUI","mine.MyMenuBarUI",

...

"Button.background",

newColorUIResource(Color.gray),

"Button.foreground",

newColorUIResource(Color.black),

"Button.font",

newFontUIResource("Dialog",Font.PLAIN,12),

"CheckBox.background",

newColorUIResource(Color.lightGray),

"CheckBox.font",

newFontUIResource("Dialog",Font.BOLD,12),

...

table.putDefaults(uiDefaults)

returntable
}

WhenthedefaultlookandfeelissetwithUIManager.setLookAndFeel(),theUIManagercallsgetDefaults()onthenewLookAndFeel
instanceandstoresthehashtableitreturns.SubsequentcallstotheUIManager'slookupmethodswillbeappliedtothistable.Forexample,after
making"mine"thedefaultLookandFeel:
UIManager.get("ButtonUI")=>"mine.MyButtonUI"

TheUIclassesaccesstheirdefaultinformationinthesameway.Forexample,ourexampleButtonUIclasswouldinitializetheJButton's
"background"propertylikethis:
button.setBackground(

UIManager.getColor("Button.background")

Thedefaultsareorganizedthiswaytoallowdeveloperstooverridethem.MoredetailaboutSwing'sDefaultsmechanismwillbepublishedina
futurearticle.
DistinguishingbetweenUIsetandappsetproperties
Swingallowsapplicationstosetpropertyvalues(suchascolorandfont)individuallyoncomponents.Soit'scriticaltomakesurethatthesevalues
don'tgetclobberedwhenalookandfeelsetsupits"default"propertiesforthecomponent.
ThisisnotanissuethefirsttimeaUIdelegateisinstalledonacomponent(atconstructtime)becauseallpropertieswillbeuninitializedandlegally
settablebythelookandfeel.Theproblemoccurswhentheapplicationsetsindividualpropertiesaftercomponentconstructionandthen
subsequentlysetsanewlookandfeel(thatis,dynamiclookandfeelswitching).Thismeansthatthelookandfeelmustbeabletodistinguish
betweenpropertyvaluessetbytheapplication,andthosesetbyalookandfeel.
Thisissueishandledbymarkingallvaluessetbythelookandfeelwiththeplaf.UIResourceinterface.Theplafpackageprovidesasetof
"marked"classesforrepresentingthesevalues,ColorUIResource,FontUIResource,andBorderUIResource.Theprecedingcodeexample
showstheusageoftheseclassestomarkthedefaultpropertyvaluesforthehypotheticalMyButtonUIclass.

TheUIdelegate
ThesuperclassofallUIDelegateclassesisswing.plaf.ComponentUI.Thisclasscontainstheprimary"machinery"formakingthepluggable
lookandfeelwork.ItsmethodsdealwithUIinstallationanduninstallation,andwithdelegationofacomponent'sgeometryhandlingandpainting.
ManyoftheUIDelegatesubclassesalsoprovideadditionalmethodsspecifictotheirownrequiredinteractionwiththecomponenthowever,this
documentfocusesprimarilyonthegenericmechanismimplementedbyComponentUI.
UIinstallationanddeinstallation
Firstoff,theComponentUIclassdefinesthesemethodsmethodsforUIdelegateinstallationanduninstallation:
publicvoidinstallUI(JComponentc)

publicvoiduninstallUI(JComponentc)

LookingattheimplementationofJComponent.setUI()(whichisalwaysinvokedfromthesetUImethodonJComponentsubclasses),wecan
clearlyseehowUIdelegateinstallation/deinstallationworks:
protectedvoidsetUI(ComponentUInewUI){

if(ui!=null){

ui.uninstallUI(this)

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

8/12

24/12/2014

ASwingArchitectureOverview

ComponentUIoldUI=ui

ui=newUI

if(ui!=null){

ui.installUI(this)

invalidate()

firePropertyChange("UI",oldUI,newUI)
}

UIinstallationillustrated
ThisarticlecomeswithagiantpostersizechartthatillustratestheprocessinstallingaUIdelegate.Itcanprovideyouwithavaluableoverviewof
thedelegateinstallationprocess.
Tofoldoutthechart,justfollowthislink

TheUIdelegate'sinstallUI()methodisresponsibleforthefollowing:
Setdefaultfont,color,border,andopacitypropertiesonthecomponent.
Installanappropriatelayoutmanageronthecomponent.
Addanyappropriatechildsubcomponentstothecomponent
Registeranyrequiredeventlistenersonthecomponent.
Registeranylookandfeelspecifickeyboardactions(mnemonics,etc.)forthecomponent.
Registerappropriatemodellistenerstobenotifiedwhentorepaint.
Initializeanyappropriateinstancedata.
Forexample,theinstallUI()methodforanextensionofButtonUImightlooklikethis:
protectedMyMouseListenermouseListener
protectedMyChangeListenerchangeListener
publicvoidinstallUI(JComponentc){

AbstractButtonb=(AbstractButton)c

//Installdefaultcolors&opacity

Colorbg=c.getBackground()

if(bg==null||bginstanceofUIResource){

c.setBackground(

UIManager.getColor("Button.background"))

Colorfg=c.getForeground()

if(fg==null||fginstanceofUIResource){

c.setForeground(

UIManager.getColor("Button.foreground"))

c.setOpaque(false)

//Installlisteners

mouseListener=newMyMouseListener()

c.addMouseListener(mouseListener)

c.addMouseMotionListener(mouseListener)

changeListener=newMyChangeListener()

b.addChangeListener(changeListener)
}

Conventionsforinitializingcomponentproperties
Swingdefinesanumberofconventionsforinitializingcomponentpropertiesatinstalltime,includingthefollowing:
Allvaluesusedforsettingcolors,font,andborderpropertiesshouldbeobtainedfromtheDefaultstable(asdescribedinthesubsectiononthe
LookAndFeelsubclass).
Color,fontandborderpropertiesshouldbesetifandonlyiftheapplicationhasnotalreadysetthem.
TofacilitateconventionNo1,theUIManagerclassprovidesanumberofstaticmethodstoextractpropertyvaluesofaparticulartype(forinstance,
thestaticmethodsUIManager.getColor(),UIManager.getFont(),andsoon).
ConventionNo.2isimplementedbyalwayscheckingforeitheranullvalueoraninstanceofUIResourcebeforesettingtheproperty.

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

9/12

24/12/2014

ASwingArchitectureOverview

TheComponentUI'suninstall()methodmustcarefullyundoeverythingthatwasdoneintheinstallUI()methodsothatthecomponentisleft
inapristinestateforthenextUIdelegate.Theuninstall()methodisresponsiblefor:
ClearingtheborderpropertyifithasbeensetbyinstallUI().
RemovethelayoutmanagerifithadbeensetbyinstallUI().
RemoveanysubcomponentsaddedbyinstallUI().
Removeanyevent/modellistenersthatwereaddedbyinstallUI().
RemoveanylookandfeelspecifickeyboardactionsthatwereinstalledbyinstallUI().
Nullifyanyinitializedinstancedata(toallowGCtocleanup).
Forexample,anuninstall()methodtoundowhatwedidintheaboveexampleinstallationmightlooklikethis:
publicvoiduninstallUI(JComponentc){

AbstractButtonb=(AbstractButton)c

//Uninstalllisteners

c.removeMouseListener(mouseListener)

c.removeMouseMotionListener(mouseListener)

mouseListener=null

b.removeChangeListener(changeListener)

changeListener=null
}

Defininggeometry
IntheAWT(andthusinSwing)acontainer'sLayoutManagerwilllayoutthechildcomponentsaccordingtoitsdefinedalgorithmthisisknownas
"validation"ofacontainmenthierarchy.TypicallyLayoutManagerswillquerythechildcomponents'preferredSizeproperty(andsometimes
minimumSizeand/ormaximumSizeaswell,dependingonthealgorithm)inordertodeterminepreciselyhowtopositionandsizethosechildren.
Obviously,thesegeometrypropertiesaresomethingthatalookandfeelusuallyneedstodefineforagivencomponent,soComponentUIprovides
thefollowingmethodsforthispurpose:
publicDimension

getPreferredSize(JComponentc)

publicDimension

getMinimumSize(JComponentc)

publicDimension

getMaximumSize(JComponentc)

publicboolean

contains(JComponentc,intx,inty)

JComponent'sparallelmethods(whichareinvokedbytheLayoutManagerduringvalidation)thensimplydelegatetotheUIobject'sgeometry
methodsifthegeometrypropertywasnotexplicitlysetbytheprogram.BelowistheimplementationofJComponent.getPreferredSize()which
showsthisdelegation:
publicDimensiongetPreferredSize(){

if(preferredSize!=null){

returnpreferredSize

Dimensionsize=null

if(ui!=null){
size=ui.getPreferredSize(this)
}

return(size!=null)?size:

super.getPreferredSize()
}

EventhoughtheboundingboxforallcomponentsisaRectangle,it'spossible
tosimulateanonrectangularcomponentbyoverridingtheimplementationofthecontains()methodfromjava.awt.Component.(Thismethod
isusedforthehittestingofmouseevents).But,liketheothergeometrypropertiesinSwing,theUIdelegatedefinesitsownversionofthe
contains()method,whichisalsodelegatedtobyJComponent.contains():
publicbooleancontains(JComponentc,intx,inty){

return(ui!=null)?
ui.contains(this,x,y)
:

super.contains(x,y)
}

SoaUIdelegatecouldprovidenonrectangular"feel"bydefiningaparticularimplementationofcontains()(forexample,ifwewantedour
MyButtonUIclasstoimplementabuttonwithroundedcorners).

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

10/12

24/12/2014

ASwingArchitectureOverview

Painting
Finally,theUIdelegatemustpaintthecomponentappropriately,henceComponentUIhasthefollowingmethods:
publicvoidpaint(Graphicsg,JComponentc)

publicvoidupdate(Graphicsg,JComponentc)

Andonceagain,JComponent.paintComponent()takescaretodelegatethepainting:
protectedvoidpaintComponent(Graphicsg){

if(ui!=null){

GraphicsscratchGraphics=

SwingGraphics.createSwingGraphics(g.create())

try{

ui.update(scratchGraphics,this)

finally{

scratchGraphics.dispose()

}
}

SimilarlytothewayinwhichthingsaredoneinAWT,theUIdelegate'supdate()methodclearsthebackground(ifopaque)andtheninvokesits
paint()method,whichisultimatelyresponsibleforrenderingthecontentsofthecomponent.
Statelessvs.statefuldelegates
AllthemethodsonComponentUItakeaJComponentobjectasaparameter.ThisconventionenablesastatelessimplementationofaUIdelegate
(becausethedelegatecanalwaysquerybacktothespecifiedcomponentinstanceforstateinformation).StatelessUIdelegateimplementations
allowasingleUIdelegateinstancetobeusedforallinstancesofthatcomponentclass,whichcansignificantlyreducethenumberofobjects
instantiated.
ThisapproachworkswellformanyofthesimplerGUIcomponents.Butformorecomplexcomponents,wefounditnottobea"win"becausethe
inefficiencycreatedbyconstantstaterecalculationswasworsethancreatingextraobjects(especiallysincethenumberofcomplexGUI
componentscreatedinagivenprogramtendstobesmall).
TheComponentUIclassdefinesastaticmethodforreturningadelegateinstance:
publicstaticComponentUI

createUI(JComponentc)

It'stheimplementationofthismethodthatdetermineswhetherthedelegateisstatelessorstateful.That'sbecausetheUIManager.getUI()
methodinvokedbythecomponenttocreatetheUIdelegateinternallyinvokesthiscreateUImethodonthedelegateclasstogettheinstance.
TheSwinglookandfeelimplementationsusebothtypesofdelegates.Forexample,Swing'sBasicButtonUIclassimplementsastateless
delegate:
//SharedUIobject
protectedstaticButtonUIbuttonUI

publicstaticComponentUIcreateUI(JComponentc)

if(buttonUI==null){

buttonUI=newBasicButtonUI()

returnbuttonUI
}

WhileSwing'sBasicTabbedPaneUIusesthestatefulapproach:
publicstaticComponentUIcreateUI(JComponentc)

returnnewBasicTabbedPaneUI()
}

PluggableLookandFeelsummary
ThepluggablelookandfeelfeatureofSwingisbothpowerfulandcomplex(whichyouunderstandifyou'vegottenthisfar!).Itisdesignedtobe
programmedbyasmallsubsetofdeveloperswhohaveaparticularneedtodevelopanewlookandfeelimplementation.Ingeneral,application
developersonlyneedtounderstandthecapabilitiesofthismechanisminordertodecidehowtheywishtosupportlookandfeels(suchas
whethertolockdowntheprogramtoasinglelookandfeelorsupportlookandfeelconfigurationbytheuser).Swing'sUIManagerprovidesthe
APIforapplicationstomanagethelookandfeelatthislevel.
Ifyou'reoneofthosedeveloperswhoneeds(orwants)todevelopacustomlookandfeel,it'scriticaltounderstandtheseunderpinningsbefore
youwriteasinglelineofcode.We'reworkingonprovidingbetterdocumentationtohelpwiththisprocessstartingwiththisdocument,and
continuingwithothersthatwillfollowsoon.
JavaSDKsandTools
JavaSE
JavaEEandGlassfish

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

11/12

24/12/2014

ASwingArchitectureOverview
JavaME
JavaCard
NetBeansIDE
JavaMissionControl
JavaResources
JavaAPIs
TechnicalArticles
DemosandVideos
Forums
JavaMagazine
Java.net
DeveloperTraining
Tutorials
Java.com

http://www.oracle.com/technetwork/java/architecture142923.html?printOnly=1

12/12

Vous aimerez peut-être aussi