Académique Documents
Professionnel Documents
Culture Documents
ASwingArchitectureOverview
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