<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang='en'>
<head>
<title>
Building Swing Applications with Compositor
</title>
<meta http-equiv="Content-type" content="text/html; charset=Windows-1252">
<meta name="Generator" content='EditPlus'>
<meta name="Keywords" content='Compositor, Swing, XML, GUI, Java'>
<meta name="Description" content='Overview of Compositor and how to build an application with it'>
<link rel='stylesheet' href='compositor.css' type='text/css'>
<style type='text/css'>
body { background: white }
</style>
<script type='text/javascript' src='compositor.js'></script>
</head>
<body onload='initContents ()'>
<div id='intro'>
<h1>
Building Swing Apps with Compositor
</h1>
<p>
or <q>Everything You Need To Know About Compositor All In One Page</q>
</p>
<p>
or <q class='page'>the white page</q>
</p>
</div>
<div id='panel'>
<img id='logo' src='core/src/main/resources/logo.png' width='138' height='135' border='0' alt=''>
<p style='display: none'>
<a href='#content'>Skip navigation</a>
</p>
<div id='contents'>
<div id='links' style='font-size: small'>
<h2 style='margin: 0; padding: 0'>Links</h2>
<ul>
<li>
<a href='https://sourceforge.net/projects/compositor/files/0.4/'>Download v0.4</a>
</li>
<li>
<a href='http://sourceforge.net/projects/compositor/' title='Sourceforge'>Project host info</a>
</li>
<li style='background: #ffffbb'>
<a href='quickstart.html' title='the yellow page'><strong>Quick start</strong></a>
</li>
<li style='background: #ffebeb'>
<a href='layout.html' title='the pink page'>Layout help</a>
</li>
<li style='background: #ebebff'>
<a href='howthingswork.html' title='the blue page'>How it works</a>
</li>
</ul>
</div>
<h2>
Contents
</h2>
<ol>
<li>
<a href='#whatis'>What is Compositor?</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#whatdoesnt'>What <em>doesn't</em> Compositor do?</a>
</li>
<li>
<a href='#hasntthis'>Hasn't this been done before?</a>
</li>
<li>
<a href='#goodbad'>What's good and bad about Compositor?</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='a' style='display: none'>
<li>
<a href='#good'>The good bits</a>
</li>
<li>
<a href='#bad'>The bad bits</a>
</li>
</ol>
</li>
</ul>
</li>
<li>
<a href='#download'>Download</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#building'>Building Compositor from source</a>
</li>
</ul>
</li>
<li>
<a href='#howto'><strong><em>Tutorial:</em></strong> Writing a simple Compositor app</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#writemyappxml'>Write <code>MyApp.xml</code></a>
</li>
<li>
<a href='#writemyappjava'>Write <code>MyApp.java</code></a>
</li>
<li>
<a href='#iconimages'>Icon images (optional)</a>
</li>
<li>
<a href='#running'>Compile and run</a>
</li>
</ol>
</li>
<li>
<a href='#filling'>Filling in detail</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#addingcomponents'>Adding components and code</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='a' style='display: none'>
<li>
<a href='#containers'>Containers</a>
</li>
<li>
<a href='#components'>Components</a>
</li>
<li>
<a href='#layout'>Layout</a>
</li>
<li>
<a href='#actions_1'>Actions</a>
</li>
<li>
<a href='#eventhandlers'>Event handlers</a>
</li>
<li>
<a href='#doubleunderscore'>Double underscore</a>
</li>
<li>
<a href='#wildcards'>Wild cards</a>
</li>
</ol>
</li>
<li>
<a href='#referringtocomponents'>Referring to components from code</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#frames'>Frames</a>
</li>
<li>
<a href='#dialogs'>Dialogs</a>
</li>
<li>
<a href='#windows'>Windows</a>
</li>
<li>
<a href='#menus'>Menus</a>
</li>
<li>
<a href='#toolbars'>Tool bars</a>
</li>
<li>
<a href='#actions_2'>Actions</a>
</li>
<li>
<a href='#othercomponents'>Other components</a>
</li>
</ul>
</li>
<li>
<a href='#addingdialogs'>Adding dialogs</a>
</li>
<li>
<a href='#threads'>Threads</a>
</li>
<li>
<a href='#manipulatingmenus'>Manipulating menus at run time</a>
</li>
<li>
<a href='#commoncode'>Common descriptor code</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#commonattributes'>Common attributes</a>
</li>
<li>
<a href='#entitymacros'>Entity macros</a>
</li>
<li>
<a href='#includemacros'>Include macros</a>
</li>
<li>
<a href='#clones'>Clones</a>
</li>
<li>
<a href='#delegates'>Delegates</a>
</li>
<li>
<a href='#cloneddelegates'>Cloned delegates</a>
</li>
</ul>
</li>
<li>
<a href='#environmentvariables'>Environment variables</a>
</li>
<li>
<a href='#splashscreen'>Splash screen</a>
</li>
<li>
<a href='#customcomponents'>Custom components</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#writing'>Writing</a>
</li>
<li>
<a href='#declaring'>Declaring</a>
</li>
<li>
<a href='#generating'>Generating</a>
</li>
</ul>
</li>
<li>
<a href='#draganddrop'>Drag and drop</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#draggingtext'>Dragging text</a>
</li>
<li>
<a href='#draggingcomponents'>Dragging components</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#dragsources'>Component drag sources</a>
</li>
<li>
<a href='#droptargets'>Panel drop targets</a>
</li>
</ul>
</li>
<li>
<a href='#otherdragtypes'>Other drag types</a>
</li>
</ul>
</li>
</ol>
</li>
<li>
<a href='#filebasedapps'>File based apps</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#prebuildfunctionality'>Pre-build functionality</a>
</li>
<li>
<a href='#stateuiinteraction'>State/UI interaction</a>
</li>
<li>
<a href='#descriptorrequirements'>Descriptor requirements</a>
</li>
<li>
<a href='#savingreminders'>Saving reminders</a>
</li>
<li>
<a href='#undoredosupport'>Undo/redo support</a>
</li>
</ol>
</li>
<li>
<a href='#thingsthatmighthelp'>Things that might help</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#methodsthatmighthelp'>Methods</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#accceptFileDragDrop'>acceptFileDragOver/acceptFileDrop</a>
</li>
<li>
<a href='#actionPostInvoke'>actionPostInvoke</a>
</li>
<li>
<a href='#changeLnF'>addLnfMenuItems/changeLnF</a>
</li>
<li>
<a href='#ask'>ask</a>
</li>
<li>
<a href='#beforeUIBuilt'>beforeUIBuilt</a>
</li>
<li>
<a href='#copyStringcopyImage'>copyString/copyImage</a>
</li>
<li>
<a href='#get'>get</a>
</li>
<li>
<a href='#getAll'>getAll</a>
</li>
<li>
<a href='#getAppName'>getAppName</a>
</li>
<li>
<a href='#getClipboardString'>getClipboardString</a>
</li>
<li>
<a href='#getDialogNames'>getDialogNames</a>
</li>
<li>
<a href='#getFrameNames'>getFrameNames</a>
</li>
<li>
<a href='#getKeyDetailsgetKeyListeners'>getKeyDetails/getKeyListeners</a>
</li>
<li>
<a href='#getMethods'>getMethods</a>
</li>
<li>
<a href='#handleEventQueueException'>handleEventQueueException</a>
</li>
<li>
<a href='#initialiseLookAndFeel'>initialiseLookAndFeel</a>
</li>
<li>
<a href='#invokeLater'>invokeLater</a>
</li>
<li>
<a href='#msgBox'>msgBox</a>
</li>
<li>
<a href='#playSound'>playSound</a>
</li>
<li>
<a href='#readWriteConfig'>readWriteConfig</a>
</li>
<li>
<a href='#run'>run</a>
</li>
<li>
<a href='#runAfterUiBuilt'>runAfterUiBuilt</a>
</li>
<li>
<a href='#showDialog'>showDialog</a>
</li>
<li>
<a href='#sizeCols'>sizeCol/sizeCols/sizeColsAdjustment</a>
</li>
<li>
<a href='#snooze'>snooze</a>
</li>
<li>
<a href='#writeStatus'>writeStatus</a>
</li>
</ul>
</li>
<li>
<a href='#classesthatmighthelp'>Classes</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#actiondelayer'>ActionDelayer</a>
</li>
<li>
<a href='#resourceloader'>ResourceLoader</a>
</li>
<li>
<a href='#filetree'>FileTree</a>
</li>
<li>
<a href='#fileops'>FileOps</a>
</li>
<li>
<a href='#selectablelabel'>SelectableLabel</a>
</li>
<li>
<a href='#config'>Config</a>
</li>
<li>
<a href='#formats'>Formats</a>
</li>
<li>
<a href='#env'>Env</a>
</li>
<li>
<a href='#info'>Info</a>
</li>
<li>
<a href='#log'>Log</a>
</li>
<li>
<a href='#nativeeditor'>NativeEditor</a>
</li>
<li>
<a href='#nativebrowser'>NativeBrowser</a>
</li>
<li>
<a href='#scriptrunner'>ScriptRunner</a>
</li>
<li>
<a href='#rotatedlabel'>RotatedLabel</a>
</li>
<li>
<a href='#propertiesignorecase'>PropertiesIgnoreCase</a>
</li>
<li>
<a href='#throttler'>Throttler</a>
</li>
<li>
<a href='#mapmaker'>MapMaker</a>
</li>
<li>
<a href='#imagecomparer'>ImageComparer</a>
</li>
<li>
<a href='#stackprobe'>StackProbe</a>
</li>
<li>
<a href='#unwinder'>Unwinder</a>
</li>
<li>
<a href='#mutint'>MutInt</a>
</li>
<li>
<a href='#padimagefilter'>PadImageFilter</a>
</li>
<li>
<a href='#exifreader'>ExifReader</a>
</li>
<li>
<a href='#threadPoolandimmortalthread'>ThreadPool/ImmortalThread</a>
</li>
<!--
<li>
<a href='#smokedoc'>SmokeDoc</a>
</li>
-->
</ul>
</li>
</ul>
</li>
<li>
<a href='#i18n'>Internationalisation</a>
</li>
<li>
<a href='#exampleapps'>Example apps</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#examples'>Examples</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#minimal'>Minimal</a>
</li>
<li>
<a href='#simpleedit'>SimpleEdit</a>
</li>
<li>
<a href='#multiedit'>MultiEdit</a>
</li>
<li>
<a href='#spsh'>Spsh</a>
</li>
<li>
<a href='#dragdrop1'>DragDrop1</a>
</li>
<li>
<a href='#dragdrop2'>DragDrop2</a>
</li>
<li>
<a href='#dragdrop3'>DragDrop3</a>
</li>
<li>
<a href='#sidetabs'>SideTabs</a>
</li>
<li>
<a href='#xibbon'>Xibbon</a>
</li>
<li>
<a href='#xibbonmacro'>XibbonMacro</a>
</li>
<li>
<a href='#calx'>Calx</a>
</li>
<li>
<a href='#decoder'>Decoder</a>
</li>
<li>
<a href='#floatywidget'>FloatyWidget</a>
</li>
<li>
<a href='#fullscreen'>FullScreen</a>
</li>
<li>
<a href='#gluetest'>GlueTest</a>
</li>
<li>
<a href='#jetris'>Jetris</a>
</li>
<li>
<a href='#laztik'>Laztik</a>
</li>
<li>
<a href='#pets'>Pets</a>
</li>
<li>
<a href='#ratedate'>RateDate</a>
</li>
<li>
<a href='#systemcolour'>SystemColour</a>
</li>
<li>
<a href='#xide'>Xide</a>
</li>
</ol>
</li>
<li>
<a href='#apps'>Apps</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#bupdate'>Bupdate</a>
</li>
<li>
<a href='#dataurimaker'>DataUriMaker</a>
</li>
<li>
<a href='#dismatch'>Dismatch</a>
</li>
<li>
<a href='#dixtionary'>Dixtionary</a>
</li>
<li>
<a href='#ftree'>FTree</a>
</li>
<li>
<a href='#fodaloda'>FodaLoad</a>
</li>
<li>
<a href='#fontsampler'>FontSampler</a>
</li>
<li>
<a href='#jemi'>Jemi</a>
</li>
<li>
<a href='#namebug'>NameBug</a>
</li>
<li>
<a href='#pixort'>Pixort</a>
</li>
<li>
<a href='#quircus'>Quircus</a>
</li>
<li>
<a href='#retest'>RETest</a>
</li>
<li>
<a href='#showgc'>ShowGC</a>
</li>
<li>
<a href='#snowflake'>Snowflake</a>
</li>
<li>
<a href='#tilex'>Tilex</a>
</li>
<li>
<a href='#timeclock'>TimeClock</a>
</li>
<li>
<a href='#wwx'>WWX</a>
</li>
</ol>
</li>
<li>
<a href='#playarea'>The play area</a>
</li>
</ul>
</li>
<li>
<a href='#otherlanguages'>Other languages</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#groovy'>Groovy</a>
</li>
<li>
<a href='#scala'>Scala</a>
</li>
<li>
<a href='#kotlin'>Kotlin</a>
</li>
<li>
<a href='#jython'>Jython</a>
</li>
<li>
<a href='#clojure'>Clojure</a>
</li>
<li>
<a href='#jruby'>JRuby</a>
</li>
<li>
<a href='#javascript'>JavaScript</a>
</li>
<li>
<a href='#anythingelse'>Anything else</a>
</li>
</ul>
</li>
<li>
<a href='#reference'><strong><em>Reference</em></strong> material</a> <a href='#.' onclick='viewList ( this )'><img src='core/src/main/resources/expand.png' alt='' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#refAccelerator'>accelerator</a>
</li>
<li>
<a href='#refAccelerators'>accelerators</a>
</li>
<li>
<a href='#refAction'>action</a>
</li>
<li>
<a href='#refActions'>actions</a>
</li>
<li>
<a href='#refButton'>button</a>
</li>
<li>
<a href='#refButtonpanel'>buttonpanel</a>
</li>
<li>
<a href='#refCell'>cell</a>
</li>
<li>
<a href='#refCheckbox'>checkbox</a>
</li>
<li>
<a href='#refClones'>clones</a>
</li>
<li>
<a href='#refColorchooser'>colorchooser</a>
</li>
<li>
<a href='#refCombobox'>combobox</a>
</li>
<li>
<a href='#refComponent'>component</a>
</li>
<li>
<a href='#refComponents'>components</a>
</li>
<li>
<a href='#refDelegate'>delegate</a>
</li>
<li>
<a href='#refDesktoppane'>desktoppane</a>
</li>
<li>
<a href='#refDialog'>dialog</a>
</li>
<li>
<a href='#refEditorpane'>editorpane</a>
</li>
<li>
<a href='#refFrame'>frame</a>
</li>
<li>
<a href='#refGlasspane'>glasspane</a>
</li>
<li>
<a href='#refGlue'>glue</a>
</li>
<li>
<a href='#refGrid'>grid</a>
</li>
<li>
<a href='#refInternalframe'>internalframe</a>
</li>
<li>
<a href='#refLabel'>label</a>
</li>
<li>
<a href='#refLayeredpane'>layeredpane</a>
</li>
<li>
<a href='#refList'>list</a>
</li>
<li>
<a href='#refMenu'>menu</a>
</li>
<li>
<a href='#refMenubar'>menubar</a>
</li>
<li>
<a href='#refMenuitem'>menuitem</a>
</li>
<li>
<a href='#refPanel'>panel</a>
</li>
<li>
<a href='#refPassword'>password</a>
</li>
<li>
<a href='#refPopupmenu'>popupmenu</a>
</li>
<li>
<a href='#refPopupmenus'>popupmenus</a>
</li>
<li>
<a href='#refProgressbar'>progressbar</a>
</li>
<li>
<a href='#refRadio'>radio</a>
</li>
<li>
<a href='#refRow'>row</a>
</li>
<li>
<a href='#refScrollbar'>scrollbar</a>
</li>
<li>
<a href='#refScrollpane'>scrollpane</a>
</li>
<li>
<a href='#refSeparator'>separator</a>
</li>
<li>
<a href='#refSlider'>slider</a>
</li>
<li>
<a href='#refSpinner'>spinner</a>
</li>
<li>
<a href='#refSplash'>splash</a>
</li>
<li>
<a href='#refSplitpane'>splitpane</a>
</li>
<li>
<a href='#refTabbedpane'>tabbedpane</a>
</li>
<li>
<a href='#refTable'>table</a>
</li>
<li>
<a href='#refTextarea'>textarea</a>
</li>
<li>
<a href='#refTextfield'>textfield</a>
</li>
<li>
<a href='#refToolbar'>toolbar</a>
</li>
<li>
<a href='#refToolbutton'>toolbutton</a>
</li>
<li>
<a href='#refTree'>tree</a>
</li>
<li>
<a href='#refUi'>ui</a>
</li>
<li>
<a href='#refWindows'>windows</a>
</li>
<li>
<a href='#refCommon'>Common properties</a>
</li>
<li>
<a href='#refCommonEventHandlers'>Common event handlers</a>
</li>
<li>
<a href='#refPaddingAndMargins'>Padding and margins</a>
</li>
<li>
<a href='#refKeyMappings'>Key mappings</a>
</li>
</ol>
</li>
<li>
<a href='#faq'><strong><em>FAQ</em></strong></a>
</li>
<li>
<a href='#morehelp'>Need more help?</a>
</li>
</ol>
<noscript>
<p class='noscript'>
If you enable JavaScript, this contents list is expandable.
</p>
</noscript>
</div>
</div>
<ol id='content'>
<li id='whatis'>
<h2>
What is Compositor?
</h2>
<p>
Compositor lets you describe your application's <abbr title='user interface'>UI</abbr> separately from its code:
"<em>This</em> is what it looks like, and <em>that</em>'s what it does."
</p>
<p>
If you'd rather see an example of how to use this, look at <a href='quickstart.html'><strong>Quick Start</strong> (the yellow page)</a>.
</p>
<p>
Why bother with describing the UI separately?
Writing a simple UI for a <a href='https://en.wikipedia.org/wiki/Swing_(Java)'>Swing</a> app in code isn't too hard.
You create components, add one to another and call some property setters.
</p>
<p>
But writing anything complex is another matter, and changing an existing UI can be mind-bending.
You look at the existing UI and you know what needs to change... but then you look at the code.
Even if you wrote it yourself, it's hard to see how one relates to the other.
And code that lays out visible components is mixed up with code that processes user interaction.
</p>
<p>
One day I was struggling to add something to a not-very-complex Swing dialog.
It occurred to me that separating layout and functionality would make things much easier.
Adding a component should involve saying that I want this type of thing to appear here, and (separately) I want it to respond to the user somehow.
</p>
<p>
Compositor makes this happen.
</p>
<ul>
<li id='whatdoesnt'>
<h3>
What <em>doesn't</em> Compositor do?
</h3>
<p>
Compositor doesn't
<p>
<ul>
<li>provide an alternative to Swing</li>
<li>or change how Swing works</li>
<li>or fix anything in Swing itself.</li>
</ul>
<p>
It's just making it easier to build/change a Swing UI, and separating that from the functionality.
</p>
<p>
Also Compositor adds some things that you might find useful.
</p>
</li>
<li id='hasntthis'>
<h3>
Hasn't this been done before?
</h3>
<p>
There are several other similar projects.
<a href='http://thinlet.sourceforge.net/overview.html'>Thinlet</a> (no longer updated?) and <a href='https://github.com/swixml/Two'>SwiXML</a> (maybe still active) were ones I considered.
Sun, er, Oracle would probably suggest that you use JavaFX, and there are others.
</p>
<p>
The components drawn by Thinlets have a non-native look and feel (though that may be fixable).
I couldn't get SwiXML to work (I didn't try hard enough: I can run the SwiXML examples now).
I hadn't tried JavaFX.
</p>
<p>
So anyway, I wrote my own.
</p>
</li>
<li id='goodbad'>
<h3>
What's good and bad about Compositor?
</h3>
<ol type='a'>
<li id='good'>
<h4>
The good bits
</h4>
<ul>
<li>
Compositor is pretty easy to understand: your <abbr title='eXtensible Markup Language'>XML</abbr> descriptor translates fairly obviously into UI components.
When it's hard to change the layout of components (as it is when you hand code it in Java), it's easy to put up with a UI design that isn't very good.
But if you can change things easily, then you're in with a chance of getting it right.
</li>
<li>
Similarly, it's quick and easy to get a prototype UI up and running, leaving you to work on the functionality of your app.
</li>
<li>
If you have custom Swing components, it's pretty easy to use them in a Compositor app.
</li>
<li>
Your app will look right on most operating systems.
Users won't notice that it isn't a native app.
You need to do almost nothing to get this right.
This is mostly Swing being helpful, with a few Compositor tweaks.
</li>
<li>
Compositor is small, so the size of your app depends mostly on how much you've written, not on Compositor.
</li>
<li>
Compositor can support apps in other languages.
I have working examples for Groovy, Scala and Kotlin, but any language that runs in the <abbr title='Java virtual machine'>JVM</abbr> and can extend a Java class should be able to use Compositor.
See the section on <a href='#otherlanguages'>other languages</a> for more details.
</li>
</ul>
</li>
<li id='bad'>
<h4>
The bad bits
</h4>
<ul>
<li>
There's a learning curve.
You have to write an XML descriptor, so you have to learn some Compositor tags and attributes.
Start by looking at the <a href='#howto'>How to...</a> section in this document.
There are lots of <a href='#exampleapps'>examples</a> to help you as well.
</li>
<li>
Compositor doesn't integrate with any <abbr title='Integrated development environment'>IDE</abbr>.
You can of course write the Java code and edit the XML with an IDE, but you won't, for example, be able to use your IDE's built-in features for UI editing.
But if you like your IDE's UI editor, there's no need for Compositor.
</li>
<li>
Component properties are specified as XML attributes, but there isn't (yet) a complete implementation of available Swing component properties.
It isn't always very clear what properties can be applied to which element (though it's mostly <a href='#reference'>documented</a>), and it's usually guessable if you're familiar with Swing.
</li>
<li>
Compositor doesn't support all layout managers.
You may miss <code class='class'>GridBagLayout</code> and <code class='class'>SpringLayout</code>, and you can't use a custom layout manager.
I've found that I can almost always get the look I want with persistence and a little ingenuity.
<code class='class'>BorderLayout</code> and <code class='class'>BoxLayout</code> are your friends, as are <code class='class'>GridLayout</code> and <code class='class'>CardLayout</code>.
I've put some of the things I've learnt into a <a href='layout.html'>layout document</a>.
</li>
<li>
Compositor uses custom stuff where you might expect some well-known library: logging and XML parsing, for example.
But this means that Compositor has no compile-time or run-time dependencies.
Only building the examples involves dependencies, which are fetched by <a href='http://maven.apache.org/'>Maven</a>.
For example, <a href='http://www.jfree.org/jfreechart/'>JFreeChart</a> is needed for <a href='#showgc'>ShowGC</a>.
</li>
<li>
Compositor lays out Swing components to make a UI.
Many UI elements cannot be made this way.
But that's a Swing thing, not a Compositor thing.
Examples of things you probably shouldn't try to do are:
<ul>
<li>syntax coloured editor</li>
<li><abbr title='Hypertext markup language'>HTML</abbr> rendering (beyond the very basic support provided by <code><editorpane contentType='text/html'></code>)</li>
<li>image editor</li>
</ul>
To build those kinds of apps in Compositor, you'd have to find or build a Swing component that does that, and wrap it in a Compositor UI.
I've done both syntax coloured editing and HTML rendering this way.
It involved finding existing free/open source Swing components that I could use.
You use the components list in the descriptor to tell Compositor how to generate the thing you want to use, then you can use it exactly like any other UI element.
</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
<li id='download'>
<h2>
Download
</h2>
<ul>
<li id='downloadoptions'>
<h3>
Options
</h3>
<p>
There are three options.
</p>
<table>
<tr>
<th>
</th>
<th>
1: Quick
</th>
<th>
2: Full
</th>
<th>
3: Git clone
</th>
</tr>
<tr>
<th>
Effort
</th>
<td>
Minimal effort now
</td>
<td>
Get it over with now
</td>
<td>
Get it over with now and forever
</td>
</tr>
<tr>
<th>
Effect
</th>
<td>
Might be a problem later
</td>
<td>
Make the future easier
</td>
<td>
Quicker fixes, occasional breaking changes
</td>
</tr>
<tr>
<th>
Steps
</th>
<td>
<ul>
<li>
Get a Compositor jar file
</li>
<li>
Write your apps
</li>
</ul>
</td>
<td>
<ul>
<li>
Get Compositor source
</li>
<li>
Make sure you have Maven
</li>
<li>
Build
</li>
<li>
Write your apps
</li>
</ul>
</td>
<td>
<ul>
<li>
<code>git clone https://git.code.sf.net/p/compositor/code compositor</code>
</li>
<li>
Make sure you have Maven
</li>
<li>
Build
</li>
<li>
Write your apps
</li>
<li>
<code>git pull</code> occasionally
</li>
</ul>
</td>
</tr>
<tr>
<th>
Advantages
</th>
<td>
<ul>
<li>
Quick
</li>
<li>
Easy
</li>
</ul>
</td>
<td>
<ul>
<li>
<a href='#exampleapps'>Example apps</a> to examine
</li>
<li>
Easy to try you own apps in the <a href='#playarea'>playarea</a>
</li>
<li>
Javadoc
</li>
<li>
Xide IDE-let (hmm - not working 100% yet...)
</li>
<li>
Includes this documentation
</li>
<!--
<li>
Added bonus: <a href='#smokedoc'>SmokeDoc</a>
</li>
-->
</ul>
</td>
<td>
<p>
All the same as number 2, but with more frequent updates, bug fixes, etc.
</p>
</td>
</tr>
</table>
</li>
<li id='building'>
<h3>
Building Compositor from source
</h3>
<p>
If you chose to <a href='#download'>download</a> the Compositor source, you'll need to build Compositor.
You'll need <a href='http://maven.apache.org/'>Maven</a>.
When Maven is installed and you can run it successfully (e.g. <kbd>mvn -h</kbd> works), then do this:
</p>
<pre>cd [wherever you put compositor]
cd build
mvn package</pre>
<p>
This will compile, test and build a jar.
</p>
<p>
For more on work rounds for possible build problems, see the <code>readme</code> file.
</p>
</li>
</ul>
</li>
<li id='howto'>
<h2>
<strong><em>Tutorial:</em></strong> Writing a simple Compositor app
</h2>
<p>
You can look at the example application, <a href='#simpleedit'><code>SimpleEdit</code></a>, that demonstrates how to use Compositor (because it was a test-bed for getting Compositor working), but this section will explain how to write a trivial app from scratch.
</p>
<p>
To make <code>MyApp</code>, you will need to:
</p>
<ul>
<li>
write <code>MyApp.xml</code>
</li>
<li>
<div class='callout'>
<p>
It's also possible to write your code in Groovy, Kotlin or Scala instead of Java.
</p>
</div>
write <code>MyApp.java</code>
</li>
<li>
(optional) draw or find icon images
</li>
<li>
set your classpath, compile and run
</li>
</ul>
<p>
Notice that the names of the XML and the class must match (<code>MyApp</code> in this case).
</p>
<p>
Source for this example is available in <code>examples/MyApp_01</code>.
</p>
<ol type='i'>
<li id='writemyappxml'>
<h3>
Write <code>MyApp.xml</code>
</h3>
<p>
This file describes the UI of your app.
Here's a simple example.
</p>
<pre><span class='comment'><!-- This app won't do much, but it will say "boo" on the standard output stream. --></span>
<span class='marker'><</span><span class='element'>ui</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'MyApp'</span><span class='marker'>></span>
<span class='comment'><!-- These actions will become instances of javax.swing.Action. --></span>
<span class='marker'><</span><span class='element'>actions</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>action </span><span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'boo' </span><span class='attrib'>label</span><span class='marker'>=</span><span class='string'>'_Boo...' </span><span class='marker'>/></span>
<span class='marker'></</span><span class='element'>actions</span><span class='marker'>></span>
<span class='comment'><!-- No bespoke components (so could have left this out). --></span>
<span class='marker'><</span><span class='element'>components </span><span class='marker'>/></span>
<span class='comment'><!-- Windows will become either JFrames or JDialogs. --></span>
<span class='marker'><</span><span class='element'>windows</span><span class='marker'>></span>
<span class='comment'><!-- This app has one frame called "main" and no dialogs. --></span>
<span class='marker'><</span><span class='element'>frame </span><span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'main' </span><span class='attrib'>title</span><span class='marker'>=</span><span class='string'>'My App'</span><span class='marker'>></span>
<span class='comment'><!-- No non-menu accelerators (so we could have left this out). --></span>
<span class='marker'><</span><span class='element'>accelerators</span> <span class='marker'>/></span>
<span class='comment'><!-- There's one menu item, which calls the only action. --></span>
<span class='marker'><</span><span class='element'>menubar</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>menu </span><span class='attrib'>label</span><span class='marker'>=</span><span class='string'>'_Speak'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>menuitem </span><span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'boo' </span><span class='attrib'>accelerator</span><span class='marker'>=</span><span class='string'>'B' </span><span class='marker'>/></span>
<span class='marker'></</span><span class='element'>menu</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>menubar</span><span class='marker'>></span>
<span class='comment'><!-- No popup menus (so we could have left this out). --></span>
<span class='marker'><</span><span class='element'>popupmenus </span><span class='marker'>/></span>
<span class='comment'><!-- There's one tool bar button, which also calls the action. --></span>
<span class='marker'><</span><span class='element'>toolbars</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>toolbar</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>toolbutton </span><span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'boo' </span><span class='marker'>/></span>
<span class='marker'></</span><span class='element'>toolbar</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>toolbars</span><span class='marker'>></span>
<span class='comment'><!-- More UI components would go in this panel, but we only have one. --></span>
<span class='marker'><</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span><span class='marker'>></span>This app says "Boo!" when you use the toolbar button or the menu.<span class='marker'></</span><span class='element'>label</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>frame</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>windows</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span></pre>
<p>
The idea is that the relationship between this XML descriptor and the resulting UI is clear, and that adding or changing components is straightforward.
It should be fairly obvious that the UI described above has a window with a menu and a tool bar, and that the body of the app is a text label.
</p>
<p>
Underscores in menu labels, etc. precede mnemonics, the underlined characters that you can use as keyboard shortcuts.
In this example, you could press <kbd>alt+S, B</kbd> to use the (only) menu item (except on a Mac).
Because <kbd>B</kbd> is also defined as an accelerator, <kbd>ctrl+B</kbd> will also work (or <kbd>command+B</kbd> on a Mac).
Anything other than a single character must work with <a href='https://docs.oracle.com/en/java/javase/14/docs/api/java.desktop/javax/swing/KeyStroke.html#getKeyStroke(java.lang.String)'><code><span class='class'>KeyStroke</span>.getKeyStroke(<span class='class'>String</span> s)</code></a>.
</p>
<p>
There was a DTD for Compositor UI descriptors, but it is no longer maintained because there were a number of issues with using it.
For example, the XML can have arbitrary includes, like this:
</p>
<pre><span class='marker'><</span><span class='element'>include </span><span class='attrib'>file</span><span class='marker'>=</span><span class='string'>'something.xml'</span><span class='marker'>/></span></pre>
<p>
There are several ways to reduce repetition in your UI descriptor.
See the <a href='#commoncode'>Common descriptor code</a> section for ways of doing this.
</p>
</li>
<li id='writemyappjava'>
<h3>
Write <code>MyApp.java</code>
</h3>
<p>
Your application must build the UI.
This is simple. Just extend <code>App</code> and make an instance of the class.
</p>
<p>
Then it must be able to process user actions, and in this case we've only defined one, called <code>boo</code>, so we must have a <code>doBoo</code> method.
</p>
<pre><span class='keyword'>import </span>net.sf.compositor.<span class='class'>App</span>;
<span class='keyword'>public class</span> MyApp
<span class='keyword'>extends</span> <span class='class highlight'>App</span> {
<span class='keyword'>public static void</span> main( <span class='keyword'>final</span> <span class='class'>String</span> [] args ) {
<span class='comment'>// We make an instance of the app, and Compositor builds the UI and starts</span>
<span class='comment'>// the main window. The XML is found by name.</span>
<span class='highlight'><span class='keyword'>new </span>MyApp();</span>
}
<span class='comment'>// We must define a method like this to handle the "boo" action.</span>
<span class='keyword'>public void </span><span class='highlight'>doBoo()</span> {
<span class='comment'>// The body of this method can do whatever you want.</span>
<span class='class'>System</span>.out.println( <span class='string'>"Boo!" </span>);
}
}</pre>
<p>
The intention is that the code you write deals only with what your application does, not how the UI is constructed.
</p>
<div class='callout'>
<p>
In the examples, the <code>main</code> method is in the app class, but you can start your app however you like.
When you're ready for the UI, just make an instance of the app class (in the example above, <code>MyApp</code>).
</p>
</div>
<p>
You must write a handler for each action you've defined.
Handling any other UI events (clicks, key presses, etc.) is optional, and it's not necessary in this case.
</p>
<p>
This simple example doesn't have a package.
If you do have a package, the XML is still found by the class name, but ignoring the package.
</p>
<p>
If you want enhanced Mac compatibility, extend <code>AppMac</code>.
This will require you to implement a few extra methods.
Running an <code>AppMac</code> app on a non-Mac platform works exactly as if you'd extended <code>App</code>.
</p>
<p>
Many apps will extend <code>FileApp</code>, but we'll come to that <a href='#filebasedapps'>later</a>.
</p>
<p class='warning'>
Don't put any code in the constructor for your app.
If you do, there can be strange concurrency issues because the UI is starting up on another thread at the same time as your constructor is executing.
It's best if you don't write a constructor at all.
Better places to put start-up logic are in a <a href='#beforeUIBuilt'><code>beforeUIBuilt</code></a> method or in an event handler for a frame being loaded or shown, e.g.: <a href='#refFrame'><code>main__onLoad</code></a>.
</p>
</li>
<li id='iconimages'>
<h3>
Icon images (optional)
</h3>
<p>
The example has no icons.
</p>
<p>
Frames, dialogs, menus, menu items and toolbar buttons can have icons if you specify an <code class='attrib'>icon</code> attribute with a file name.
You can snag these from some open source project, or you can draw them yourself, in which case you'll need an image editor that understands image transparency.
GIF or PNG format images will work.
16x16 pixels used to be the usual size but as screen resolutions have increased, larger sizes have become more common.
</p>
</li>
<li id='running'>
<h3>
Compile and run
</h3>
<p>
You need Compositor (either <code>compositor.jar</code> or the <code>classes</code> directory) in your classpath to compile a Compositor app.
To run, your classpath should include Compositor, your app, your XML descriptor, and any icon image files.
</p>
<p>
If you make a prototype in the <a href='#playarea'><code>playarea</code></a> directory, the Compositor <a href='#building'>build</a> will compile it, and you can run it from the <a href='#exampleapps'>Examples</a> app.
</p>
</li>
</ol>
<p>
If you try this example, you should find that using the menu, clicking the toolbar button or pressing Ctrl+B all make the app write "Boo!" to the console.
</p>
<p>
<strong>Bonus hints:</strong>
</p>
<ul style='margin: 0.5em; list-style-type: square'>
<li>
If you use <code>msgBox( <span class='string'>"Boo!"</span> )</code> instead of <code><span class='class'>System</span>.out.println( <span class='string'>"Boo!"</span> )</code> you'll get a GUI boo.
</li>
<li>
There are several variants: <code>msgBox( getFrame( <span class='string'>"main"</span> ), <span class='string'>"Boo!"</span>, WARNING_MESSAGE )</code> will get you a more alarming-looking message dialog, centred on the app's frame.
</li>
<li>
Alert readers will notice the similarity with <code class='class'>JOptionPane</code>.
</li>
</ul>
</li>
<li id='filling'>
<h2>
Filling in detail
</h2>
<p>
Once you have something very simple working, you'll want to add UI components, and refer to them in code.
This section describes how to do that.
</p>
<p>
A word of warning: your app class will tend to grow and grow.
A good design goal is to move as much as possible out of your app class so that it just handles the UI.
</p>
<ol type='i'>
<li id='addingcomponents'>
<h3>
Adding components and code
</h3>
<p>
A real app would have a much richer UI than the example above, so how do we add more stuff?
</p>
<ol type='a'>
<li id='containers'>
<h4>
Containers
</h4>
<p>
You can use various containers for your components, but the simplest way to group things is with a <a href='#refPanel'><code class='element'>panel</code></a> element (which generates a <code class='class'>JPanel</code>).
By nesting panels one inside another, almost any arrangement of components can be built.
</p>
<p>
Another useful container is a <a href='#refSplitpane'><code class='element'>splitpane</code></a> element (which generates a <code class='class'>JSplitPane</code>).
This divides two components so that the user can move the divider.
</p>
<p>
A <a href='#refScrollpane'><code class='element'>scrollpane</code></a> (which generates a <code class='class'>JScrollPane</code>) is a container for a single component, and provides scrolling as required.
</p>
<p>
A <a href='#refTabbedpane'><code class='element'>tabbedpane</code></a> (which generates <code class='class'>JTabbedPane</code>) shows components grouped under tabs.
</p>
<p>
A <a href='#refGrid'><code class='element'>grid</code></a> (which generates <code class='class'>JPanel</code> with <code class='class'>GridBagLayout</code>) shows components in rows and columns.
</p>
<p>
A <a href='#refButtonpanel'><code class='element'>buttonpanel</code></a> (which generates <code class='class'>JPanel</code>) is a container for radio buttons.
</p>
</li>
<li id='components'>
<h4>
Components
</h4>
<p>
Here's the mapping for Compositor descriptor elements to Swing components.
</p>
<p>
You may notice a relationship between most of the names.
The Compositor names are linked to more info about how to use them.
</p>
<table>
<col class='element'>
<col class='class'>
<tr>
<th>
Compositor XML element
</th>
<th>
Swing component
</th>
</tr>
<tr>
<th>
<a href='#refButton'>button</a>
</th>
<td>
JButton
</td>
</tr>
<tr>
<th>
<a href='#refButtonpanel'>buttonpanel</a>
</th>
<td>
JPanel as a container for radio buttons
</td>
</tr>
<tr>
<th>
<a href='#refCheckbox'>checkbox</a>
</th>
<td>
JCheckBox
</td>
</tr>
<tr>
<th>
<a href='#refColorchooser'>colorchooser</a>
</th>
<td>
JColorChooser
</td>
</tr>
<tr>
<th>
<a href='#refCombobox'>combobox</a>
</th>
<td>
JComboBox
</td>
</tr>
<tr>
<th>
<a href='#refDesktoppane'>desktoppane</a>
</th>
<td>
JDesktopPane
</td>
</tr>
<tr>
<th>
<a href='#refEditorpane'>editorpane</a>
</th>
<td>
JEditorPane
</td>
</tr>
<tr>
<th>
<a href='#refGrid'>grid</a>
</th>
<td>
JPanel with GridBagLayout
</td>
</tr>
<tr>
<th>
<a href='#refLabel'>label</a>
</th>
<td>
JLabel
</td>
</tr>
<tr>
<th>
<a href='#refLayeredpane'>layeredpane</a>
</th>
<td>
JLayeredPane
</td>
</tr>
<tr>
<th>
<a href='#refList'>list</a>
</th>
<td>
JList
</td>
</tr>
<tr>
<th>
<a href='#refPanel'>panel</a>
</th>
<td>
JPanel
</td>
</tr>
<tr>
<th>
<a href='#refPassword'>password</a>
</th>
<td>
JPasswordField
</td>
</tr>
<tr>
<th>
<a href='#refProgressbar'>progressbar</a>
</th>
<td>
JProgressBar
</td>
</tr>
<tr>
<th>
<a href='#refRadio'>radio</a>
</th>
<td>
JRadioButton
</td>
</tr>
<tr>
<th>
<a href='#refScrollbar'>scrollbar</a>
</th>
<td>
JScrollBar
</td>
</tr>
<tr>
<th>
<a href='#refScrollpane'>scrollpane</a>
</th>
<td>
JScrollPane
</td>
</tr>
<tr>
<th>
<a href='#refSeparator'>separator</a>
</th>
<td>
JSeparator
</td>
</tr>
<tr>
<th>
<a href='#refSlider'>slider</a>
</th>
<td>
JSlider
</td>
</tr>
<tr>
<th>
<a href='#refSpinner'>spinner</a>
</th>
<td>
JSpinner
</td>
</tr>
<tr>
<th>
<a href='#refSplitpane'>splitpane</a>
</th>
<td>
JSplitPane
</td>
</tr>
<tr>
<th>
<a href='#refTabbedpane'>tabbedpane</a>
</th>
<td>
JTabbedPane
</td>
</tr>
<tr>
<th>
<a href='#refTable'>table</a>
</th>
<td>
JTable
</td>
</tr>
<tr>
<th>
<a href='#refTextarea'>textarea</a>
</th>
<td>
JTextArea
</td>
</tr>
<tr>
<th>
<a href='#refTextfield'>textfield</a>
</th>
<td>
JTextField
</td>
</tr>
<tr>
<th>
<a href='#refTree'>tree</a>
</th>
<td>
JTree
</td>
</tr>
</table>
</li>
<li id='layout'>
<h4>
Layout
</h4>
<p>
So how do you specify layout, besides saying that some component is contained in another?
The answer is by giving elements attributes.
For example, this fragment sets a panel's layout manager to <code class='class'>BorderLayout</code>, and adds two labels at the top and bottom.
</p>
<pre><span class='marker'><</span><span class='element'>panel</span> <span class='highlight'><span class='attrib'>layout</span><span class='marker'>=</span><span class='string'>'borderLayout'</span></span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span> <span class='highlight'><span class='attrib'>borderLayout</span><span class='marker'>=</span><span class='string'>'north'</span></span><span class='marker'>></span>Above<span class='marker'></</span><span class='element'>label></span>
<span class='marker'><</span><span class='element'>label</span> <span class='highlight'><span class='attrib'>borderLayout</span><span class='marker'>=</span><span class='string'>'south'</span></span><span class='marker'>></span>Below<span class='marker'></</span><span class='element'>label></span>
<span class='marker'></</span><span class='element'>panel</span><span class='marker'>></span></pre>
<p>
Attributes broadly follow names from Spring.
In this example, the value of <code class='attrib'>layout</code> is used to call the container's <code>setLayout</code> method.
</p>
<p>
There's a lot to learn about how to use panels and layout managers, but that's not covered here as it's mostly about Swing and not much about Compositor.
But there is <a href='layout.html'>an introduction to Swing layout managers</a> ("the pink page") that goes along side this documentation.
</p>
<p>
Details of available layout managers and other layout attributes are in the <a href='#reference'>reference material</a> at the end of this page.
</p>
</li>
<li id='actions_1'>
<h4>
Actions
</h4>
<p>
For every action defined in your descriptor, you'll need a corresponding method to implement it.
These match by name.
The action <code>foo</code> would be handled by a method like this:
</p>
<pre><span class='keyword'>public void</span> <span class='highlight'>doFoo</span>( <span class='keyword'>final</span> <span class='class'>ActionEvent</span> e ) {
<span class='comment'>// Do something...</span>
}</pre>
<div class='callout'>
<p>
If you write both versions of an action method (with <em>and</em> without an <code class='class'>ActionEvent</code> parameter) then the no-param version is ignored.
That might explain why it doesn't do what you expect.
</p>
</div>
<p>
In many cases you won't need the event parameter, so this works too:
</p>
<pre><span class='keyword'>public void</span> <span class='highlight'>doFoo</span>() {
<span class='comment'>// Do something...</span>
}</pre>
<p>
Adding the <code>foo</code> action to a menu, toolbar, button, etc. in your descriptor will mean that this method is called at the appropriate time.
</p>
</li>
<li id='eventhandlers'>
<h4>
Event handlers
</h4>
<p>
Your app won't just have actions being triggered by menus, toolbar buttons and keyboard shortcuts.
You'll want elements of your UI to respond directly to the user in other ways, so you'll write event handler methods.
For components to respond to events, they need names, and your event handling methods names must match these component names.
</p>
<p>
Extending the layout example above, one of the components is now named <code>below</code>:
</p>
<pre><span class='marker'><</span><span class='element'>panel</span> <span class='attrib'>layout</span><span class='marker'>=</span><span class='string'>'borderLayout'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span> <span class='attrib'>borderLayout</span><span class='marker'>=</span><span class='string'>'north'</span><span class='marker'>></span>Above<span class='marker'></</span><span class='element'>label></span>
<span class='marker'><</span><span class='element'>label</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string highlight'>'below'</span> <span class='attrib'>borderLayout</span><span class='marker'>=</span><span class='string'>'south'</span><span class='marker'>></span>Below<span class='marker'></</span><span class='element'>label></span>
<span class='marker'></</span><span class='element'>panel</span><span class='marker'>></span></pre>
<p>
If this is in the window named <code>main</code> then we can make an event handler for clicks on the label like this.
</p>
<pre>
<span class='comment'>// Handle clicks on the "main" window, "below" label.</span>
<span class='keyword'>public void</span> <span class='highlight'>main_below_onClick</span>( <span class='keyword'>final</span> <span class='class'>MouseEvent</span> e ) {
msgBox( <span class='string'>"Label font: "</span> + e.getComponent().getFont() );
}</pre>
<p>
The label now tells us about its font.
</p>
<p>
This example used the <code class='class'>MouseEvent</code> associated with the click, but if you don't need it you can ignore it:
</p>
<pre>
<span class='comment'>// Handle a click, ignoring the event details.</span>
<span class='keyword'>public void</span> <span class='highlight'>main_below_onClick</span>() {
msgBox( <span class='string'>"You clicked a label!"</span> );
}</pre>
</li>
<li id='doubleunderscore'>
<h4>
Double underscore
</h4>
<p>
An event on a frame or dialog has no other component, so the method name has that bit missing: there's a double-underscore in there.
</p>
<pre>
<span class='comment'>// Called when the frame is loaded</span>
<span class='keyword'>public void</span> <span class='highlight'>main__onLoad()</span> {
<span class='comment'>// Do some initialisation here...</span>
}</pre>
</li>
<li id='wildcards'>
<h4>
Wild cards
</h4>
<p>
If you want several components to respond to events in the same way, you can use <code>$</code> as a wild card for part of a method name.
In the following example, clicked components report their names if they are in the <code>main</code> window and their names begin with <code>c</code> and end with <code>t</code>.
</p>
<pre>
<span class='comment'>// Handle a click on various components (cat, cut, cart, etc.)</span>
<span class='keyword'>public void</span> main_c$t_onClick( <span class='keyword'>final</span> <span class='class'>MouseEvent</span> e ) {
msgBox( <span class='string'>"You clicked on "</span> + e.getComponent().getName() );
}</pre>
<p>
If there are two methods that could be applied to some event, one with a wild card and one without, both are called.
The non-wild method is called first.
</p>
</li>
</ol>
</li>
<li id='referringtocomponents'>
<h3>
Referring to components from code
</h3>
<p>
In an event handler, as in the previous example, you can get the source of the event by asking the event object you are passed.
</p>
<p>
All objects given a name in your UI descriptor are also available at run-time by their name.
There are two ways to get hold of them.
</p>
<ol>
<li id='magic'>
<p>
UI components can be discovered auto-magically by your app at start up.
We could find the <code>below</code> label in the <code>main</code> window by declaring a public field <code>main_below</code>. If, like me, you prefer to prefix field names (e.g. <code>m_foo</code> for a member field, <code>s_foo</code> for a static member) then you can use <code>x_</code> for these Compositor "magic" fields: <code>x_main_below</code> works just like <code>main_below</code>.
</p>
<pre> <span class='keyword'>public</span> <span class='class'>JLabel</span> <span class='highlight'>main_below</span>;
<span class='keyword'>public void</span> someMethod() {
<span class='comment'>// A suitably named public field of the right type</span>
<span class='comment'>// will automatically contain the right UI component.</span>
msgBox( <span class='string'>"Label font: "</span> + <span class='highlight'>main_below</span>.getFont() );
}</pre>
</li>
<li>
<p>
Alternatively, all UI components can also be found with a qualified name.
We could find the <code>below</code> label with <code>get( <span class='string'>"main_below"</span> )</code> which returns a <code>CompositorComponent</code> wrapper around the component that allows type-unsafe method calling on the wrapped component.
<p>
<p>
Here's examples of all the objects you can get hold of:
</p>
<dl>
<dt id='frames'>
Frames
</dt>
<dd>
<code><span class='class'>JFrame</span> myFrame = <span class='highlight'>getFrame</span>( <span class='string'>"myFrameName"</span> );</code>
</dd>
<dt id='dialogs'>
Dialogs
</dt>
<dd>
<code><span class='class'>JDialog</span> myDialog = <span class='highlight'>getDialog</span>( <span class='string'>"myDialogName"</span> );</code>
</dd>
<dt id='windows'>
Windows
</dt>
<dd>
<code><span class='class'>Window</span> myWindow = <span class='highlight'>getWindow</span>( <span class='string'>"myWindowName"</span> );<br>
<span class='comment'>// Looks for frames first, then dialogs.</span></code>
</dd>
<dt id='menus'>
Menus
</dt>
<dd>
<code><span class='class'>JPopupMenu</span> myMenu = <span class='highlight'>getMenu</span>( <span class='string'>"myMenuName"</span> );</code>
</dd>
<dt id='toolbars'>
Tool bars
</dt>
<dd>
<code><span class='class'>JToolBar</span> myToolBar = <span class='highlight'>getToolBar</span>( <span class='string'>"myToolBarName"</span> );</code>
</dd>
<dt id='actions_2'>
Actions
</dt>
<dd>
<code><span class='class'>AppAction</span> myAction = <span class='highlight'>getAction</span>( <span class='string'>"myActionName"</span> );</code>
</dd>
<dt id='othercomponents'>
Other components
</dt>
<dd>
<ol type='a'>
<li>
<code><span class='class'>JComponent</span> myComponent = <span class='highlight'>get</span>( <span class='string'>"myFrameOrDialog_myComponentName"</span> ).getComponent();</code>
</li>
<li>
<code>CompositorComponent myComponent = <span class='highlight'>get</span>( <span class='string'>"myFrameOrDialog_myComponentName"</span> );</code>
</li>
<li>
<code><span class='class'>JComponent</span> myComponent = myFrameOrDialog_myComponentName; <span class='comment highlight'>// ...if field is defined</span></code>
</li>
</ol>
</dd>
</dl>
</li>
</ol>
<h4>
Summary
</h4>
<p>
The following expressions will all return the font of a label called <var>below</var> in a frame called <var>main</var>.
Your mileage may vary as to which syntax is better.
</p>
<ul>
<li>
<code>(Font) get( <span class='string'>"main_below"</span> ).call( <span class='string'>"getFont"</span> )</code>
</li>
<li>
<code>get( <span class='string'>"main_below"</span> ).getComponent().getFont()</code>
</li>
<li>
<code>x_main_below.getFont()</code>
</li>
</ul>
</li>
<li id='addingdialogs'>
<h3>
Adding dialogs
</h3>
<p>
Dialogs are defined in a very similar way to frames, but with different contents.
You have a panel of components and a button bar, like this.
</p>
<pre><span class='marker'><</span><span class='element highlight'>dialog</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'showMsg'</span> <span class='attrib'>title<span class='marker'>=</span><span class='string'>'Message'</span><span class='marker'>></span>
</span><span class='marker'><</span><span class='element highlight'>panel</span> <span class='attrib'>padding</span><span class='marker'>=</span><span class='string'>'10'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'msg'</span><span class='marker'>></span>Message here...<span class='marker'></</span><span class='element'>label</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element highlight'>buttonbar</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>button</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'ok'</span> <span class='attrib'>default</span><span class='marker'>=</span><span class='string'>'true'</span><span class='marker'>></span>OK<span class='marker'></</span><span class='element'>button</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>buttonbar</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>dialog</span><span class='marker'>></span></pre>
<p>
You call the dialog something like this.
</p>
<pre><span class='highlight'>showDialog</span>( getDialog( <span class='string'>"showMsg"</span> ), getFrame( <span class='string'>"main"</span> ) );</pre>
<p>
You handle a dialog button press something like this.
</p>
<pre><span class='keyword'>public void</span> <span class='highlight'>showMsg_ok_onPress</span>( <span class='keyword'>final</span> <span class='class'>ActionEvent</span> e ) {
<span class='comment'>// This button just gets rid of the dialog</span>
getDialog( <span class='string'>"showMsg"</span> ).setVisible( <span class='keyword'>false</span> );
}</pre>
</li>
<li id='threads'>
<h3>
Threads
</h3>
<p class='warning'>
All UI updates should happen on the event handling thread.
This is a Swing rule, not a Compositor rule.
</p>
<p>
All processing in Compositor will happen on the event handling thread.
This is important because it's not safe to do any UI updates on another thread.
The <code>main</code> thread that starts your app is one of the ones where no UI stuff should happen.
Compositor makes sure that UI generation happens on the right thread, but it's not a good idea to let your <code>main</code> method do anything besides make an instance of your app.
</p>
<p>
Any long running task should not happen on the event handling thread because the UI is un-responsive while the task runs.
One way to deal with this is to use <a href='http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html'>SwingWorker</a>.
I've never used it, but many people seem keen on it.
</p>
<p>
Another way is simply to start a thread and post updates and results to the event handling thread.
You can make things happen on the event handling thread by calling <code>invokeLater( <span class='string'>"methodName"</span> )</code> on your app, or by explicitly posting a <code class='class'>Runnable</code> to the event queue.
Here's an example of both of those.
</p>
<pre><span class='comment'>// We're going to call this method from another thread...</span>
<span class='keyword'>public void</span> setMessage( <span class='keyword'>final</span> <span class='class'>String</span> msg ) {
someWidget.setText( msg );
}
<span class='keyword'>public void</span> doLongRunningThing() {
<span class='keyword'>new</span> <span class='class'>Thread</span>() {
() -> {
<span class='comment'>// This code is on another thread, so can call UI updates like this:</span>
<span class='highlight'>invokeLater</span>( <span class='string'>"setMessage"</span>, <span class='string'>"Running..." </span>);
<span class='comment'>// This would fail at run time if you got the method name wrong</span>
<span class='comment'>// Something that takes a long time happens here...</span>
<span class='comment'>// Another way to call a UI update is this:</span>
<span class='highlight'>invokeLater</span>( () -> setMessage( <span class='string'>"Done."</span> ) );
<span class='comment'>// This way is type-safe, and can do things besides call a public method.</span>
}
}.start();
}</pre>
<p>
Besides explicitly using threads, you could also use stuff from <code>java.io.concurrent</code> for long running tasks, but that's outside the scope of this documentation.
</p>
</li>
<li id='manipulatingmenus'>
<h3>
Manipulating menus at run time
</h3>
<p>
When you define your UI you can't always know what the menu options should be.
For example, if you want to allow the user to choose a look and feel, you won't know which options are available until the app is running: look and feel availability can vary with platform and JVM version.
Alternatively, you might want to make some menu options configurable, or only available on some platforms.
</p>
<p>
You can deal with this at run time by adding menu items to an existing menu, which you find by name.
</p>
<pre><span class='keyword'>for</span> ( <span class='keyword'>final</span> <span class='class'>String</span> menuText : menuTexts ) {
<span class='keyword'>final</span> <span class='class'>JMenuItem</span> <span class='highlight'>newItem</span> = <span class='keyword'>new</span> <span class='class'>JMenuItem</span>( menuText );
newItem.addActionListener( (e) -> {
<span class='comment'>// Do whatever's appropriate</span>
} );
<span class='highlight'>getMenu</span>( <span class='string'>"myFrameName_myMenuName"</span> ).add( <span class='highlight'>newItem</span> );
}</pre>
</li>
<li id='commoncode'>
<h3>
Common descriptor code
</h3>
<p>
As an app grows in complexity, its descriptor (the XML) can become large and repetitious.
Here are some things you can do to address these problems.
</p>
<ul>
<li id='commonattributes'>
<h4>
Common attributes
</h4>
<p>
If you have a lot of similar components, you can specify common attributes that apply to all components of that type.
Here's an example that sets the margin of all buttons:
</p>
<pre><span class='marker'><</span><span class='element'>windows</span><span class='marker'>></span>
<span class='marker'><</span><span class='element highlight'>commonattributes</span><span class='marker'>></span>
<span class='element'><button </span><span class='attrib'>margin</span>=<span class='string'>'4'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>commonattributes</span><span class='marker'>></span>
<span class='comment'><!-- frames and dialogs defined here --></span>
<span class='marker'></</span><span class='element'>windows</span><span class='marker'>></span></pre>
<p>
Notice that these common attributes apply to all the frames and windows defined in this app.
You can override the common attribute for a specific component.
This would make one button really big:
</p>
<pre><span class='element'><button </span><span class='attrib'>margin</span>=<span class='string'>'99'</span> <span class='marker'>/></span></pre>
</li>
<li id='entitymacros'>
<h4>
Entity macros
</h4>
<p>
If you need repetitive sections in your UI descriptor, you can define an XML entity and use that to generate the repeated elements.
In this pet name app example, the content of the dialogs <code>cat</code> and <code>dog</code> are the same, so we can specify it only once as a <code>widgets</code> entity.
This isn't a Compositor feature.
It's just how XML works.
</p>
<pre><span class='marker'><!DOCTYPE</span> ui [
<span class='marker'><!ENTITY</span> <span class='highlight'>widgets</span>
<span class='string'>"<panel>
<label>Name:</label>
<textfield cols='10' />
</panel>
<include file='buttonbar_okcancel.xml' />"</span>
>
]>
<span class='marker'><</span><span class='element'>ui</span> <span class='attrib'>name</span>=<span class='string'>'Pets'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>windows</span><span class='marker'>></span>
<span class='comment'><!-- snip --></span>
<span class='marker'><</span><span class='element'>dialog</span> <span class='attrib'>name</span>=<span class='string'>'cat'</span> <span class='attrib'>title</span>=<span class='string'>'Cat'</span><span class='marker'>></span>
&<span class='highlight'>widgets</span>;
<span class='marker'></</span><span class='element'>dialog</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>dialog</span> <span class='attrib'>name</span>=<span class='string'>'dog'</span> <span class='attrib'>title</span>=<span class='string'>'Dog'</span><span class='marker'>></span>
&<span class='highlight'>widgets</span>;
<span class='marker'></</span><span class='element'>dialog</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>windows</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span>
</pre>
</li>
<li id='includemacros'>
<h4>
Include macros
</h4>
<p>
For repetitive but non-identical sections, you could use <code class='element'>include</code> macros.
The idea here is that you put the structure of the repetitious part in a separate file, then include it with (optional) customisations.
</p>
<p>
That's how <code>buttonbar_okcancel.xml</code> (and friends) work.
You can add a standard set of dialog buttons (and specify the text they display) by including one of these.
See <a href='#refDialog'>the <code class='element'>dialog</code> reference</a> for more.
</p>
<p>
But includes can be more complex.
Here's the same pet example done with <code class='element'>include</code> macros.
</p>
<div class='callout'>
<p>
This section doesn't show you what the result is of combining <code>petDialog.inc</code> and <code>Pets.xml</code> because if the app looks right, that's all you need to see.
However, if you're having trouble getting it right, you could set the debug level to verbose.
You will get <em>lots</em> of info (or too much info) about what's going on.
The resultant descriptor is in there.
Look for the last XML dump.
</p>
</div>
<h5>
petDialog.inc
</h5>
<pre><span class='marker'><</span><span class='element highlight'>forEach</span> <span class='attrib'>tag</span>=<span class='string highlight'>'p:dlg'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>dialog</span> <span class='attrib'>name</span>=<span class='string'>'<span class='highlight'>${dlgName}</span>'</span> <span class='attrib'>title</span>=<span class='string'>'<span class='highlight'>${dlgTitle}</span>'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span><span class='marker'>></span>Name of <span class='highlight'>${petType=pet}</span>:<span class='marker'></</span><span class='element'>label</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>textfield</span> <span class='attrib'>cols</span>=<span class='string'>'10'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>include</span> <span class='attrib'>file</span>=<span class='string'>'buttonbar_okcancel.xml'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>dialog</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>forEach</span><span class='marker'>></span></pre>
<p>
Notice the <code class='element'>forEach</code> part.
For each <code class='element'>p:dlg</code> tag you nest in the <code class='element'>include</code> in your descriptor, the contents of the <code>forEach</code> is duplicated.
</p>
<p>
Notice also the dollar-curly variables.
These will be replaced with values that you specify in your descriptor.
It's possible to supply a default value in the <code class='element'>include</code> to be used if no value is given by the descriptor.
So <code>${petType=pet}</code> means <q>use the value of <code>petType</code> here, or if there isn't one, use the string <code>pet</code></q>.
</p>
<h5>
Pets.xml
</h5>
<pre><span class='marker'><</span><span class='element'>ui</span> <span class='attrib'>name</span>=<span class='string'>'Pets'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>windows</span><span class='marker'>></span>
<span class='comment'><!-- snipped frame and other dialogs --></span>
<span class='marker'><</span><span class='element'>include</span> <span class='attrib'>file</span>=<span class='string'>'petDialog.inc'</span> <span class='attrib'>xmlns:p</span>=<span class='string'>'http://net.sf.compositor/petDialog'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element highlight'>p:dlg</span> <span class='attrib'>dlgName</span>=<span class='string'>'cat'</span> <span class='attrib'>dlgTitle</span>=<span class='string'>'Cat'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element highlight'>p:dlg</span> <span class='attrib'>dlgName</span>=<span class='string'>'dog'</span> <span class='attrib'>dlgTitle</span>=<span class='string'>'Dog'</span> <span class='attrib'>petType</span>=<span class='string'>'faithful friend'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>include</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>windows</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span></pre>
<p>
A quirk here is that attributes that end up with no value are removed.
When Compositor comes to build the UI, it might be confused by <code><span class='attrib'>someAttrib</span>=<span class='string'>''</span></code> so <code class='attrib'>someAttrib</code> disappears altogether.
This means that the attribute takes its normal value (e.g. <code class='attrib'>layout</code> of a panel defaults to <code>flowLayout</code>).
</p>
<p>
This works with defaults in dollar-curly variables too: <code>${foo=}</code> sets the default to nothing, so if that's used as the value of an attribute and you don't supply a value in your descriptor, that attribute disappears.
</p>
<p>
See <a href='#xibbonmacro'>XibbonMacro</a> for a more complex example, including nested <code class='element'>forEach</code>.
That example also uses <code><<span class='element'>copyChildren</span>/></code> to allow the ribbon contents to come from the descriptor.
Only the structure is generated by that <code class='element'>include</code> macro.
</p>
</li>
<li id='clones'>
<h4>
Clones
</h4>
<p>
Sometimes you don't know until run time how many components to display.
For example, in a tabbed editor, the user might open any number of files, or none.
To make this work, you can define the components that make up one item as a <code class='element'>clone</code>.
Here's an example:
</p>
<pre>
<span class='marker'><</span><span class='element'>ui </span><span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'Foo'</span><span class='marker'>></span>
<span class='comment'><!-- actions go here --></span>
<span class='marker'><</span><span class='element highlight'>clones</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>scrollpane</span> <span class='attrib highlight'>cloneName</span><span class='marker'>=</span><span class='string'>'fileWidget'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>textarea</span> <span class='attrib'>wrap</span><span class='marker'>=</span><span class='string'>'true' </span><span class='attrib'>wrapStyle</span><span class='marker'>=</span><span class='string'>'word' </span><span class='marker'>/></span>
<span class='marker'></</span><span class='element'>scrollpane</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>clones</span><span class='marker'>></span>
<span class='comment'><!-- windows go here --></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span></pre>
<p>
You can build a new clone instance like this:
</p>
<pre><span class='keyword'>private void </span>addFile( <span class='keyword'>final </span><span class='class'>String</span> fileName ) {
<span class='comment'>// build "fileWidget" clone and add to "files" in window "main"</span>
<span class='keyword'>final </span><span class='class'>JScrollPane</span> sp = (<span class='class'>JScrollPane</span>) <span class='highlight'>buildClone</span>( <span class='string'>"fileWidget"</span>, <span class='string'>"main"</span>, main_files );
<span class='keyword'>if </span>( <span class='keyword'>null</span> != sp ) {
<span class='comment'>// tweak the results</span>
main_files.setTitleAt( main_files.getTabCount() - <span class='number'>1</span>, fileName );
( (<span class='class'>JTextArea</span>) sp.getViewport().getView() ).setText( <span class='string'>"Should come from file..."</span> );
}
}</pre>
<p>
A clone component needs a <code class='attrib'>cloneName</code> so that you can say which kind of clone to build.
</p>
<p>
Clones can't be defined with component names because you'll be making more than one of them, and names should be unique.
So there is no point in using a <code class='attrib'>name</code> attribute anywhere in a clone.
But you can give them a name when you build them.
</p>
<pre><span class='keyword'>private void </span>addFile( <span class='keyword'>final </span><span class='class'>String</span> fileName, <span class='keyword'>final </span><span class='class'>String</span> widgetName ) {
<span class='comment'>// build "file" clone, add to "files" in window "main", and call it widgetName</span>
<span class='keyword'>final </span><span class='class'>JScrollPane</span> sp = (<span class='class'>JScrollPane</span>) <span class='highlight'>buildClone</span>( <span class='string'>"fileWidget"</span>, <span class='string'>"main"</span>, main_files, <span class='highlight'>widgetName</span> );
}</pre>
<p>
If <code>widgetName</code> was <code>foo</code> you can, for example, call a method on it like this:
</p>
<pre>get( <span class='string'>"main_foo"</span> ).call( <span class='string'>"someMethod"</span>, <span class='string'>"Some param"</span> );</pre>
</li>
<li id='delegates'>
<h4>
Delegates
</h4>
<p>
You can hand off part of the work of building your UI and handling its events to a delegate.
This can be useful if you want to re-use some of your UI.
It can also help reduce the size of your main app class, which may grow large as your app gains functionality.
</p>
<p>
A delegate class extends <code>Delegate</code> and can be used in place of a frame, a dialog, or a component.
This class loads a descriptor of its own in the same way as an app.
The class will also handle events for the UI elements it has built.
</p>
<ol>
<li>
<h5>
Frames and dialogs
</h5>
<p>
Add a delegate for a frame or dialog to your app descriptor in a similar way to this dialog example:
</p>
<pre><span class='marker'><</span><span class='element'>ui</span> <span class='attrib'>name</span>=<span class='string'>'Delegate example'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>windows</span><span class='marker'>></span>
<span class='comment'><!-- frame definitions here --></span>
<span class='marker'><</span><span class='element highlight'>delegate </span><span class='attrib'>class</span>=<span class='string'>'com.example.SomeDialog'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>windows</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span></pre>
<p>
The class would look something like this.
</p>
<pre><span class='comment'>// package, imports</span>
<span class='keyword'>public class</span> SomeDialog <span class='keyword'>extends</span> <span class='highlight'>Delegate</span> {
<span class='comment'>// Constructor - should do nothing but call super</span>
<span class='keyword'>public</span> SomeDialog( DescriptorLoader descriptorLoader, UIInfo uiInfo, <span class='keyword'>int</span> indent )
<span class='keyword'>throws</span> XmlParserException {
<span class='keyword'>super</span>( descriptorLoader, uiInfo, indent );
}
<span class='comment'>// Example button handling method</span>
<span class='keyword'>public void</span> someDialog_ok_onPress() {
getDialog( <span class='string'>"someDialog"</span> ).call( <span class='string'>"setVisible"</span>, <span class='keyword'>false </span>);
}
}</pre>
<p>
The delegate class here is <code>com.example.SomeDialog</code> so its descriptor will be <code>SomeDialog.delegate</code>.
The descriptor for a frame or dialog delegate is not very different from what you would put in an app descriptor, except:
</p>
<ul>
<li>
the frame/dialog is wrapped in a <span class='element'>uifragment</span> element
</li>
<li>
the file name ends with <code>.delegate</code>
</li>
</ul>
<p>
Here's an example.
</p>
<pre><span class='marker'><</span><span class='element highlight'>uifragment</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>dialog</span> <span class='attrib'>name</span>=<span class='string'>'someDialog'</span> <span class='attrib'>title</span>=<span class='string'>'A Dialog'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span><span class='marker'>></span>This is a delegate<span class='marker'><</span>/<span class='element'>label</span><span class='marker'>></span>
<span class='marker'><</span>/<span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>include</span> <span class='attrib'>file</span>=<span class='string'>'buttonbar_ok.xml'</span> /<span class='marker'>></span>
<span class='marker'><</span>/<span class='element'>dialog</span><span class='marker'>></span>
<span class='marker'><</span>/<span class='element'>uifragment</span><span class='marker'>></span></pre>
<p>
The example SimpleEdit includes a dialog that is a delegate.
</p>
</li>
<li>
<h5>
Components
</h5>
<p>
A delegate for a component is similar, but it generates only part of a frame or dialog.
This example adds a date and time picker to a dialog.
</p>
<pre><span class='marker'><</span><span class='element'>dialog</span> <span class='attrib'>name</span>=<span class='string'>'dateDialog'</span> <span class='attrib'>title</span>=<span class='string'>'Pick a date and time'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>panel</span><span class='marker'>></span>
<span class='comment'><!-- other components --></span>
<span class='marker'><</span><span class='element highlight'>delegate</span> <span class='attrib'>name</span>=<span class='string'>'dateTimePicker'</span> <span class='attrib'>class</span>=<span class='string'>'DateTimePicker'</span> /<span class='marker'>></span>
<span class='comment'><!-- other components --></span>
<span class='marker'><</span>/<span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>include</span> <span class='attrib'>file</span>=<span class='string'>'buttonbar_ok.xml'</span> /<span class='marker'>></span>
<span class='marker'><</span>/<span class='element'>dialog</span><span class='marker'>></span></pre>
<p>
A component delegate class is very similar to a frame or dialog delegate.
</p>
<pre><span class='comment'>// package, imports</span>
<span class='keyword'>public class</span> DateTimePicker <span class='keyword'>extends</span> <span class='highlight'>Delegate</span> {
<span class='comment'>// Constructor - should do nothing but call super</span>
<span class='keyword'>public</span> DateTimePicker ( DescriptorLoader descriptorLoader, UIInfo uiInfo, <span class='keyword'>int</span> indent )
<span class='keyword'>throws</span> XmlParserException {
<span class='keyword'>super</span>( descriptorLoader, uiInfo, indent );
}
<span class='comment'>// Example button handling method</span>
<span class='comment'>// No window name - don't know what it will be!</span>
<span class='keyword'>public void</span> _useCurrentDateTime_onPress() {
<span class='comment'>// Set fields to the current date/time</span>
}
<span class='comment'>// Expose the results of this dialog</span>
<span class='keyword'>public void</span> getLastDate() {
<span class='comment'>// return the value that the user chose</span>
}
}</pre>
<p>
The descriptor for a component delegate is again named <code>.delegate</code>, and has <code class='element'>uifragment</code> as a root element, but then can contain any component or container.
Here's a very simple example.
</p>
<pre><span class='marker'><</span><span class='element highlight'>uifragment</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>label</span><span class='marker'>></span>This is a delegate<span class='marker'><</span>/<span class='element'>label</span><span class='marker'>></span>
<span class='marker'><</span>/<span class='element'>uifragment</span><span class='marker'>></span></pre>
<p>
It's not a good idea for your app to rely on details of the UI widgets displayed by the delegate.
So instead of your app interacting directly with the delegate UI widgets, you can call methods on the delegate.
To make this work, the component delegate needs a name.
Here's some example app code.
</p>
<pre><span class='keyword'>public void</span> importantDatePicker_ok_onPress() {
getDialog ( <span class='string'>"dateDialog"</span> ).setVisible ( <span class='keyword'>false</span> );
importantDate = getDelegate ( <span class='string'>"dateDialog_dateTimePicker"</span> ).call ( <span class='string'>"getLastDate"</span> ) );
}</pre>
</li>
</ol>
</li>
<li id='cloneddelegates'>
<h4>
Cloned delegates
</h4>
<p>
It's possible to combine clones and delegates, so that a cloned section can be (or include) a delegate.
</p>
<pre>
<span class='marker'><</span><span class='element'>ui </span><span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'Foo'</span><span class='marker'>></span>
<span class='comment'><!-- actions go here --></span>
<span class='marker'><</span><span class='element highlight'>clones</span><span class='marker'>></span>
<span class='marker'><</span><span class='element highlight'>delegate</span> <span class='attrib'>cloneName</span><span class='marker'>=</span><span class='string'>'delegateWidget'</span> <span class='attrib'>class</span><span class='marker'>=</span><span class='string'>'MyDelegateWidget'</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>clones</span><span class='marker'>></span>
<span class='comment'><!-- windows go here --></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span></pre>
<p>
Now you can create as many <code class='element'>delegateWidget</code> instances as you need, and their events are handled by <code class='class'>MyDelegateWidget</code>.
</p>
<p>
You may need to do some start-up logic for each component as it is created.
For a window, you might use <code>_onLoad</code>, but for a delegate component that doesn't exist.
Your delegate class can override <code>setParent</code> instead because that is always called when a new delegate is created.
Here's an example.
</p>
<pre><span class='keyword'>@Override
protected void</span> setParent( <span class='keyword'>final</span> <span class='class'>UIHandler</span> parentUIHandler ) {
<span class='highlight'><span class='keyword'>super</span>.setParent( parentUIHandler );</span>
invokeLater( () -> {
<span class='comment highlight'>// Delegate start-up logic goes here</span>
} );
}</pre>
</li>
</ul>
</li>
<li id='environmentvariables'>
<h3>
Environment variables
</h3>
<p>
Besides dollar-curly variables in <a href='#includemacros'><code class='element'>include</code> macros</a>, you can use them to include information about the app's environment.
</p>
<p>
You can add environment variables.
</p>
<pre>${environment.PATH}</pre>
<p>
What's available is platform dependant, so relying on this may stop your app working on another operating system.
</p>
<p>
You can add values from the <a href='#env'>Env</a> class.
</p>
<pre>${Env.USER_HOME}</pre>
<p>
These should be more platform independent.
</p>
</li>
<li id='splashscreen'>
<h3>
Splash screen
</h3>
<p>
If your app is complex, it may take a little time to load.
You can display an image as a splash screen during this time by adding something like this to your descriptor.
This image is displayed after the descriptor is read, but before the UI is built.
It is not removed until the application has started.
</p>
<pre><span class='marker'><</span><span class='element'>ui</span><span class='marker'>></span>
<span class='marker'><</span><span class='element highlight'>splash</span> <span class='attrib'>image</span>=<span class='string'>'mySplashImage.png'</span> <span class='marker'>/></span>
<span class='comment'><-- rest of descriptor... --></span>
<span class='marker'></</span><span class='element'>ui</span><span class='marker'>></span></pre>
</li>
<li id='customcomponents'>
<h3>
Custom components
</h3>
<ul>
<li id='writing'>
<h4>
Writing
</h4>
<p>
Any Swing component can be used in Compositor, including ones you've written yourself.
There are no special constraints on how you write a component to use with Compositor, except that it should have a no-argument constructor.
</p>
<p>
You may also need to write a <code class='class'>Generator</code> for custom components.
</p>
<ul>
<li>
If your component doesn't need any attributes set, you can use the generic <code class='class'>Generator</code>.
</li>
<li>
If you're making a subclass of a component that Compositor knows about, you may be able to re-use an existing <code class='class'>Generator</code>.
For example, if you made a subclass of <code class='class'>JTextField</code> then you may be able to use <code>net.sf.compositor.<span class='class'>TextFieldGenerator</span></code>.
</li>
<li>
Otherwise, write you own class extending <code class='class'>Generator</code> overriding whichever of the following methods are appropriate.
<dl>
<dt>Constructor</dt>
<dd>
<ul>
<li>
Must take a <code class='class'>UIHandler</code> parameter.
</li>
<li>
Can take a <code class='class'>String</code> class name parameter.
If components share the same generator, this parameter is used to decide what to construct.
If a generator only makes one type of component, this paramter is not required.
</li>
<li>
Must call the superclass constructor, passing the app and a class name.
</li>
</ul>
</dd>
<dt>Method <code>setAttributes</code></dt>
<dd>
<ul>
<li>
Allows you to handle attributes from the descriptor and call appropriate methods on the component that is being generated
</li>
<li>
You only need to implement this method if you have some attributes to handle.
</li>
<li>
Here's an example
<pre><span class='keyword'>@Override
protected void</span> <span class='highlight'>setAttributes</span>( <span class='keyword'>final</span> <span class='class'>UIHandler</span> uiHandler, <span class='keyword'>final</span> <span class='class'>JComponent</span> component, <span class='keyword'>final</span> <span class='class'>String</span> windowName, <span class='keyword'>final</span> <span class='class'>String</span> componentName, <span class='keyword'>final</span> <span class='class'>Config</span> attribs, <span class='keyword'>final int</span> indent ) {
<span class='comment'>// Some helper methods are available for setting an int, boolean, etc.</span>
setIntAttribute( component, attribs, <span class='string'>"foo"</span>, <span class='string'>"setFoo"</span>, <span class='string'>"widget foo value"</span> );
<span class='comment'>// If it's more complex, do something like this</span>
<span class='keyword'>if</span> ( attribs.containsKey( <span class='string'>"orientation"</span> ) ) {
<span class='keyword'>final</span> <span class='class'>String</span> orientation = attribs.getProperty( <span class='string'>"orientation"</span> );
<span class='keyword'>final</span> <span class='class'>MyWidget</span> myWidget = ( <span class='class'>MyWidget</span> ) component;
<span class='keyword'>switch</span> ( orientation ) {
<span class='keyword'>case</span> <span class='string'>"horizontal"</span>:
myWidget.setOrientation( <span class='class'>MyWidget</span>.HORIZONTAL );
break;
<span class='comment'>// more orientation options...</span>
<span class='keyword'>default</span>:
s_log.warn ( <span class='string'>"Unexpected widget orientation: "</span>, orientation );
}
}
}</pre>
</li>
</ul>
</dd>
<dt>Method <code>addListener</code></dt>
<dd>
<ul>
<li>
This generator method is called once for each app method that matches a component.
</li>
<li>
Just because an app has <code>window_widget_onFoo()</code> doesn't mean that <code>widget</code> will respond to a <code><var>Foo</var></code> event.
Your generator needs to add listeners to the component and make them call the app method.
</li>
<li>
You only need to implement this method if you have some events to listen for.
</li>
<li>
Here's an example of how to get <code>window_widget_onFoo()</code> called when a <code><var>Foo</var></code> event occurs:
<pre><span class='keyword'>@Override
protected void</span> <span class='highlight'>addListener</span>( <span class='keyword'>final</span> <span class='class'>UIHandler</span> uiHandler, <span class='keyword'>final</span> <span class='class'>Method</span> method, <span class='keyword'>final</span> <span class='class'>String</span> eventName, <span class='keyword'>final</span> <span class='class'>String</span> getStr, <span class='keyword'>final</span> <span class='string'>Component</span> component, <span class='keyword'>final int</span> indent ) {
<span class='keyword'>if</span> ( <span class='string'>"Foo"</span>.equals( eventName ) ) {
component.addFooListener
(
new <span class='keyword'>FooListener</span>() {
<span class='keyword'>@Override
public void</span> foo( <span class='keyword'>final</span> <span class='class'>FooEvent</span> e ) {
uiHandler.getCallable().call( method.getName(), e, <span class='class'>FooEvent</span>.class );
}
}
);
}
}</pre>
</li>
</ul>
</dd>
<dt>Method <code>finishMaking</code></dt>
<dd>
This method is called after the component has been built, and (if it's a container) after all its contents have been added to it.
Occasionally it's useful to do something when the state of everything is known.
Only implement this method if you need it.
</dd>
<dt>Method <code>setContent</code></dt>
<dd>
If the descriptor has some text content for an element, what should we do with it?
If the component has a <code>setText</code> method, that will be called.
If your component doesn't have a <code>setText</code> method, implement <code>setContent</code> this in your generator.
</dd>
</dl>
</li>
</ul>
<p>
For your app to handle events on custom components involves <a href='#eventhandlers'>writing a suitably named method</a>, just like any other component.
</p>
</li>
<li id='declaring'>
<h4>
Declaring
</h4>
<p>
Add your custom component as a <code class='element'>component</code> element in <code class='element'>components</code>.
The attributes are:
</p>
<dl>
<dt><code class='attrib'>name</code></dt>
<dd>(required)<br>How to refer to this component in your UI descriptor - XML namespace will prevent tears later</dd>
<dt><code class='attrib'>generator</code></dt>
<dd>(required)<br>A class name for your <code class='class'>Generator</code></dd>
<dt><code class='attrib'>class</code></dt>
<dd>(optional - depends if the generator's constructor needs it)<br>The class name of the component</dd>
</dl>
<p>
An example:
</p>
<pre><span class='marker'><</span><span class='element'>components</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>component</span>
<span class='attrib'>name</span><span class='marker'> = </span><span class='string'>'<span class='highlight'>c:tfwm</span>'</span>
<span class='attrib'>generator</span><span class='marker'> = </span><span class='string'>'net.sf.compositor.TextFieldGenerator'</span>
<span class='attrib'>class</span><span class='marker'> = </span><span class='string'>'net.sf.compositor.widgets.TextFieldWithMenu'</span>
<span class='marker'>/></span>
<span class='marker'></</span><span class='element'>components</span><span class='marker'>></span></pre>
</li>
<li id='generating'>
<h4>
Generating
</h4>
<p>
Now if you use the custom component in your UI, the <code class='class'>Generator</code> should generate it correctly and the component should appear in your UI.
</p>
<pre><span class='marker'><</span><span class='element'>panel</span><span class='marker'>></span>
<span class='marker'><</span><span class='element highlight'>c:tfwm</span>
<span class='attrib'>name</span><span class='marker'> = </span><span class='string'>'myTextField'</span>
<span class='attrib'>size</span><span class='marker'> = </span><span class='string'>'16'</span>
<span class='attrib'>fontWeight</span><span class='marker'> = </span><span class='string'>'bold'</span>
<span class='marker'>></span>This text has a context menu.<span class='marker'></</span><span class='element'>c:tfwm</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>panel</span><span class='marker'>></span></pre>
</li>
</ul>
</li>
<li id='draganddrop'>
<h3>
Drag and Drop
</h3>
<ul>
<li id='draggingtext'>
<h4>
Dragging and dropping text
</h4>
<h5>
Dragging notes
</h5>
<p>
To do:
</p>
<ul>
<li>
<code>dragEnabled</code> attrib to set <code>setDragEnabled</code>
</li>
<li>
how would drop work?
</li>
</ul>
<h5>
Dropping
</h5>
<p>
Some Swing components already support dropping text onto them:
</p>
<ul>
<li>
JEditorPane
</li>
<li>
JPasswordField
</li>
<li>
JTextArea
</li>
<li>
JTextField
</li>
<li>
JColorChooser
</li>
</ul>
</li>
<li id='draggingcomponents'>
<h4>
Dragging components
</h4>
<p>
Support for dragging and dropping UI components is built in to Compositor.
In your UI descriptor, you can define any component as draggable and any panel as a drop target.
Then you can drag any of the draggable components into any of the drop targets.
</p>
<ul>
<li id='dragsources'>
<h5>
Component drag sources
</h5>
<p>
To make a component draggable, add <code><span class='attrib'>draggable</span>=<span class='string'>'true'</span></code> to its attributes.
</p>
<p>
Optionally, if you want more control over whether or not to initiate a drag, implement a method like this:
</p>
<pre><span class='keyword'>public void</span> [window]_[component]_<span class='highlight'>onDragGestureRecognized</span>( <span class='keyword'>final</span> <span class='class'>DragGestureEvent</span> e ) {
<span class='keyword'>if</span> ( [some condition] ) {
e.startDrag( <span class='keyword'>null</span>, new TransferableComponent( e.getComponent() ) );
<span class='comment'>// See DragGestureEvent documentation for variants of startDrag</span>
}
}</pre>
</li>
<li id='droptargets'>
<h5>
Panel drop targets
</h5>
<p>
To make a panel accept component drops, add <code><span class='attrib'>dropTarget</span>=<span class='string'>'true'</span></code> to its attributes.
</p>
<p>
Optionally, if you want the drop to have an effect other than moving the dropped component in to the panel, implement a drop handler something like this:
</p>
<pre><span class='keyword'>public void</span> [window]_[component]_<span class='highlight'>onDrop</span>( <span class='keyword'>final</span> <span class='class'>DropTargetDropEvent</span> e ) {
e.acceptDrop( e.getDropAction() );
try {
<span class='keyword'>final</span> <span class='class'>Component</span> dropped = ( <span class='class'>Component</span> ) e.getTransferable()
.getTransferData( TransferableComponent.FLAVOUR );
...
e.dropComplete( <span class='keyword'>true</span> );
}
<span class='comment'>//catch blocks...</span>
}</pre>
<p>
To have more control over whether the dragged object is droppable on a panel, implement event handlers like this:
</p>
<pre><span class='keyword'>public void</span> [window]_[component]_<span class='highlight'>onDragOver</span>( <span class='keyword'>final</span> <span class='class'>DropTargetDragEvent</span> e )
<span class='keyword'>public void</span> [window]_[component]_<span class='highlight'>onDropActionChanged</span>( <span class='keyword'>final</span> <span class='class'>DropTargetDragEvent</span> e )</pre>
<p>
Your drop target may also handle notifications that a drag is taking place over it:
</p>
<pre><span class='keyword'>public void</span> [window]_[component]_<span class='highlight'>onDragEnter</span>( <span class='keyword'>final</span> <span class='class'>DropTargetDragEvent</span> e )
<span class='keyword'>public void</span> [window]_[component]_<span class='highlight'>onDragExit</span>( <span class='keyword'>final</span> <span class='class'>DropTargetEvent</span> e )</pre>
<p>
These event handlers all correspond to <code class='class'>DropTargetListener</code> events.
</p>
</li>
</ul>
</li>
<li id='otherdragtypes'>
<h4>
Other drag types
</h4>
<p>
The built-in drag and drop support will only directly handle dragging UI components.
Just making a panel a drop target is not enough to allow you to drop other things on the panel.
</p>
<p>
But with only a little extra work, drags of other things, including drags from outside your app <em>can</em> be accepted.
For example, you could accept files being dropped onto your app, a common alternative to a file open dialog.
</p>
<p>
Write handlers for <code>onDragOver</code> and <code>onDrop</code>.
You may also need to handle other events.
See <a href='#refPanel'>the reference for panel</a> for what event handlers are available.
These handlers should decide whether a drag is droppable, and what to do with the dropped data.
</p>
<ul>
<li>
See <a href='#tilex'>Tilex</a> for an example of how to accept drags as an alternative to the file open dialog.
</li>
<li>
See <a href='#simpleedit'>SimpleEdit</a> for an example of how to accept file drags on a <code class='element'>textarea</code>.
</li>
<li>
See <a href='#dragdrop3'>DragDrop3</a> for a more generic example of how to accept drags of many kinds.
</li>
</ul>
<p>
<strong>To do...</strong>
</p>
<p>
Drags <em>to</em> other apps?
</p>
</li>
</ul>
</li>
</ol>
</li>
<li id='filebasedapps'>
<h2>
File based apps
</h2>
<ol type='i'>
<li id='prebuildfunctionality'>
<h3>
Pre-build functionality
</h3>
<p>
Many applications involve opening a file, manipulating the data, and saving it.
Such apps have a lot in common.
Your app can extend <code>FileApp</code> to get this pre-built.
You should also implement a data handling class that extends <code>AppFile</code>.
Separating UI and data handling is a Good Thing.
</p>
<p>
The sample apps <a href='#ratedate'>RateDate</a>, <a href='#spsh'>Spsh</a>, <a href='#tilex'>Tilex</a> and <a href='#xide'>Xide</a> follow this pattern.
</p>
</li>
<li id='stateuiinteraction'>
<h3>
State/UI interaction
</h3>
<p>
The UI needs to be updated when the data changes.
One way of achieving this is to make the data object a model for a UI component (e.g. a <code class='class'>TreeModel</code> for a <code class='class'>JTree</code>).
This is how <a href='#spsh'>Spsh</a> works.
</p>
<p>
An alternative is to add a <code class='class'>ChangeListener</code> to your data class that will update your UI, and have your data class call <code>fireStateChanged()</code> as appropriate.
This is how Tilex works.
</p>
</li>
<li id='descriptorrequirements'>
<h3>
Descriptor requirements
</h3>
<p>
The following actions are already implemented in <code>FileApp</code>
Just define them in your descriptor.
You need to provide a <code>newDataInstance</code> method in your app, and <code>loadHandler</code> and <code>save</code> methods in your data class.
</p>
<ul>
<li>new</li>
<li>open</li>
<li>save</li>
<li>saveAs</li>
<li>exit</li>
</ul>
<p>
These actions will write information to a status bar if you have one called <code>main_statusBar</code>.
</p>
</li>
<li id='savingreminders'>
<h3>
Saving reminders
</h3>
<p>
It's helpful for the user to be reminded to save when your app closes, or when they open a different file.
Because the <code>exit</code> action is already implemented, you just need to set <code>m_changed</code> in your data class at the appropriate times for this to work.
</p>
</li>
<li id='undoredosupport'>
<h3>
Undo/redo support
</h3>
<p>
Two further actions will work if you add some behaviour.
</p>
<ul>
<li>undo</li>
<li>redo</li>
</ul>
<p>
To implement undo/redo, your data class must do two things.
</p>
<ol>
<li>
<h4>Methods that perform undoable edits must create a <code class='class'>StateEdit</code> object</h4>
<p>
That means something like this:
</p>
<pre><span class='comment'>// Create an edit</span>
<span class='keyword'>final</span> <span class='highlight'><span class='class'>StateEdit</span> edit = <span class='keyword'>new</span> <span class='class'>StateEdit</span></span>( this, <span class='string'>"Some descriptive text"</span> );
<span class='comment'>// Change the data</span>
this.whatever();
<span class='comment'>// "End" the edit</span>
<span class='highlight'>edit.end</span>();
<span class='comment'>// Post the edit to the undo system</span>
m_undoSupport.<span class='highlight'>postEdit( edit )</span>;
</pre>
</li>
<li>
<h4>Override <code>storeState</code> and <code>restoreState</code></h4>
<pre><span class='keyword'>@Override
public void</span> storeState( <span class='keyword'>Hashtable</span> < <span class='keyword'>Object</span>, <span class='keyword'>Object</span> > state ) {
<span class='comment'>// Record any relevant state</span>
state.put( <span class='string'>"somename"</span>, somevalue );
state.put( <span class='string'>"othername"</span>, othervalue );
}
<span class='keyword'>@Override
public void</span> restoreState( <span class='keyword'>Hashtable</span> < ?, ? > state ) {
<span class='comment'>// Only things that changed are in the state!</span>
<span class='keyword'>if</span> ( state.containsKey ( <span class='string'>"somename"</span> ) ) {
<span class='comment'>// Restore the value somehow</span>
this.somevalue = ( Foo ) state.get( <span class='string'>"somename"</span> );
}
<span class='keyword'>if</span> ( state.containsKey ( <span class='string'>"othername"</span> ) ) {
this.othervalue = ( Bar ) state.get( <span class='string'>"othername"</span> );
}
}</pre>
</li>
</ol>
</li>
</ol>
</li>
<li id='thingsthatmighthelp'>
<h2>
Things that might help
</h2>
<p>
Making a GUI app isn't all about laying out the GUI.
Compositor includes a number of things to help in other areas.
</p>
<p>
There are helper <a href='#methodsthatmighthelp'>methods</a> and <a href='#classesthatmighthelp'>classes</a>.
</p>
<ul>
<li id='methodsthatmighthelp'>
<h3>
Methods
</h3>
<p>
All of these are inherited from <code>UIHandler</code> so you can call them anywhere in your app.
They're listed in alphabetical order.
</p>
<ul class='methods'>
<li>
<h4 id='accceptFileDragDrop'>
acceptFileDragOver/acceptFileDrop
</h4>
<p>
If you want to accept dragging and dropping a file on your app, you can do something like this.
</p>
<pre><span class='keyword'>public void</span> myWindow_myWidget_onDragOver( <span class='keyword'>final</span> <span class='class'>DropTargetDragEvent</span> e ) {
<span class='keyword'>return</span> <span class='highlight'>acceptFileDragOver</span>( e );
}
<span class='keyword'>public boolean</span> myWindow_myWidget_onDrop ( <span class='keyword'>final</span> <span class='class'>DropTargetDropEvent</span> e ) {
<span class='keyword'>return</span> <span class='highlight'>acceptFileDrop</span>( e, file -> myFileOpenMethod( file.getAbsolutePath () ), x_myWindow );
}</pre>
<p>
This only helps if you want to accept a single file being dropped on your app. To accepts multiple files, look at how <a href='#multiedit'>MultiEdit</a> does it. To accept string drops, look at how <a href='#dixtionary'>Dixtionary</a> does it.
</p>
</li>
<li>
<h4 id='actionPostInvoke'>
actionPostInvoke
</h4>
<p>
After processing an action, this method is invoked.
You can override it if you want some tidying up to happen.
</p>
<p>
It's a protected method that takes a <code class='class'>String</code> parameter, the name of the action.
</p>
<p>
A common use for this is to restore focus.
If the user clicked a toolbar button, the button will have focus.
This is probably not what the user would want.
</p>
</li>
<li>
<h4 id='changeLnF'>
addLnfMenuItems/changeLnF
</h4>
<p>
<code>addLnfMenuItems</code> allows you to add an item per available look and feel to a menu.
These menu items will call <code>changeLnF</code> and it is possible to call that method directly if you prefer another way of choosing the look and feel.
</p>
<p>
This example would add look and feel items to a menu called <code>lnf</code> in a frame called <code>main</code>:
</p>
<pre>addLnfMenuItems( <span class='string'>"main_lnf"</span>, getFrame( <span class='string'>"main"</span> ) );</pre>
<p>
This example would set the look and feel to the zeroth item in <code>s_lf</code> in frame <code>main</code>:
</p>
<pre>changeLnF( <span class='number'>0</span>, x_main );</pre>
<p>
You might for example get the index of the look and feel by showing the user a list of names in a dialog.
</p>
<p>
See also <a href='#initialiseLookAndFeel'><code>initialiseLookAndFeel</code></a>
</p>
</li>
<li>
<h4 id='ask'>
ask
</h4>
<p>
This method is a convenient wrapper around <code><span class='class'>JOptionPane</span>.showConfirmDialog</code> for yes/no questions.
</p>
<pre><span class='keyword'>if</span> ( <span class='highlight'>ask</span>(
someComponent,
<span class='string'>"Delete "</span> + fileName + <span class='string'>"?"</span>,
<span class='string'>"Confirm delete"</span>,
WARNING_MESSAGE ) )
<span class='comment'>// User said yes, so delete the file</span></pre>
</li>
<li>
<h4 id='beforeUIBuilt'>
beforeUIBuilt
</h4>
<p>
Override this method if you want something done before the UI is built.
Common examples are calling <a href='#runAfterUiBuilt'><code>runAfterUiBuilt</code></a> or <a href='#readWriteConfig'><code>readWriteConfig</code></a>:
</p>
<pre><span class='keyword'>@Override
protected void</span> beforeUIBuilt() {
<span class='highlight'>readWriteConfig</span>( somePath, config, VERSION );
<span class='highlight'>runAfterUiBuilt</span>( () -> {
<span class='comment'>// Do some init stuff...</span>
});
}</pre>
</li>
<li>
<h4 id='copyStringcopyImage'>
copyString/copyImage
</h4>
<p>
These methods are convenient ways to copy common data formats to the default system clipboard.
</p>
<p>
(see also: <a href='#getClipboardString'><code>getClipboardString</code></a>)
</p>
</li>
<li>
<h4 id='get'>
get
</h4>
<p>
This method is an alternative to <a href='#magic'>magic fields</a>.
It may be useful if you want to iterate over a number of similarly named components: you can construct the names and find the components with this method.
</p>
<p>
This method has friends, <code>getFrame</code>, <code>getMenu</code>, and so on.
They are all described in the <a href='#referringtocomponents'>Referring to components</a> section of this documentation.
</p>
</li>
<li>
<h4 id='getAll'>
getAll
</h4>
<p>
This method returns a map of names to <code>AppComponent</code>s.
The real purpose of this method is to make <a href='#configurator'>Configurator</a> work, but it might also be useful if you needed to find all named components in a window for some other reason.
</p>
</li>
<li>
<h4 id='getAppName'>
getAppName
</h4>
<p>
This is useful for filling in the app's name in dialogs.
It saves you hard coding the name.
</p>
<pre><span class='keyword'>if</span> ( ask( x_main, <span class='string'>"Close "</span> + <span class='highlight'>getAppName</span>() + <span class='string'>'?'</span> ) ) {
<span class='comment'>// close it</span>
}</pre>
</li>
<li>
<h4 id='getClipboardString'>
getClipboardString
</h4>
<p>
Gets the contents of the system clipboard as a string.
</p>
<p>
(see also: <a href='#copyStringcopyImage'><code>copyString/copyImage</code></a>)
</p>
</li>
<li>
<h4 id='getDialogNames'>
getDialogNames
</h4>
<p>
Gets the names of all the dialogs defined in the descriptor.
</p>
</li>
<li>
<h4 id='getFrameNames'>
getFrameNames
</h4>
<p>
Gets the names of all the frames defined in the descriptor.
</p>
</li>
<li>
<h4 id='getKeyDetailsgetKeyListeners'>
getKeyDetails/getKeyListeners
</h4>
<p>
These methods are useful for debugging when keyboard handling does not go as expected.
</p>
<pre><span class='keyword'>if</span> ( debugging ) {
log.debug( <span class='highlight'>getKeyDetails</span>( keyEvent ) );
log.debug( <span class='highlight'>getKeyListeners</span>( x_main_table ) );
}</pre>
</li>
<li>
<h4 id='getMethods'>
getMethods
</h4>
<p>
This might be useful if you need to find all your app's methods at run time (which Compositor certainly does).
</p>
</li>
<li>
<h4 id='handleEventQueueException'>
handleEventQueueException
</h4>
<p>
Override this if you want to handle an uncaught exception on the event handling thread.
The default implementation just writes an error to the log.
Here's an example of writing to system out instead.
</p>
<pre><span class='keyword'>protected void</span> <span class='highlight'>handleEventQueueException</span>( <span class='keyword'>final</span> <span class='class'>Throwable</span> t ) {
System.out.println( "Bad stuff: " + t );
}
</pre>
</li>
<li>
<h4 id='initialiseLookAndFeel'>
initialiseLookAndFeel
</h4>
<p>
Override this if you want to control the initial look and feel.
By default, Compositor uses the "native" look and feel.
Providing a no-op implementation should give you the Java "metal" L&F.
</p>
<p>
See also <a href='#changeLnF'><code>changeLnF</code></a>
</p>
</li>
<li>
<h4 id='invokeLater'>
invokeLater
</h4>
<p>
This posta an event to the event queue.
This is a good way to get UI updates to happen on the right thread.
It's also useful if you want to call a method after the current method has completed.
</p>
<p>
Here's an example of using it to pass command line arguments to a method on the event handling thread:
</p>
<pre><span class='keyword'>public static void</span> main( <span class='keyword'>final</span> <span class='class'>String</span>[] args ) {
<span class='keyword'>new</span> MyApp().<span class='highlight'>invokeLater</span>(
() -> commandLineHandler( args )
);
}
<span class='keyword'>public void</span> commandLineHandler( <span class='keyword'>final</span> <span class='class'>String</span>[] args ) {
<span class='comment'>// Handle command line args</span>
}</pre>
<p>
You can also invoke a method by name.
This means there's no compile time check that it will work, but it does allow you to decide at run time what should be called.
</p>
<pre><span class='comment'>// We could omit the third argument if cat and dog were instances of Animal</span>
<span class='comment'>// but we need them if they are instances of Cat and Dog</span>
<span class='highlight'>invokeLater</span>(
<span class='string'>"myMethod"</span>,
<span class='keyword'>new</span> <span class='class'>Object</span>[]{ cat, dog },
<span class='keyword'>new</span> <span class='class'>Class</span><?>[]{ Animal.class, Animal.class }
);
<span class='comment'>// Single arg convenience version</span>
<span class='highlight'>invokeLater</span>(
<span class='string'>"myMethod"</span>,
cat,
Animal.class
);</pre>
</li>
<li>
<h4 id='msgBox'>
msgBox
</h4>
<p>
These methods produce a message dialog (an alert).
They are a wrapper around <code><span class='class'>JOptionPane</span>.showMessageDialog</code>.
</p>
</li>
<li>
<h4 id='playSound'>
playSound
</h4>
<p>
This will try to play a sound.
The sound file is found by <code><a href='#resourceloader'>ResourceLoader</a></code>, so it can be a classpath resource or a file.
Some sound file formats don't work on some platforms.
</p>
</li>
<li>
<h4 id='readWriteConfig'>
readWriteConfig
</h4>
<p>
This is a simple way to ensure that a config file is immediately read, and also written every time the config properties are updated.
</p>
<p>
See the example under <a href='#beforeUIBuilt'><code>beforeUIBuilt</code></a>.
</p>
</li>
<li>
<h4 id='run'>
run
</h4>
<p>
Override this method if you want to change the default startup behaviour, which expects a single frame and displays it.
</p>
</li>
<li>
<h4 id='runAfterUiBuilt'>
runAfterUiBuilt
</h4>
<p>
If you need some initialisation to happen after the descriptor has been turned into UI, but before your app starts, call this method, passing it a <code class='class'>Runnable</code>.
A problem is that the first thing that Compositor does is to build the UI, so it's best to override <code>beforeUIBuilt</code> and call <code>runAfterUiBuilt</code> from there.
Calling it this way also ensures it runs on the <a href='#threads'>right thread</a>.
</p>
<p>
See the example under <a href='#beforeUIBuilt'><code>beforeUIBuilt</code></a>.
</p>
<p>
You can call <code>runAfterUiBuilt</code> as many times as necessary.
Don't rely on the sequence that the <code class='class'>Runnable</code>s are run.
</p>
</li>
<li>
<h4 id='showDialog'>
showDialog
</h4>
<p>
This will open a dialog.
The dialog will be validated, packed, and centred on the parent component of your choice, or the centre of the screen if there is no parent.
</p>
</li>
<li>
<h4 id='sizeCols'>
sizeCol/sizeCols/sizeColsAdjustment
</h4>
<p>
When you load a table, the column widths will probably not be what you want.
These methods fix that.
They work out the maximum width of the text displayed, and size the columns accordingly.
</p>
<pre><span class=comment>// When the dialog loads, adjust the table column width</span>
<span class=keyword>public void</span> myDialog__onShow() {
<span class=highlight>sizeCols</span>( <span class=string>"myDialog_myTable"</span> ); <span class=comment>// Also works if you pass a JTable object</span>
}</pre>
<p>
You can resize just one column.
This might be useful if you didn't automatically resize the colums, but you want the user to be able to make one column fit the contents.
</p>
<pre>// The user asked (somehow) to resize column at offset two</span>
<span class=highlight>sizeCol</span>( myDialog_myTable, 2 );</pre>
<p>
You can adjust the calculated width by a fixed amount per column with <code>sizeColsAdjustment</code>.
For example, the file icons in <a href='#ftree'>FTree</a> add to the width of the name column.
</p>
<pre><span class=keyword>@Override
protected int</span> <span class=highlight>sizeColsAdjustment</span>( <span class=keyword>final int</span> col ) {
<span class=keyword>return</span> col == 0 ? 19 : 3; <span class=comment>// Columns zero gets more extra space than the others</span>
}</pre>
<p>
These methods assume that the result of <code>toString</code> on the column data is a good measure of the actual width.
If your content is graphical rather than text, these methods won't help you.
</p>
</li>
<li>
<h4 id='snooze'>
snooze
</h4>
<p>
<code><span class=class>Thread</span>.sleep(...)</code> throws <code><span class=class>InterruptedException</span></code> but a lot of the time we don't care.
So <code><span class=highlight>snooze( <span class=number>99L</span> )</span>;</code> is a shortcut for
</p>
<pre><span class=keyword>try</span> {
<span class=class>Thread</span>.sleep( <span class=number>99L</span> );
} <span class=keyword>catch ( <span class=class>InterruptedException x ) {
<span class=comment>// ignored
}</pre>
</li>
<li>
<h4 id='writeStatus'>
writeStatus
</h4>
<p>
Your app can override this method to show unobtrusive messages to the user.
The canonical example is status bar text that the user can read, but can equally well ignore.
A <a href='#msgBox'><code>msgBox</code></a> that requires user interaction would not be such a good choice.
</p>
<p>
If you write components to be used in Compositor apps, you are encouraged to provide user feedback via <code>writeStatus</code>.
An app can pass <em>itself</em> (as a <code>StatusTarget</code>) to your component to achieve this.
</p>
</li>
</ul>
</li>
<li id='classesthatmighthelp'>
<h3>
Classes
</h3>
<p>
All of these are included in the Compositor jar.
They are listed in rough order of usefulness, but obviously that's subjective.
</p>
<ul class='classes'>
<li>
<h4 id='actiondelayer'>
ActionDelayer
</h4>
<p>
This kind of thing is sometimes called a "debouncer".
</p>
<p>
It can be helpful for grouping together user inputs.
For example, the <a href='#namebug'>NameBug</a> example waits for a pause in user input before it starts drawing.
Responding to each individual input would make the app slow to respond.
</p>
<p>
You pass the required action as a <code class='class'>Runnable</code> to the ActionDelayer, but it waits for a specified time until it executes.
If another action arrives within that time, the previous one is discarded.
So only the last one of a series is acted upon.
</p>
<p>
It's up to you to set a suitable delay, and to send suitable actions to the delayer.
</p>
<p>
The action is taken on another thread, so if your action will update the UI, consider the usual <a href='#threads'>threading issues</a>.
You should probably use <a href='#invokeLater'><code>invokeLater</code></a>.
</p>
<p>
In this example, frame <code>main</code> contains <code>list</code>.
</p>
<pre><span class='keyword'>private</span> ActionDelayer m_selectDelayer =
<span class='keyword'>new</span> ActionDelayer( <span class='string'>"selectionDelayer"</span>, <span class='number'>500</span> );
<span class='keyword'>public void</span> main_list_onSelect() {
m_selectDelayer.<span class='highlight'>delay</span>(
() -> invokeLater(
() -> delayedListSelect()
)
);
}
<span class='keyword'>private void</span> delayedListSelect() {
<span class='comment'>// Handle list selection here
// Only called when no list selection
// in the last half second</span>
}</pre>
</li>
<li>
<h4 id='resourceloader'>
ResourceLoader
</h4>
<p>
This class finds resources such as images and text files from the class path or from the file system.
It also can have a simple attempt at guessing a file type.
</p>
<pre><span class='keyword'>switch</span>( ResourceLoader.guessFileType( filePath ) ) {
<span class='keyword'>case</span> IMAGE:
<span class='keyword'>final</span> <span class='class'>Image</span> image = <span class='highlight'>ResourceLoader.getImage</span>( filePath );
<span class='comment'>// Do something with image...</span>
<span class='keyword'>break</span>;
<span class='keyword'>case</span> HTML:
<span class='keyword'>final</span> <span class='class'>String</span> content = <span class='highlight'>ResourceLoader.readUTF8File</span>( filePath );
<span class='comment'>// Do something with HTML...</span>
<span class='keyword'>break</span>;
<span class='comment'>// etc...</span>
}</pre>
<p>
Resources are found by name, first by looking on the class path (or more strictly, wherever the class loader looks, but that's almost always the same thing).
If nothing was found, then the requested name is used as a file path.
</p>
</li>
<li>
<h4 id='filetree'>
FileTree
</h4>
<p>
This represents the file system as a tree component.
</p>
<p>
Declare it in your descriptor something like this:
</p>
<pre><span class="marker"><</span><span class="element">components</span><span class="marker">></span>
<span class="marker"><</span><span class="element">component</span>
<span class="attrib">name</span>=<span class="string">'<span class='highlight'>c:fileTree</span>'</span>
<span class="attrib">generator</span>=<span class="string">'net.sf.compositor.FileTreeGenerator'</span>
/<span class="marker">></span>
<span class="marker"><</span>/<span class="element">components</span>></pre>
<p>
Then use it something like this:
</p>
<pre><span class="marker"><</span><span class="element">scrollpane</span><span class="marker">></span>
<span class="marker"><</span><span class="element highlight">c:fileTree</span>
<span class="attrib">name</span>=<span class="string">'tree'</span>
<span class="attrib">showHiddenFiles</span>=<span class="string">'false'</span>
/<span class="marker">></span>
<span class="marker"><</span>/<span class="element">scrollpane</span><span class="marker">></span></pre>
</li>
<li>
<h4 id='fileops'>
FileOps
</h4>
<p>
This class gives a simple API for file system operations: <code>copy</code>, <code>move</code>, <code>rename</code>, <code>mkdir</code> and <code>delete</code>.
</p>
<p>
If you use these, <em>please write a good set of tests</em>.
Successful file operations are your responsibility, not Compositors!
</p>
</li>
<li>
<h4 id='selectablelabel'>
SelectableLabel
</h4>
<p>
Displaying text in a <code class='class'>JLabel</code> doesn't let the user select or copy the text.
This class fixes that by extending <code class='class'>JTextField</code> and disabling editing.
</p>
<p>
Declare it in your descriptor something like this:
</p>
<pre><span class="marker"><</span><span class="element">components</span><span class="marker">></span>
<span class="marker"><</span><span class="element">component</span>
<span class="attrib">name</span>=<span class="string">'c:selectablelabel'</span>
<span class="attrib">generator</span>=<span class="string">'net.sf.compositor.TextFieldGenerator'</span>
<span class="attrib">class</span>=<span class="string">'net.sf.compositor.util.SelectableLabel'</span>
/<span class="marker">></span>
<span class="marker"><</span>/<span class="element">components</span><span class="marker">></span></pre>
<p>
Then use it something like this:
</p>
<pre><span class="marker"><</span><span class="element">c:selectablelabel</span>
<span class="attrib">name</span>=<span class="string">'myLabel'</span>
<span class="attrib">cols</span>=<span class="string">'15'</span><span class="marker">></span>Initial text<span class="marker"><</span>/<span class="element">c:selectablelabel</span><span class="marker">></span></pre>
<p>
In most look and feel implementations, this class renders like <code class='class'>JLabel</code>, but on some it has a different colour background and/or a border.
That probably counts as a bug...
</p>
</li>
<li>
<h4 id='config'>
Config
</h4>
<p>
This class represents a configuration file.
It extends <code class='class'>Properties</code> with convenience methods for getting integers, boolean values, and so on, and with indexed properties.
Reading and writing files with this class will preserve the original sequence of properties, and preserve comments.
This means hand editing of config files can be less painful.
</p>
<p>
Here's a way to set one up with some defaults, and make sure it's read and written at the right time.
</p>
<pre><span class="keyword">private static final</span> MyAppConfig <span class='highlight'>s_config = new MyAppConfig</span>();
<span class="keyword">@Override
protected void</span> <span class='highlight'>beforeUIBuilt</span>() {
<span class='highlight'>readWriteConfig</span>(
Env.USER_HOME + Env.FILE_SEP + <span class="string">"myapp.properties"</span>,
<span class='highlight'>s_config</span>,
VERSION
);
}
<span class="keyword">private static class</span> MyAppConfig
<span class="keyword">extends</span> <span class="class">Config</span> {
<span class="keyword">private static final</span> <span class="class">String</span> SOME_PROPERTY_NAME = <span class="string">"somePropertyName"</span>;
<span class="comment">// etc.</span>
<span class="keyword">private</span> MyAppConfig() {
<span class="keyword">super</span>(
<span class="keyword">new</span> Config() {{
<span class="comment">// Defaults</span>
setIntProperty( SOME_PROPERTY_NAME, <span class="string">"SomeValue"</span> );
<span class="comment">// etc.</span>
}}
);
}
}</pre>
</li>
<li>
<h4 id='formats'>
Formats
</h4>
<p>
This class formats things in human-readable ways.
You can format:
</p>
<ul>
<li>
a byte count as kb, Mb, etc. (traditional 1024 style, not ISO 1000 style)
</li>
<li>
the time elapsed between two instants
</li>
<li>
integers as hex
</li>
<li>
integers as fixed width
</li>
</ul>
<p>
Some of this can nowadays be done with <code><span class='class'>String</span>.format</code>.
</p>
</li>
<li>
<h4 id='env'>
Env
</h4>
<p>
This is a large set of values that represent the runtime environment.
Many of them are system properties, but I suggest that...
</p>
<pre>Env.NL</pre>
<p>
...is better than...
</p>
<pre><span class='class'>System</span>.getProperty( <span class='string'>"line.separator"</span> )</pre>
<p>
There is also a method <code>javaVersionAtLeast</code> that allows you to tailor code to the JVM on which it's running.
</p>
</li>
<li>
<h4 id='info'>
Info
</h4>
<p>
This is a short hand way of constructing an information dialog in code.
An example will help.
</p>
<pre><span class="keyword">public void</span> doAbout() {
<span class='highlight'><span class="keyword">new</span> Info.Builder</span>(
getFrame( <span class="string">"main"</span> ),
<span class="string">"About "</span> + getAppName(),
<span class="keyword">new</span> <span class="class">String</span>[][] {
{ <span class="string">"This app"</span>, getAppName(), Info.BOLD, },
{ <span class="string">"Explanation"</span>, <span class="string">"Does some handy thing"</span>, },
{ Info.SPACER, },
{ <span class="string">""</span>, <span class="string">"Some useful information might go here"</span>, Info.NO_COLON, },
{ <span class="string">""</span>, <span class="string">"if you want to say stuff to users..."</span>, Info.NO_COLON, },
{ Info.SPACER, },
{ <span class="string">"Docs"</span>, <span class="string">"Link text"</span>, Info.LINK, docUrl, },
}
)
<span class="comment">// Optional extras:</span>
.setStatusMsg( <span class="string">"Showing \"About\" box..."</span>)
.setStatusTarget( <span class="keyword">this</span> )
.setExtraInfo( mapToShowOnDialog )
.setEvenMoreInfo( getSysProps() ) <span class="comment">// Displays behind "more" button</span>
.setIcon( ResourceLoader.getIcon( <span class="string">"help32.png"</span> ) )
<span class="comment">// Now we can show the dialog</span>
.show();
}</pre>
<p>
The resulting dialog would look something like this:
</p>
<img src='core/src/main/resources/infodialog.png' alt='[dialog image]' title=''>
<p>
Obviously you can miss out any optional elements that you don't want.
That's why they're optional.
</p>
<p>
Multiple constants should be OK: <code>Info.BOLD, Info.NO_COLON</code> works.
</p>
<p>
The example will show all system properties when the user presses "More...".
This might be useful information for you if a user has an issue.
</p>
</li>
<li>
<h4 id='log'>
Log
</h4>
<p>
The logger used by Compositor is simple.
It's home-grown because it pre-dates other logging options.
An instance of this logger, <code>s_log</code>, is available in every Compositor app.
</p>
<p>
But if you want to use another log framework in your app, you can persuade this logger to delegate to it.
An example is <code>LogApiJdk</code> which uses the built-in Java logging system.
To use this, first call <code>s_log.setApiClass(...)</code>, then <code>s_log.setDestination(Log.TO_API)</code>.
</p>
</li>
<li>
<h4 id='nativeeditor'>
NativeEditor
</h4>
<p>
This class allows you to open a file in a native text editor.
The algorithm used is pretty simplistic, and only understands Windows, OS X, and Linux distributions that have <code>xdg</code>.
</p>
<p>
Here's an example of how to use it to implement an action:
</p>
<pre><span class="keyword">public void</span> doEditor() {
<span class="keyword">try</span> {
<span class='highlight'>NativeEditor.open</span>( <span class="keyword">new</span> <span class="class">File</span>( someFileName ) );
} <span class="keyword">catch</span> ( <span class="keyword">final</span> <span class="class">IOException</span> x ) {
msgBox( x_main, <span class="string">"Oops: "</span> + x );
}
}</pre>
<p>
See also <a href='#nativebrowser'><code>NativeBrowser</code></a>
</p>
</li>
<li>
<h4 id='nativebrowser'>
NativeBrowser
</h4>
<p>
This class allows you to open a file in a native web browser.
The algorithm used is pretty simplistic, and only understands Windows, OS X, and Linux distributions that have <code>xdg</code>.
</p>
<pre><span class="keyword">try</span> {
<span class='highlight'>NativeBrowser.open</span>( someUrl );
} <span class="keyword">catch</span> ( <span class="keyword">final</span> <span class="class">IOException</span> x ) {
msgBox( x_main, <span class="string">"Could not open URL:"</span> + Env.NL + x.getMessage() );
}</pre>
<p>
See also <a href='#nativeeditor'><code>NativeEditor</code></a>
</p>
</li>
<li>
<h4 id='scriptrunner'>
ScriptRunner
</h4>
<p>
This class is a simple interface to running a script in a language such as JavaScript.
</p>
<p>
An example will help.
</p>
<pre><span class="keyword">new</span> <span class="highlight">ScriptRunner</span>
(
<span class="string">"<span class="highlight">data</span>.doSomeEdit(); <span class="highlight">ui</span>.say('Edit done')"</span>,
<span class="string">"JavaScript"</span>,
<span class="keyword">new</span> <span class="class">HashMap</span> < <span class="class">String</span>, <span class="class">Object</span> > () {{
put( <span class="string highlight">"data"</span>, <span class="keyword">new</span> DataWrapper() );
put( <span class="string highlight">"ui"</span>, <span class="keyword">new</span> UIWrapper() );
}},
myFrame,
myMessageTitle
)
.<span class="highlight">run</span> ();</pre>
<ul>
<li>
The actual script would probably be provided by the user.
</li>
<li>
The languages available depend on the JVM.
There may be none!
</li>
<li>
The objects exposed to the script should probably be wrappers around actual UI elements or other objects in your app.
This provides a sandbox for the script, giving it only access to functionality you intend.
</li>
<li>
The script is executed on a separate thread.
Any UI updates should be done by <code>invokeLater</code> on the event handling thread.
Exposing only wrapper objects allows you to do this in the wrappers.
</li>
<li>
A <code>msg</code> object is automatically exposed to the script.
The methods are
<ul>
<li><code>msg.alert(message)</code> - displays a message popup</li>
<li><code>msg.confirm(question)</code> - true if user says yes</li>
<li><code>msg.prompt(question)</code> - returns the user's answer</li>
<li><code>msg.choose(map)</code> - keys in map are displayed for the user to choose, and the mapped value is returned</li>
</ul>
</li>
</ul>
</li>
<li>
<h4 id='rotatedlabel'>
RotatedLabel
</h4>
<p>
This class is a label that displays text reading up or down, so you could lean your head over to see it the usual way up.
The <a href='#sidetabs'>SideTabs</a> example uses this.
</p>
<p>
Declare it in your descriptor something like this:
</p>
<pre><span class="marker"><</span><span class="element">components</span><span class="marker">></span>
<span class="marker"><</span><span class="element">component</span>
<span class="attrib">name</span>=<span class="string">'c:rotatedlabel'</span>
<span class="attrib">generator</span>=<span class="string">'net.sf.compositor.RotatedLabelGenerator'</span>
/<span class="marker">></span>
<span class="marker"><</span>/<span class="element">components</span><span class="marker">></span></pre>
<p>
Then use it something like this:
</p>
<pre><span class="marker"><</span><span class="element">c:rotatedlabel</span> <span class="attrib">direction</span>=<span class="string">'up'</span><span class="marker">></span>Label goes upwards!<span class="marker"><</span>/<span class="element">c:rotatedlabel</span><span class="marker">></span></pre>
</li>
<li>
<h4 id='propertiesignorecase'>
PropertiesIgnoreCase
</h4>
<p>
This class represents a property map where the case of the keys is unimportant.
An example where this is useful is HTTP headers.
</p>
<p>
This class relies on <code><span class='class'>String</span>.toLowerCase()</code> which uses the default locale.
</p>
</li>
<li>
<h4 id='throttler'>
Throttler
</h4>
<p>
A throttler prevents too many threads processing a section of code at once.
I wrote this for a case where image processing operations that required lots of memory where being run in parallel.
Beyond a certain number of threads I found that performance dropped dramatically because useful processing was replaced by disk thrashing.
Throttling the threads so that only a few could run in parallel improved the speed from dozens of minutes to a few seconds.
</p>
<p>
You make a <code>Throttler</code>, specifying how many threads are allowed in.
Then you pass <code>Throttleable</code> instances to it that execute the throttled code.
If too many threads arrive, they queue up.
</p>
</li>
<li>
<h4 id='mapmaker'>
MapMaker
</h4>
<p>
This class will turn a semi-colon separated string into a map.
It is used by Compositor to read CSS-style attributes.
</p>
</li>
<li>
<h4 id='imagecomparer'>
ImageComparer
</h4>
<p>
This class compares images.
It's useful in tests.
</p>
</li>
<li>
<h4 id='stackprobe'>
StackProbe
</h4>
<p>
To find the current class you can say <code><span class='keyword'>this</span>.getClass()</code>.
But in a static method there is no <code class='keyword'>this</code>.
Instead you can say <code>StackProbe.getMyClass()</code>.
</p>
<p>
Similarly, <code>StackProbe.getMyClassName()</code>.
</p>
</li>
<li>
<h4 id='unwinder'>
Unwinder
</h4>
<p>
Finding the root cause of a chain of exceptions may be useful.
For example, <code class='class'>InvocationTargetException</code> will always have some other cause.
<code>Unwinder.unwind(x)</code> finds the original exception wrapped by <var>x</var>.
</p>
</li>
<li>
<h4 id='mutint'>
MutInt
</h4>
<p>
This is a wrapper around an integer value.
If you increment an <code class='keyword'>int</code> parameter inside a method, the caller doesn't see the change (which is usually a good thing).
But if you pass a <code>MutInt</code> and call <code>myMutInt.value++</code> then the caller will see that change.
</p>
<p>
This class makes functional programmers weep.
</p>
</li>
<li>
<h4 id='padimagefilter'>
PadImageFilter
</h4>
<p>
This class adds empty space to an image to make it larger.
It's used by Compositor to make sure that mouse cursor images are big enough.
</p>
</li>
<li>
<h4 id='exifreader'>
ExifReader
</h4>
<p>
Most JPG images include lots of data about how the image was created.
This class extracts that information in a usable form.
</p>
</li>
<li>
<h4 id='threadPoolandimmortalthread'>
ThreadPool/ImmortalThread
</h4>
<p>
This is probably redundant nowadays.
You should probably use NIO thread pooling instead.
</p>
</li>
<!--
<li>
<h4 id='smokedoc'>
SmokeDoc
</h4>
<p>
I like Javadoc but I always thought that the presentation was ugly.
This is a doclet that I think makes nicer looking documentation.
It includes a few different colour schemes.
</p>
</li>
-->
</ul>
</li>
</ul>
</li>
<li id='i18n'>
<h2>
Internationalisation
</h2>
<p>
It should be easy (or at least possible) to have your UI displayed in the language and conventions of the user.
Sadly it isn't (yet).
</p>
</li>
<li id='exampleapps'>
<h2>
Example apps
</h2>
<p>
There are some example apps that, compared to the simple stuff above, are closer to something you might actually write (but some are more finished than others).
</p>
<p>
To run the examples, you need the source distribution of Compositor.
First build, then:
</p>
<ul>
<li>
Windows:
<pre>cd <pathToCompositor>
examples</pre>
</li>
<li>
Everyone else:
<pre>cd <pathToCompositor>
./examples.sh</pre>
</li>
</ul>
<ul>
<li id='examples'>
<h3>
Examples
</h3>
<ol type='i'>
<li id='minimal'>
<h4>
Minimal
</h4>
<p>
This is an example of how little you need do to get a working UI.
</p>
<p>
Starting with something minimal is good.
Don't try to get everything working at the start.
</p>
</li>
<li id='simpleedit'>
<h4>
SimpleEdit
</h4>
<p>
This is a text file editor, the "hello world" of GUI generators.
You can open, edit and save text files (but surely you have a better text editor than this?)
SimpleEdit uses the default encoding, so you may have difficulty with files that use other encodings, including <strong>loss of data</strong>.
</p>
<p>
Have a look at the dialogs (<samp>File</samp>, <samp>Dialogs</samp> on the menu).
They don't do anything useful but they do show a lot of different components and how to use them.
Try the view menu too.
</p>
<p>
This example also shows the use of a custom component, and it allows drag and drop as an alternative to its file open dialog.
</p>
</li>
<li id='multiedit'>
<h4>
MultiEdit
</h4>
<p>
This multi-file editor demonstrates how to do MDI, and how to use <a href='#clones'>clones</a>.
</p>
</li>
<li id='spsh'>
<h4>
Spsh
</h4>
<p>
This is a cut-down spreadsheet.
Even its name is short for "spreadsheet".
It works on tab-separated files, 10 columns by 100 rows, and you can enter formulae in a slightly bizarre format chosen only for ease of implementation.
See the help for more info.
</p>
<p>
You're not really meant to <em>use</em> this spreadsheet.
Surely you have a better one?
</p>
<p>
This sample uses a table as its main UI component.
It extends <code>FileApp</code> and separates UI handling and data handling into separate classes.
</p>
</li>
<li id='dragdrop1'>
<h4>
DragDrop1
</h4>
<p>
This is a simple example of dragging components from one panel to another.
It <em>doesn't</em> use Compositor's built-in drag and drop handling, so it may be useful if you want an example of how to handle drag and drop yourself.
</p>
</li>
<li id='dragdrop2'>
<h4>
DragDrop2
</h4>
<p>
This is a clone of DragDrop1, but using Compositor's <a href='#draggingcomponents'>built-in drag and drop handling</a>.
Much easier!
</p>
<p>
Doing it this way gives you a bit less control, though.
Any draggable widget can be dropped on any drop target.
</p>
</li>
<li id='dragdrop3'>
<h4>
DragDrop3
</h4>
<p>
This examples shows how to handle drags from other apps.
Try dragging some text from your word processor, or some files from your file manager.
</p>
<p>
This app doesn't do anything useful with things that are dragged onto it, but it shows you how you can find out what's being dragged.
In a real app you would want to give the user more feedback.
If they drag something that your app doesn't handle, don't accept the drag, and the operating system should give the user feedback with the appropriate mouse cursor.
</p>
</li>
<li id='sidetabs'>
<h4>
SideTabs
</h4>
<p>
This is an example of how to reproduce a feature found in many <abbr title='Integrated development environment'>IDE</abbr>s: collapsing side tabs.
Try clicking various tabs, then click the currently selected one again.
</p>
<p>
This example shows how to use a wild card method for events on several components.
Handling a click on any of the tabs on the "west" side is very similar, so instead of <code>main_westHomeTab_onClick</code>, <code>main_westFilesTab_onClick</code>, etc. all of those clicks are handled by <code>main_west$Tab_onClick</code>.
</p>
</li>
<li id='xibbon'>
<h4>
Xibbon
</h4>
<p>
I was looking at the "ribbon" that replaces menus and toolbars in MS Office.
Could something similar be done with Compositor?
Well, the ribbon looks like some tabs, so I tried that, and it kind of works.
Each tab contains several groups of controls, the end result looks somewhat similar to the ribbon.
</p>
</li>
<li id='xibbonmacro'>
<h4>
XibbonMacro
</h4>
<p>
Generating a ribbon-style UI involves a lot of nested panels, which makes it difficult to understand.
</p>
<pre><span class="marker"><</span><span class="element">tabbedpane</span> <span class="atrib">borderLayout</span><span class="marker">=</span><span class="string">'north'</span><span class="marker">></span>
<span class="marker"><</span><span class="element">panel</span> <span class="attrib">tabText</span><span class="marker">=</span><span class="string">'Home'</span> <span class="attrib">layout</span><span class="marker">=</span><span class="string">'boxLayoutX'</span><span class="marker">></span>
<span class="marker"><</span><span class="element">panel</span> <span class="attrib">border</span><span class="marker">=</span><span class="string">'etched'</span> <span class="attrib">title</span><span class="marker">=</span><span class="string">'Clipboard'</span> <span class="attrib">padding</span><span class="marker">=</span><span class="string">'2'</span><span class="marker">></span>
<span class="marker"><</span><span class="element">panel</span> <span class="attrib">layout</span><span class="marker">=</span><span class="string">'boxLayoutY'</span><span class="marker">></span>
<span class="comment"><!-- Widgets go here --></span></pre>
<p>
Using a macro in the descriptor allows a more readable style.
</p>
<pre><span class='marker'><</span><span class='element'>include </span><span class='attrib'>file</span><span class='marker'>=</span><span class='string'>'ribbon.inc'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>r:tab</span> <span class='attrib'>label</span><span class='marker'>=</span><span class='string'>'Home'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>r:section </span><span class='attrib'>label</span><span class='marker'>=</span><span class='string'>'Clipboard' </span><span class='attrib'>layout</span><span class='marker'>=</span><span class='string'>'flowLayout' </span><span class='attrib'>padding</span><span class='marker'>=</span><span class='string'>'2'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>r:block </span><span class='attrib'>layout</span><span class='marker'>=</span><span class='string'>'boxLayoutY' </span><span class='attrib'>align</span><span class='marker'>=</span><span class='string'>''</span><span class='marker'>></span>
<span class="comment"><!-- Widgets go here --></span></pre>
</li>
<li id='calx'>
<h4>
Calx
</h4>
<p>
I wanted to see if I could make a UI like the Windows calculator, just because of its complexity.
It's reasonably similar...
</p>
<p>
...at least it was on Windows XP.
</p>
<p>
It doesn't work at all.
You can't calculate with it.
</p>
</li>
<li id='decoder'>
<h4>
Decoder
</h4>
<p>
Notice how the two sides of the UI stay the same size as you resize the window, and how you can cut and paste with the keyboard even when the buttons have focus.
</p>
<p>
This example does something mildly useful.
What do the following mean?
Decoder can tell you for these and others.
</p>
<ul>
<li>
URL encoding: <tt>%43%61%74</tt>
</li>
<li>
HTML entities: <tt>&#67;&#97;&#116;</tt>
</li>
<li>
Base64: <tt>Q2F0</tt>
</li>
</ul>
</li>
<li id='floatywidget'>
<h4>
FloatyWidget
</h4>
<p>
This shows how to use <a href='#refLayeredpane'><code class='element'>layeredpane</code></a> to put one widget on top of another.
The tool bar has a clickable icon on top of a text field.
</p>
</li>
<li id='fullscreen'>
<h4>
FullScreen
</h4>
<p>
This is an example of how to make an app go to full screen.
</p>
</li>
<li id='gluetest'>
<h4>
GlueTest
</h4>
<p>
This example demonstrates how to use <a href='#refGlue'>glue</a> and empty border layout panels to control where space goes when a window is re-sized.
</p>
</li>
<li id='jetris'>
<h4>
Jetris
</h4>
<p>
This is a version of a well-known game, just for fun.
It uses <a href='#clones'>clones</a>, <a href='#refGrid'>grid</a> and <a href='#refGlasspane'>glasspane</a> for layout.
</p>
</li>
<li id='laztik'>
<h4>
Laztik
</h4>
<p>
This is a bit of fun with non-modal dialogs.
They move as if on elastic.
This is the only thing I've written that impressed my 13 year old son.
</p>
</li>
<li id='pets'>
<h4>
Pets
</h4>
<p>
Asks you for the name of your pets.
</p>
<p>
This shows how to use <a href='#includemacros'><code class='element'>include</code> macros</a> and <a href='#wildcards'>method wild cards</a>.
</p>
</li>
<li id='ratedate'>
<h4>
RateDate
</h4>
<p>
You can rate whatever you like against dates.
</p>
<p>
This is a simple example of extending <a href='#filebasedapps'><code>FileApp</code></a>.
</p>
</li>
<li id='systemcolour'>
<h4>
SystemColour
</h4>
<p>
Shows the colours currently used for all the "system" colour definitions.
</p>
</li>
<li id='xide'>
<h4>
Xide
</h4>
<p>
This is a mini <abbr title='Integrated development environment'>IDE</abbr> for building Compositor apps.
It doesn't really work (yet) but you can use it to browse the structure of Compositor app descriptors.
</p>
</li>
</ol>
</li>
<li>
<h3 id='apps'>
Apps
</h3>
<p>
There are some more fully worked applications.
They're not so helpful if you're learning how to use Compositor, but they important because writing these drives improvements to Compositor.
</p>
<p>
Some of them are also useful!
</p>
<ol type='i'>
<li id='bupdate'>
<h4>
Bupdate
</h4>
<p>
You copied files somewhere as a backup, then you changed something. Bupdate can update the backup.
</p>
</li>
<li id='dataurimaker'>
<h4>
DataUriMaker
</h4>
<p>
Find a file (or drop one from elsewhere), select some options, and copy a data URI that you can use in a web page.
</p>
</li>
<li id='dismatch'>
<h4>
Dismatch
</h4>
<p>
This app searches for matching files, including simple image comparison, so that you can delete duplicates.
</p>
</li>
<li id='dixtionary'>
<h4>
Dixtionary
</h4>
<p>
This example lets you look up definitions with <a href='http://www.dict.org/rfc2229.txt'>the DICT protocol</a>
</p>
<p>
The default server, <code>dict.org</code>, also includes CIA factbook info on countries, translations, bible info, personal names and US gazeteers.
I have used this for helping with kids' homework: "What's the Spanish for... ?"
</p>
</li>
<li id='ftree'>
<h4>
FTree
</h4>
<p>
The Windows Explorer used to be quite good, but by Windows 7 it annoyed me so much that I decided to write my own file manager.
This shows:
</p>
<ul>
<li>
how to use <a href='#fileops'><code>FileOps</code></a> to manipulate the file system
</li>
<li>
how to use a <a href='#filetree'><code>FileTree</code></a> to display a directory structure
</li>
<li>
how to use <a href='#actiondelayer'><code>ActionDelayer</code></a> to allow multiple user inputs before reacting to them (sometimes known as a <q>debouncer</q>)
</li>
<li>
how to use <code>Configurator</code> with a settings dialog
</li>
<li>
how to use <code>FileGrid</code> to display files (the "grid" view with image thumbnails, not the "detail" view which is a table)
</li>
<li>
how to use <code>Roller</code>, an alternative to tabs for switching between components
</li>
<li>
how to use <a href='#delegates'>delegates</a> inside <a href='#clones'>clones</a>
</li>
</ul>
<p>
FTree mostly works, but there are some things to consider.
</p>
<ul>
<li>
Deleted files are really deleted.
They're not in the Recycle Bin or the Trash or whatever your computer calls that.
FTree does warn you about this when you delete.
</li>
<li>
<q>Uh-oh - did I drag that file to the right place?</q>
There's no undo.
Some file managers realise that you might make a mistake, and let you undo changes.
FTree's approach is to always ask you if you <em>really</em> want to move/copy/delete.
</li>
</ul>
</li>
<li id='fodaloda'>
<h4>
FodaLoda
</h4>
<p>
My camera stopped connecting to my computer, so I had to put the memory card in and copy the photos.
Boring repetitive actions should be automated.
FodaLoda does that.
</p>
<p>
It looks at some path (the memory card), finds directories not previously copied, and copies the photos.
Simple.
</p>
</li>
<li id='fontsampler'>
<h4>
FontSampler
</h4>
<p>
This is a quick hack that shows samples of all the available fonts.
</p>
<p>
The fonts are the ones that your JVM thinks are available, so you should get a few cross-platform ones with generic names plus whatever is installed on your platform.
</p>
</li>
<li id='jemi'>
<h4>
Jemi
</h4>
<p>
I did a client for the Gemini protocol, which is somewhere in between the web and Gopher.
</p>
</li>
<li id='namebug'>
<h4>
NameBug
</h4>
<p>
Try entering your name and choosing a script font (one that looks like old-fashioned handwriting).
You may or may not get something bug-like.
See the About box for the origin of this app.
</p>
<p>
Anyone who enjoyed looking up rude words in the dictionary should try putting them into NameBug.
Not that I've done that myself...
</p>
</li>
<li id='pixort'>
<h4>
Pixort
</h4>
<p>
Putting images in order of preference involves a sort algorithm where comparisons are made by asking the user.
This is an attempt at that.
</p>
</li>
<li id='quircus'>
<h4>
Quircus
</h4>
<p>
Qu<em><strong>e</strong></em>rcus is the Latin name for an oak tree.
Qu<em><strong>irc</strong></em>us is a little IRC client.
</p>
<p>
I used IRC for a long time via a browser's built-in client.
I thought I'd have a go at writing a client.
You can connect to only one channel at once.
</p>
<p>
This is an example of using scripting.
</p>
</li>
<li id='retest'>
<h4>
RETest
</h4>
<p>
Tests regular expressions.
The RE dialect is the one supported by the Java <code class='class'>Pattern</code> class, and matching options are the ones provided by <code class='class'>Matcher</code>.
</p>
</li>
<li id='showgc'>
<h4>
ShowGC
</h4>
<p>
Draws a graph from a Java garbage collection log.
It's like <code>gcviewer</code> but less ugly.
It uses JFreeChart to draw the graph.
</p>
</li>
<li id='snowflake'>
<h4>
Snowflake
</h4>
<p>
I wanted to be able to draw patterns with rotational symmetry like <a href='http://www.amaziograph.com/'>Amaziograph</a> does, but that's for an iPad, and I don't have one.
So I thought "How hard can it be?"
Answer: it filled in spare moments over one Christmas break.
</p>
<p>
You might also like <a href='http://www.drawerings.com/draw'>Drawerings</a> which is similar.
</p>
</li>
<li id='tilex'>
<h4>
Tilex
</h4>
<p>
This turns images into seamless tiles that can be used on your desktop.
</p>
<p>
This example may be useful, or at least entertaining.
</p>
<p>
Like <a href='#spsh'>Spsh</a>, this example extends <code>FileApp</code> and separates UI handling and data handling into separate classes.
This example also allows drag and drop as an alternative to its file open dialog.
</p>
</li>
<li id='timeclock'>
<h4>
TimeClock
</h4>
<p>
Lets you clock in and out of work (or whatever else) to record your hours.
</p>
</li>
<li id='wwx'>
<h4>
WWX
</h4>
<p>
How hard can it be to write a web browser?
Pretty hard, unless you rely on <code class='class'>HTMLEditorKit</code> to do the rendering.
Sadly, easiness comes with a price: the rendering is pretty broken for almost all web sites.
</p>
</li>
</ol>
</li>
<li>
<h3 id='playarea'>
The Play Area
</h3>
<p>
The <a href='#exampleapps'><code>Examples</code></a> app will run any Compositor app in the <code>examples</code> directory, but also in the <code>playarea</code> directory.
This is a good place to try out your own apps.
Use the radio buttons to navigate to the playarea.
</p>
<p>
The Compositor build will compile anything in the <code>playarea</code> directory.
</p>
<p>
If your play area app needs any additional jar files, add them to the <code>examples.properties</code> file in the play area.
Example syntax is:
</p>
<pre>additional.classpath.MyAppName.1 = somePath/someLibrary.jar
additional.classpath.MyAppName.2 = someOtherPath/someOtherLibrary.jar</pre>
</li>
</ul>
</li>
<li id='otherlanguages'>
<h2>
Other languages
</h2>
<p>
If you're not writing code in Java, but your language runs in the JVM, you can probably still use Compositor to build your UI.
</p>
<dl>
<dt id='groovy'>Groovy</dt>
<dd>
<p>
A Groovy class is so close to a Java class that this pretty much just works.
See <code>examples/nonjava/groovy/RunGrapp.groovy</code> for an example.
</p>
<p>
Well done to the people who designed Groovy: ten out of ten for interoperability.
</p>
</dd>
<dt id='scala'>Scala</dt>
<dd>
<p>
Make a class that extends AppScala and an object with a <code>main</code> that instantiates your class.
See <code>examples/nonjava/scala/RunScalapp.scala</code> for an example.
</p>
<p>
Well done to the people who designed Scala: nine out of ten for interoperability.
</p>
</dd>
<dt id='kotlin'>Kotlin</dt>
<dd>
<p>
Make a class that extends AppKotlin and a <code>main</code> that instantiates your class.
See <code>examples/nonjava/kotlin</code> for examples.
</p>
<p>
Well done to the people who designed Kotlin: nine out of ten for interoperability.
</p>
</dd>
<dt id='jython'>Jython</dt>
<dd>
<p>
Make a class that extends AppJython and instantiate it.
BUT, so far you can make the UI, but I haven't been able to connect back to action methods or event handlers.
</p>
<p>
So far, the designers of Jython get three out of ten for interoperability.
</p>
</dd>
<dt id='clojure'>Clojure</dt>
<dd>
<p>
It looks as if you can use <a href='http://kotka.de/blog/2010/02/gen-class_how_it_works_and_how_to_use_it.html'><code>:gen-class</code></a> to extend a Java class, but I haven't figured out how to make it work.
</p>
<p>
Zero out of ten for me understanding Lisp in general and Clojure in particular.
</p>
</dd>
<dt id='jruby'>JRuby</dt>
<dd>
<p>
I haven't tried this one yet.
</p>
<p>
Zero out of ten for me thinking about which JVM languages might be popular.
</p>
</dd>
<dt id='javascript'>JavaScript</dt>
<dd>
<p>
Since support for JavaScript is built in to Java nowadays, this should be possible.
</p>
<p>
You can use scripting inside a Compositor app.
<a href='#ftree'>FTree</a> does this.
But it should be possible to write the whole app as a script.
</p>
<p>
Zero out of ten for me again.
</p>
</dd>
<dt id='anythingelse'>Anything else</dt>
<dd>
<p>
You need to be able to extend a Java class, and to be able to find by reflection methods defined in your subclass.
You may also need to implement in Java an <code>AppHooks</code> class and a subclass of <code>AppMac</code> to connect everything up correctly.
It's pretty simple: look at <code>AppScala</code> for an example.
</p>
</dd>
</dl>
</li>
<li id='reference'>
<h2>
Reference material
</h2>
<p>
This section describes what is supported by the various Compositor elements.
Generally everything defaults in the expected way: if you don't specify something, it does whatever Swing does.
The names and values broadly follow the equivalent Swing naming.
</p>
<ol type='i'>
<li id='refAccelerator'>
<h3>
accelerator
</h3>
<p>
Defines a mapping from a key stroke to an action for the current window.
</p>
<p>
Only valid as a child of <a href='#refAccelerators'><code class='element'>accelerators</code></a>
</p>
<p>
<strong>Note:</strong> This adds the key stroke to input map for the content pane of the current window, which usually works.
But for some keys, it might not.
For example, <code>alt DOWN</code> should work, but <code>DOWN</code> often won't.
You might find that per-component key mappings work better in such cases - see <a href='#refKeyMappings'>key mappings</a>.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
action
</dt>
<dd>
<p>
The name of an <a href='#refAction'><code class='element'>action</code></a> defined in the descriptor.
</p>
</dd>
<dt>
key
</dt>
<dd>
<p>
The value must work for <a href='https://docs.oracle.com/en/java/javase/14/docs/api/java.desktop/javax/swing/KeyStroke.html#getKeyStroke(java.lang.String)'><code><span class='class'>KeyStroke</span>.getKeyStroke(<span class='class'>String</span>)</code></a> except that single character strings map to <kbd>ctrl+<char></kbd> (or <kbd>command+<char></kbd> on a Mac).
</p>
</dd>
</dl>
</li>
<li id='refAccelerators'>
<h3>
accelerators
</h3>
<p>
Only valid as a child of <a href='#refFrame'><code class='element'>frame</code></a> or <a href='#refDialog'><code class='element'>dialog</code></a>
</p>
<h4>
Content
</h4>
<ul>
<li>
<a href='#refAccelerator'><code class='element'>accelerator</code></a>
</li>
</ul>
</li>
<li id='refAction'>
<h3>
action
</h3>
<p>
An action can only defined inside the <code>actions</code> element at the beginning of a descriptor.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
name
</dt>
<dd>
<p>
The name of the action must correspond to the name of an action method in the app.
For example, an action named <code>fooBar</code> must have a corresponding method <code>doFooBar</code>.
</p>
</dd>
<dt>
label
</dt>
<dd>
<p>
This text is displayed wherever the action is used: menu item, button, etc.
</p>
</dd>
<dt>
icon
</dt>
<dd>
An icon for this button: must be on the classpath, or a suitably qualified file name
</dd>
<dt>
tooltip
</dt>
<dd>
<p>
Displays on mouseover of any component with this action.
</p>
</dd>
<dt>
checked
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
If you set this attribute, invoking the action will toggle its state.
The attribute value sets the initial state.
</p>
<p>
To avoid this behaviour, don't set this attribute at all.
</p>
<p>
Here's an example of keeping a boolean in line with the checked state of an action.
Note that you must toggle the action checked state.
It's not automatic.
</p>
<pre>
<span class='keyword'>public void</span> doFoo() {
<span class='keyword'>final</span> AppAction action = getAction( <span class='string'>"foo"</span> );
m_foo = ! action.isChecked();
action.setChecked( m_foo );
}</pre>
</dd>
<dt>
enabled
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
</dl>
</li>
<li id='refActions'>
<h3>
actions
</h3>
<h4>
Content
</h4>
<ul>
<li>
<a href='#refAction'><code class='element'>action</code></a>
</li>
</ul>
</li>
<li id='refButton'>
<h3>
button
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
default
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Can the Enter key be used as a short cut for this button?
It will usually render differently to indicate this.
</p>
</dd>
<dt>
cancel
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Can the Escape key be used as a short cut for this button?
</p>
</dd>
<dt>
action
</dt>
<dd>
(an action name)
<p>
Does this button trigger an action?
The action also provides default text and icon for the button.
</p>
</dd>
<dt>
margin
</dt>
<dd>
(up to 4 space-separated integers: top left bottom right)
<p>
Sets space for margin between the button's border and the label.
</p>
<p class='warning'>
The margin is <em>inside</em> the border, unlike other components, where margins are <em>outside</em> the border.
Sometimes Swing is peculiar.
</p>
</dd>
<dt>
focusPainted
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Tells the look and feel that this button should look different when it has focus.
The difference is defined by the look and feel, and may be nothing.
Typically on Windows the button will display a dotted box around the text.
</p>
</dd>
<dt>
defaultCapable
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Can this button become the default?
</p>
</dd>
<dt>
icon
</dt>
<dd>
An icon for this button: must be on the classpath, or a suitably qualified file name
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onPress [<span title='optional' class='optional'>ActionEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
The button text
</p>
</li>
<li id='refButtonpanel'>
<h3>
buttonpanel
</h3>
<p>
See <a href='#refPanel'>panel</a>
</p>
<h4>
Content
</h4>
<p>
<a href='#refRadio'>radio</a> buttons
</p>
</li>
<li id='refCell'>
<h3>
cell
</h3>
<p>
Only makes sense inside a <a href='#refRow'>row</a> of a <a href='#refGrid'>grid</a>.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
anchor
</dt>
<dd>
<code>north</code>, <code>northeast</code>, <code>east</code>, <code>southeast</code>, <code>south</code>, <code>southwest</code>, <code>west</code>, <code>northwest</code>, <code>pageStart</code>, <code>pageEnd</code>, <code>lineStart</code>, <code>lineEnd</code>, <code>firstLineStart</code>, <code>firstLineEnd</code>, <code>lastLineStart</code>, <code>lastLineEnd</code>, <code>baseline</code>, <code>baselineLeading</code>, <code>baselineTrailing</code>, <code>aboveBaseline</code>, <code>aboveBaselineLeading</code>, <code>aboveBaselineTrailing</code>, <code>belowBaseline</code>, <code>belowBaselineLeading</code>, <code>belowBaselineTrailing</code>, <code>center</code>
<p>
Where in the cell should the contents go?
</p>
</dd>
<dt>
fill
</dt>
<dd>
<code>none</code>, <code>horizontal</code>, <code>vertical</code>, <code>both</code>
<p>
By default, smaller cells don't take up all the space available, and resizing a grid adds space around the outside (instead of resizing the cells).
That's pretty useless.
You can address these issues with this property, but you need <code>weightX</code> and <code>weightY</code> as well.
</p>
</dd>
<dt>
weightX
</dt>
<dd>
(number)
<p>
On resize, the grid uses this to decide how to allocate horizontal space.
So, on enlarging, what proportion of the extra width should go to this cell?
The default is 0.
</p>
</dd>
<dt>
weightY
</dt>
<dd>
(number)
<p>
On resize, the grid uses this to decide how to allocate vertical space.
So, on enlarging, what proportion of the extra height should go to this cell?
The default is 0.
</p>
</dd>
</dl>
<h4>
Content
</h4>
<p>
Other components
</p>
</li>
<li id='refCheckbox'>
<h3>
checkbox
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
selected
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
action
</dt>
<dd>
An action to invoke when the check box is selected
</dd>
<dt>
borderPaintedFlat
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Javadoc for JCheckbox says "gives a hint to the look and feel as to the appearance of the check box border."
May be ignored.
</p>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onItemEvent [<span title='optional' class='optional'>ItemEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
The checkbox text
</p>
</li>
<li id='refClones'>
<h3>
clones
</h3>
<h4>
Properties
</h4>
<p>
None
</p>
<h4>
Content
</h4>
<p>
<a href='#clones'>See explanation</a>
</p>
</li>
<li id='refColorchooser'>
<h3>
colorchooser
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
color/colour
</dt>
<dd>
The default colour.
See the <a href='#refCommon'>common colour values under <code class='attrib'>background</code></a>.
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onChange [<span title='optional' class='optional'>ChangeEvent</span>]
</li>
</ul>
</li>
<li id='refCombobox'>
<h3>
combobox
</h3>
<div class='callout'>
<p>
A comcobox consists of a collection of sub-components, so colours don't necessarily work as expected.
For example, setting <code>background</code> doesn't work.
This is a Swing issue, not a Compositor issue.
</p>
</div>
<h4>
Properties
</h4>
<dl>
<dt>
editable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onAction [<span title='optional' class='optional'>ActionEvent</span>]<br>
Called when a drop down option is chosen, or (if the combo box is editable and the user has entered their own value) when the combo box loses focus.
</li>
<li>
onInsert [<span title='optional' class='optional'>DocumentEvent</span>]<br>
Called only when the combo box is editable and text has been inserted in the editable portion,
</li>
<li>
onRemove [<span title='optional' class='optional'>DocumentEvent</span>]<br>
Called only when the combo box is editable and text has been removed from the editable portion,
</li>
</ul>
<p>
Note that while the user is entering text in an editable combo box, <code>onInsert</code> and <code>onRemove</code> will be called appropriately, but the value of the combo box will not change.
<code>getSelectedItem()</code> will still return the previous value.
To get the up-to-date value, call <code>getComboEditorValue(...)</code>
</p>
<p>
The following event handlers work the same as for other components, but only in the editable part of a combo box:
</p>
<ul>
<li>onKeyTyped</li>
<li>onKeyPressed</li>
<li>onKeyReleased</li>
</ul>
<h4>
Content
</h4>
<p>
The default contents of a combo box can be set as text content of the <code><<span class='element'>combobox</span>></code> element.
Use the pipe symbol to separate the entries:
</p>
<pre><span class='marker'><</span><span class='element'>combobox</span><span class='marker'>></span>cat|dog|fish<span class='marker'></</span><span class='element'>combobox</span><span class='marker'>></span></pre>
<p>
The value will default to the first item in the list.
</p>
</li>
<li id='refComponent'>
<h3>
component
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
name
</dt>
<dd>
Now to refer to this component in the descriptor.
Use an XML namespace to prevent clashes.
</dd>
<dt>
generator
</dt>
<dd>
The class that will generate components of this type.
</dd>
<dt>
class
</dt>
<dd>
Optional.
The class that will be generated.
you only need this is your generator can handle more than one class, and needs to know which one this is.
</dd>
</dl>
</li>
<li id='refComponents'>
<h3>
components
</h3>
<h4>
Content
</h4>
<ul>
<li>
<a href='#refComponent'><code class='element'>component</code></a>
</li>
</ul>
</li>
<li id='refDelegate'>
<h3>
delegate
</h3>
<p>
<a href='#delegates'>See explanation</a>
</p>
</li>
<li id='refDesktoppane'>
<h3>
desktoppane
</h3>
<h4>
Content
</h4>
<p>
Only <a href='#refInternalframe'><code class='element'>internalframe</code></a> makes sense.
Probably the best content is nothing, then later add <a href='#refInternalframe'><code class='element'>internalframe</code></a> instances as <a href='#clones'>clones</a>.
See <a href='#multiedit'>MultiEdit</a> for an example.
</p>
</li>
<li id='refDialog'>
<h3>
dialog
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
title
</dt>
<dd>
Text to display in the title bar
</dd>
<dt>
modal
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
alwaysOnTop
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
resizable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
An icon for this frame: must be on the classpath, or a suitably qualified file name.
The icon may not be displayed - for example, modal fixed size dialogs may display no icon at all.
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onLoad [<span title='optional' class='optional'>WindowEvent</span>]
<br>
Only called when the dialog is initially loaded, but after the first <code>onShow</code>
</li>
<li>
onClosing [<span title='optional' class='optional'>WindowEvent</span>]
</li>
<li>
onMoved [<span title='optional' class='optional'>HierarchyEvent</span>]
</li>
<li>
onResized [<span title='optional' class='optional'>HierarchyEvent</span>]
</li>
<li>
onHide [<span title='optional' class='optional'>ComponentEvent</span>]
</li>
<li>
onShow [<span title='optional' class='optional'>ComponentEvent</span>]
<br>
Called every time the dialog is shown, initially before <code>onLoad</code> is called
</li>
<li>
onLostFocus [<span title='optional' class='optional'>WindowEvent</span>]
</li>
<li>
onGainedFocus [<span title='optional' class='optional'>WindowEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<ol>
<li>
A single <a href='#refPanel'><code class='element'>panel</code></a> element, which in turn contains other elements
</li>
<li>
<p>
A single <code class='element'>buttonbar</code> element, which in turn contains <code class='element'>button</code> elements.
There are some commonly used button bar includes that you can use:
</p>
<pre><span class='marker'><</span><span class='element'>include</span> <span class='attribute'>file</span>=<span class='string'>'buttonbar_ok.xml'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>include</span> <span class='attribute'>file</span>=<span class='string'>'buttonbar_okcancel.xml'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>include</span> <span class='attribute'>file</span>=<span class='string'>'buttonbar_okhelpcancel.xml'</span> <span class='marker'>/></span></pre>
<p>
These can be customised. For example:
</p>
<pre><span class='marker'><</span><span class='element'>include</span> <span class='attribute'>file</span>=<span class='string'>'buttonbar_okhelpcancel.xml'</span> <span class='attribute'>okLabel</span>=<span class='string'>'Load'</span> <span class='attribute'>okEnabled</span>=<span class='string'>'false'</span> <span class='attribute'>cancelLabel</span>=<span class='string'>'Abort'</span> <span class='attribute'>helpLabel</span>=<span class='string'>'_Info...'</span> <span class='attribute'>helpName</span>=<span class='string'>'info'</span> <span class='marker'>/></span></pre>
</li>
</ol>
</li>
<li id='refEditorpane'>
<h3>
editorpane
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
editable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
contentType
</dt>
<dd>
A MIME type: the supported types depend on available <code class='class'>EditorKit</code>s, but <code>text/html</code> and <code>application/rtf</code> should work.
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onInsert [<span title='optional' class='optional'>DocumentEvent</span>]
</li>
<li>
onRemove [<span title='optional' class='optional'>DocumentEvent</span>]
</li>
<li>
onChanged [<span title='optional' class='optional'>DocumentEvent</span>]
<br>
Note: a change event indicates attribute changes on the text field's document (useless), not for changes to the text (would have been useful).
Swing can be unhelpful.
To respond to text changes, handle both onInsert and onRemove.
</li>
</ul>
<p>
See also <a href='#textComponentFromDocEvent'>How can I get hold of a text component from a document event?</a>
</p>
<h4>
Content
</h4>
<p>
The text that appears in the pane.
</p>
<p>
To include HTML, you will need to wrap it in CDATA.
Here's an example:
</p>
<pre><span class='marker'><</span><span class='element'>editorpane</span> <span class='highlight'><span class='attrib'>contentType</span>=<span class='string'>'text/html'</span></span><span class='marker'>></span><span class='highlight marker'><</span><span class='highlight'>![CDATA[</span><html>
<h1>A header</h1>
<p>A paragraph</p>
</html><span class='highlight'>]]</span><span class='marker highlight'>></span></<span class='element'>editorpane</span><span class='marker'>></span></pre>
</li>
<li id='refFrame'>
<h3>
frame
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
title
</dt>
<dd>
Text to display in the title bar.
Defaults to the name of the app.
If you really want no title, set it to nothing: <code><span class='attrib'>title</span>=<span class='string'>""</span></code>
</dd>
<dt>
icon
</dt>
<dd>
An icon for this frame: must be on the classpath, or a suitably qualified file name
</dd>
<dt>
resizable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
top
</dt>
<dd>
(integer)
</dd>
<dt>
left
</dt>
<dd>
(integer)
</dd>
<dt>
height
</dt>
<dd>
(integer)
</dd>
<dt>
width
</dt>
<dd>
(integer)
</dd>
<dt>
undecorated
</dt>
<dd>
<code>false</code> - normal window<br>
<code>true</code> - remove all OS decorations (title bar, close and minimise buttons, resize borders, etc.)
<p>
<strong>Note:</strong> if you set this to <code>true</code> you're removing functionality that the OS would have provided, so you should probably provide the user with some other way to do these things.
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onLoad [<span title='optional' class='optional'>WindowEvent</span>]
<br>
Only called when the frame is initially loaded, but after the first <code>onShow</code>
</li>
<li>
onClosing [<span title='optional' class='optional'>WindowEvent</span>]
</li>
<li>
onMoved [<span title='optional' class='optional'>HierarchyEvent</span>]
</li>
<li>
onResized [<span title='optional' class='optional'>HierarchyEvent</span>]
</li>
<li>
onHide [<span title='optional' class='optional'>ComponentEvent</span>]
</li>
<li>
onShow [<span title='optional' class='optional'>ComponentEvent</span>]
<br>
Called every time the frame is shown, initially before <code>onLoad</code> is called
</li>
<li>
onLostFocus [<span title='optional' class='optional'>WindowEvent</span>]
</li>
<li>
onGainedFocus [<span title='optional' class='optional'>WindowEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<ol>
<li>
Optional <a href='#refAccelerators'><code class='element'>accelerators</code></a> element, containing <a href='#refAccelerator'><code class='element'>accelerator</code></a> elements which map keys to actions, e.g. <code><span class='attrib'>key</span>=<span class='string'>'control INSERT'</span> <span class='attrib'>action</span>=<span class='string'>'copy'</span></code>
</li>
<li>
Optional <a href='#refMenubar'><code class='element'>menubar</code></a> element containing <a href='#refMenu'><code class='element'>menu</code></a> elements with a <code class='attrib'>label</code> attribute and an optional <code class='attrib'>name</code> attribute.
These in turn contains <a href='#refMenuitem'><code class='element'>menuitem</code></a> elements with an optional <code class='attrib'>action</code> attribute and an optional <code class='attrib'>accelerator</code> attribute.
Menu items with no attributes produce a separator.
</li>
<li>
Optional <a href='#refPopupmenus'><code class='element'>popupmenus</code></a> element containing <a href='#refPopupmenu'><code class='element'>popupmenu</code></a> with the same attributes and contents as <code class='element'>menu</code> above.
</li>
<li>
Optional <code class='element'>toolbars</code> element containing <code class='element'>toolbar</code> elements, in turn containing <code class='element'>toolbutton</code> elements with an optional <code class='attrib'>action</code> attribute (tool buttons with no action produce a separator).
</li>
<li>
A single <a href='#refPanel'><code class='element'>panel</code></a> element (which in turn contains other elements), or a or <a href='#refDesktoppane'><code class='element'>desktoppane</code></a>
</li>
</ol>
</li>
<li id='refGlasspane'>
<h3>
glasspane
</h3>
<p>
A frame is covered by a glass pane.
You can add components here that float on top of the window.
See the <a href='#jetris'>Jetris</a> "game over" message for an example.
</p>
<p>
It may not be a good idea to use the glass pane.
For example, components here can appear on top of menus!
If you want a layered presentation, <a href='#refLayeredpane'><code class='element'>layeredpane</code></a> is more flexible and won't do anything weird.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
layout, align, gridRows, gridCols, gridHGap, gridVGap
</dt>
<dd>
See <a href='#refPanel'><code class='element'>panel</code></a>
</dd>
</dl>
<h4>
Content
</h4>
<p>
Other components
</p>
</li>
<li id='refGlue'>
<h3>
glue
</h3>
<p>
Glue has no properties and contains nothing.
It fills up space.
See Box.createGlue for more info.
</p>
<p>
If you want to see the space that glue is filling, try giving it a <code class='attrib'>border</code> or a <code class='attrib'>background</code>.
Hmm - so glue goes have <em>some</em> properties (the default ones) but none of its own
</p>
<p>
Glue can be useful if you want to have something centred horizontally or vertically: you can put glue on either side of the centred component.
</p>
<p>
You can also use an empty panel with border layout in this way, but the reaction to resizing is different.
Run the <a href='#gluetest'>GlueTest</a> example to see how this works.
</p>
</li>
<li id='refGrid'>
<h3>
grid
</h3>
<p>
See <a href='#refPanel'>panel</a>, but some properties wouldn't make sense, such as changing the layout.
</p>
<h4>
Content
</h4>
<p>
<a href='#refRow'><code class='element'>row</code></a> elements, which in turn contain <a href='#refCell'><code class='element'>cell</code></a> elements
</p>
</li>
<li id='refInternalframe'>
<h3>
internalframe
</h3>
<p>
It only makes sense to put this in a <a href='#refDesktoppane'><code class='element'>desktoppane</code></a>
</p>
<h4>
Properties
</h4>
<dl>
<dt>
icon
</dt>
<dd>
An icon for this label: must be on the classpath, or a suitably qualified file name.
</dd>
<dt>
closable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
iconifiable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
maximizable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
resizable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
</dl>
<h4>
Content
</h4>
<p>
Other components
</p>
</li>
<li id='refLabel'>
<h3>
label
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
icon
</dt>
<dd>
An icon for this label: must be on the classpath, or a suitably qualified file name.
The value <code>none</code> suppresses any icon inherited from an <code class='attrib'>action</code>.
</dd>
<dt>
align
</dt>
<dd>
<code>right</code>, <code>center</code>, <code>centre</code>, <code>left</code>
</dd>
<dt>
verticalAlign
</dt>
<dd>
<code>top</code>, <code>center</code>, <code>centre</code>, <code>bottom</code>
</dd>
<dt>
for
</dt>
<dd>
(component name - if this label has a keyboard accelerator, determines which control gets the focus)
</dd>
<dt>
horizontalTextPosition
</dt>
<dd>
<code>left</code>, <code>center</code>, <code>centre</code>, <code>right</code>, <code>leading</code>, <code>trailing</code>
</dd>
<dt>
verticalTextPosition
</dt>
<dd>
<code>top</code>, <code>center</code>, <code>centre</code>, <code>bottom</code>
</dd>
<dt>
action
</dt>
<dd>
(an action name)
<p>
Clicking this label will trigger an action.
The action also provides default text and icon for the label.
</p>
</dd>
<dt>
(shared padding and margin properties)
</dt>
<dd>
<a href='#refPaddingAndMargins'>(see below)</a>
</dd>
</dl>
<h4>
Content
</h4>
<p>
The text to display in the label.
</p>
<p>
If the text contains an underscore, the following letter becomes a keyboard accelerator, and may be underlined (depending on your operating system and settings). Press this key with a modifier (usually <kbd>Alt</kbd>) to give focus to the control named in the <code class='attrib'>for</code> attribute.
</p>
<p>
For multi-line labels or other text layout, you can use HTML.
You must put it in a CDATA section so that it is seen as the content of the label rather than nested elements.
Here's an example:
</p>
<pre><span class='marker'><</span><span class='element'>label</span><span class='marker'>></span><span class='highlight marker'><</span><span class='highlight'>![CDATA[</span><html>
<style>
body{font-family:monospace}
</style>
<body>
<h1>Yay!</h1>
<p>
<em>Fancy</em> text
</p>
</body>
</html><span class='highlight'>]]</span><span class='marker highlight'>></span></<span class='element'>label</span><span class='marker'>></span></pre>
<h4>
Notes
</h4>
<p>
An example of how to display an icon with text below:
</p>
<pre><span class='marker'><</span><span class='element'>label</span>
<span class='attribute'>icon</span> = <span class='string'>'somefilename'</span>
<span class='attribute'>verticalTextPosition</span> = <span class='string'>'bottom'</span>
<span class='attribute'>horizontalTextPosition</span> = <span class='string'>'center'</span>
<span class='marker'>></span>text below<span class='marker'></</span><span class='element'>label</span><span class='marker'>></span></pre>
<p>
<code><span class='attrib'>align</span>=<span class='string'>'center'</span></code> may also help if there are several to line up.
</p>
</li>
<li id='refLayeredpane'>
<h3>
layeredpane
</h3>
<p>
This works just like a <a href='#refPanel'>panel</a>.
The difference is that components are in layers and can overlap.
You specify which layer with a <code class='attrib'>layer</code> attribute on the children of the <code class='element'>layeredpane</code> (see <a href='#refCommon'>Common properties</a>).
</p>
<p>
By default, layered panes have no layout manager, and you should position and size the contents yourself.
This should include setting the size of contained components, which defaults to zero.
You probably also need to implement <code>fooWindow_barLayeredPane_onResize()</code>.
The example app, <a href='#floatywidget'>FloatyWidget</a>, shows how to do this.
</p>
<p>
It is possible to use the <code class='attrib'>layout</code> attribute in the same way as with a <a href='#refPanel'>panel</a>, but then the components won't overlap.
</p>
</li>
<li id='refList'>
<h3>
list
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
selection
</dt>
<dd>
<code>single</code>, <code>interval</code>, <code>multiple</code>
</dd>
<dt>
layoutOrientation
</dt>
<dd>
<code>vertical</code>, <code>horizontalWrap</code>, <code>verticalWrap</code>
<ul>
<li>
The default is <code>vertical</code>.
The list goes downwards and never wraps.
</li>
<li>
With <code>horizontalWrap</code> the list items read across, but flow to extra rows if required.
</li>
<li>
With <code>verticalWrap</code> the list items read down, but flow to extra columns if required.
</li>
</ul>
</dd>
<dt>
visibleRowCount
</dt>
<dd>
(integer)
<p>
You can control the fixed height of a horizontally or vertically wrapped list.
Set this to <code>0</code> to make the list adjust to fit.
</p>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onSelect [<span title='optional' class='optional'>ListSelectionEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
The default contents of a list can be set as text content of the <code class='element'>list</code> element.
Use the pipe symbol to separate the entries:
</p>
<pre><span class='marker'><</span><span class='element'>list</span><span class='marker'>></span>cat<span class='highlight'>|</span>dog<span class='highlight'>|</span>fish<span class='marker'></</span><span class='element'>list</span><span class='marker'>></span></pre>
</li>
<li id='refMenu'>
<h3>
menu
</h3>
<p>
Only makes sense inside a <a href='#refMenubar'>menubar</a> or a <a href='#refPopupmenu'>popupmenu</a>.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
name
</dt>
<dd>
(text) - used to refer to the menu from code, e.g. <code>getMenu(<span class='string'>"someName"</span>)</code>
</dd>
<dt>
label
</dt>
<dd>
(text) - might be displayed to the user to identify this menu (depending on the platform and/or look and feel)
</dd>
<dt>
icon
</dt>
<dd>
(text) - might be displayed to the user to identify this menu (depending on the platform and/or look and feel)
</dd>
</dl>
<h4>
Content
</h4>
<p>
<a href='#refMenuitem'>menuitem</a>s
</p>
</li>
<li id='refMenubar'>
<h3>
menubar
</h3>
<p>
Only makes sense inside a <a href='#refFrame'>frame</a>.
</p>
<h4>
Content
</h4>
<p>
<a href='#refMenu'>menu</a>s
</p>
</li>
<li id='refMenuitem'>
<h3>
menuitem
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
action
</dt>
<dd>
The name of an <a href='#refAction'><code class='element'>action</code></a> defined in the descriptor.
</dd>
<dt>
accelerator
</dt>
<dd>
A keyboard shortcut for this menu item.
</dd>
</dl>
<p>
Other properties of this menu item (displayed text, icon, tool tip, etc.) are picked up from the action.
</p>
<h4>
Content
</h4>
<p>
None
</p>
</li>
<li id='refPanel'>
<h3>
panel
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
title
</dt>
<dd>
(text)
<p>
Adding a title will give the panel a border with the title text included.
</p>
</dd>
<dt>
dropTarget
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Can you drop draggable components into this panel?
</p>
</dd>
<dt>
layout
</dt>
<dd>
<code>flowLayout</code>, <code>borderLayout</code>, <code>boxLayoutX</code>, <code>boxLayoutY</code>, <code>gridLayout</code>, <code>cardLayout</code>
</dd>
<dt>
borderLayout
</dt>
<dd>
<code>north</code>, <code>south</code>, <code>east</code>, <code>west</code>, <code>center</code>, <code>centre</code>, <code>middle</code>
<p>
This only makes sense with <code>borderLayout</code>.
</p>
</dd>
<dt>
align
</dt>
<dd>
<code>left</code>, <code>right</code>, <code>center</code>, <code>centre</code>, <code>leading</code>, <code>trailing</code>
<p>
This only makes sense with <code>flowLayout</code>.
</p>
</dd>
<dt>
hGap
</dt>
<dd>
(integer)
<p>
This only makes sense with <code>flowLayout</code>.
</p>
</dd>
<dt>
vGap
</dt>
<dd>
(integer)
<p>
This only makes sense with <code>flowLayout</code>.
</p>
</dd>
<dt>
gridRows
</dt>
<dd>
(integer)
<p>
This only makes sense with <code>gridLayout</code>.
Zero means "as many rows as necessary".
</p>
</dd>
<dt>
gridCols
</dt>
<dd>
(integer)
<p>
This only makes sense with <code>gridLayout</code>.
Zero means "as many columns as necessary"
</p>
</dd>
<dt>
gridHGap
</dt>
<dd>
(integer)
<p>
This only makes sense with <code>gridLayout</code>.
</p>
</dd>
<dt>
gridVGap
</dt>
<dd>
(integer)
<p>
This only makes sense with <code>gridLayout</code>.
</p>
</dd>
<dt>
(shared padding and margin properties)
</dt>
<dd>
<a href='#refPaddingAndMargins'>(see below)</a>
</dd>
</dl>
<h4>
Event handlers
</h4>
<p>
Default behaviour for these is provided if <code class='attrib'>dropTarget</code> is <code>true</code>.
</p>
<ul>
<li>
onDragEnter [<span title='optional' class='optional'>DropTargetDragEvent</span>]
</li>
<li>
onDragExit [<span title='optional' class='optional'>DropTargetEvent</span>]
</li>
<li>
onDragOver [<span title='optional' class='optional'>DropTargetDragEvent</span>]
</li>
<li>
onDrop <code class='class'>DropTargetDropEvent</code>
<p>
There's no point implementing this handler without the event parameter.
For the drop to work, you must call <code>acceptDrop</code> on the event, do something as a result of the drop, and call <code>dropComplete</code> on the event.
Implementing this handler disables the default behaviour for a <code>dropTarget</code> panel (to accept the drag of a component and move it to this panel).
</p>
</li>
<li>
onDropActionChanged [<span title='optional' class='optional'>DropTargetDragEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
Other components
</p>
</li>
<li id='refPassword'>
<h3>
password
</h3>
<p>
See <a href='#refTextfield'>textfield</a>
</p>
<h4>
Content
</h4>
<p>
Can be used to set a default value, but probably not a good idea to do so
</p>
</li>
<li id='refPopupmenu'>
<h3>
popupmenu
</h3>
<p>
Only makes sense inside <a href='#refPopupmenus'>popupmenus</a>.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
name
</dt>
<dd>
(text) - used to refer to the menu elsewhere in the descriptor
</dd>
<dt>
label
</dt>
<dd>
(text) - might be displayed to the user to identify this menu (depending on the platform and/or look and feel)
</dd>
<dt>
icon
</dt>
<dd>
(text) - might be displayed to the user to identify this menu (depending on the platform and/or look and feel)
</dd>
</dl>
<h4>
Content
</h4>
<p>
<a href='#refMenuitem'>menuitem</a>s
</p>
</li>
<li id='refPopupmenus'>
<h3>
popupmenus
</h3>
<p>
Only makes sense inside <a href='#refFrame'>frame</a>.
</p>
<h4>
Content
</h4>
<p>
<a href='#refPopupmenu'>popupmenu</a>s
</p>
</li>
<li id='refProgressbar'>
<h3>
progressbar
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
min
</dt>
<dd>
(integer)
</dd>
<dt>
max
</dt>
<dd>
(integer)
</dd>
</dl>
<h4>
Content
</h4>
<p>
The default value of the progress bar
</p>
</li>
<li id='refRadio'>
<h3>
radio
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
selected
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
value
</dt>
<dd>
When this button is in a <a href='#refButtonpanel'><code class='element'>buttonpanel</code></a>, the value returned by <code>RadioButtonPanel.getSelectedValue()</code>.
Similarly, you can get the name of the selected radio button: <code>RadioButtonPanel.getSelectedName()</code>.
</dd>
<dt>
action
</dt>
<dd>
An action to invoke when the radio button is selected
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onItemEvent [<span title='optional' class='optional'>ItemEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
The radio button text
</p>
</li>
<li id='refRow'>
<h3>
row
</h3>
<p>
Only makes sense inside a <a href='#refGrid'>grid</a>.
</p>
<h4>
Content
</h4>
<p>
<a href='#refCell'>cell</a>s
</p>
</li>
<li id='refScrollbar'>
<h3>
scrollbar
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
min
</dt>
<dd>
(integer)
</dd>
<dt>
max
</dt>
<dd>
(integer)
</dd>
<dt>
unitIncremement
</dt>
<dd>
(integer)
</dd>
<dt>
blockIncremement
</dt>
<dd>
(integer)
</dd>
<dt>
orientation
</dt>
<dd>
<code>horizontal</code>, <code>vertical</code>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onAdjustment [<span title='optional' class='optional'>AdjustmentEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
The default position of the scroll bar
</p>
</li>
<li id='refScrollpane'>
<h3>
scrollpane
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
hScroll
</dt>
<dd>
<code>asNeeded</code>, <code>never</code>, <code>always</code>
<p>
When does the horizontal scroll bar appear?
</p>
</dd>
<dt>
vScroll
</dt>
<dd>
<code>asNeeded</code>, <code>never</code>, <code>always</code>
<p>
When does the vertical scroll bar appear?
</p>
</dd>
<dt>
hScrollUnitIncrement
</dt>
<dd>
(integer)
</dd>
<dt>
vScrollUnitIncrement
</dt>
<dd>
(integer)
</dd>
<dt>
hScrollBlockIncremement
</dt>
<dd>
(integer)
</dd>
<dt>
vScrollBlockIncremement
</dt>
<dd>
(integer)
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onVerticalScroll [<span title='optional' class='optional'>AdjustmentEvent</span>]
</li>
<li>
onHorizontalScroll [<span title='optional' class='optional'>AdjustmentEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
Other components
</p>
</li>
<li id='refSeparator'>
<h3>
separator
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
orientation
</dt>
<dd>
<code>horizontal</code>, <code>vertical</code>
</dd>
</dl>
</li>
<li id='refSlider'>
<h3>
slider
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
min
</dt>
<dd>
(integer)
</dd>
<dt>
max
</dt>
<dd>
(integer)
</dd>
<dt>
major
</dt>
<dd>
(integer)
</dd>
<dt>
minor
</dt>
<dd>
(integer)
</dd>
<dt>
track
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Is the track painted?
</p>
</dd>
<dt>
snap
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
Does the slider jump to the nearest tick?
</p>
</dd>
<dt>
labels
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
orientation
</dt>
<dd>
<code>horizontal</code>, <code>vertical</code>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onChange [<span title='optional' class='optional'>ChangeEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
Initial value of the slider
</p>
</li>
<li id='refSpinner'>
<h3>
spinner
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
type
</dt>
<dd>
<code>integer</code>, <code>double</code>, <code>list</code>, <code>date</code>: sets what sort of spinner it is
<br>
(default: <code>integer</code>)
</dd>
<dt>
min
</dt>
<dd>
(number) - only makes sense with types <code>integer</code> or <code>double</code>
</dd>
<dt>
max
</dt>
<dd>
(number) - only makes sense with types <code>integer</code> or <code>double</code>
</dd>
<dt>
step
</dt>
<dd>
(number) - only makes sense with types <code>integer</code> or <code>double</code>
</dd>
<dt>
list
</dt>
<dd>
(pipe-separated list) - only makes sense with type <code>list</code>
</dd>
<dt>
format
</dt>
<dd>
(date format in the style of SimpleDateFormat) - only makes sense with type <code>date</code>
<br>
default: <code class='string'>"yyyy-MM-dd-HH:mm"</code>
</dd>
<dt>
start
</dt>
<dd>
(date/time) - only makes sense with type <code>date</code>
</dd>
<dt>
end
</dt>
<dd>
(date/time) - only makes sense with type <code>date</code>
</dd>
<dt>
field
</dt>
<dd>
<code>era</code>, <code>year</code>, <code>month</code>, <code>week_of_year</code>, <code>week_of_month</code>, <code>day_of_month</code>, <code>day_of_year</code>, <code>day_of_week</code>, <code>day_of_week_in_month</code>, <code>am_pm</code>, <code>hour</code>, <code>hour_of_day</code>, <code>minute</code>, <code>second</code>, <code>millisecond</code> - only makes sense with type <code>date</code>
<br>
Sadly, although this value is used in constructing the underlying SpinnerDateModel, it seems to be ignored by the spinner.
The normal behaviour of a date spinner is to display an editable date, and the spinner buttons will spin the element of the date where the text cursor is.
It's a Swing feature, not a Compositor feature.
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onChange [<span title='optional' class='optional'>ChangeEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
Initial value of the spinner: format depends on <code>type</code>
</p>
<h4>
Examples
</h4>
<ul>
<li>
<h5>
Integer
</h5>
<pre><span class='marker'><</span><span class='element'>spinner</span> <span class='attrib'>type</span>=<span class='string'>'integer'</span> <span class='attrib'>min</span>=<span class='string'>'-2'</span> <span class='attrib'>max</span>=<span class='string'>'4'</span> <span class='attrib'>step</span>=<span class='string'>'2'</span><span class='marker'>></span>1<span class='marker'></</span><span class='element'>spinner</span><span class='marker'>></span></pre>
</li>
<li>
<h5>
Double
</h5>
<pre><span class='marker'><</span><span class='element'>spinner</span> <span class='attrib'>type</span>=<span class='string'>'double'</span> <span class='attrib'>min</span>=<span class='string'>'-2'</span> <span class='attrib'>max</span>=<span class='string'>'3.5'</span> <span class='attrib'>step</span>=<span class='string'>'0.5'</span><span class='marker'>></span>1.5<span class='marker'></</span><span class='element'>spinner</span><span class='marker'>></span></pre>
</li>
<li>
<h5>
List
</h5>
<pre><span class='marker'><</span><span class='element'>spinner</span> <span class='attrib'>type</span>=<span class='string'>'list'</span> <span class='attrib'>list</span>=<span class='string'>'Cat|Dog|Fish|Rabbit|Lizard'</span><span class='marker'>></span>Rabbit<span class='marker'></</span><span class='element'>spinner</span><span class='marker'>></span></pre>
</li>
<li>
<h5>
date
</h5>
<pre><span class='marker'><</span><span class='element'>spinner</span> <span class='attrib'>type</span>=<span class='string'>'date'</span> <span class='attrib'>start</span>=<span class='string'>'2000-01-01-00:00'</span> <span class='attrib'>end</span>=<span class='string'>'2038-01-01-00:00'</span> <span class='attrib'>field</span>=<span class='string'>'day_of_month'</span><span class='marker'>></span>2015-12-25-15:00<span class='marker'></</span><span class='element'>spinner</span><span class='marker'>></span></pre>
</li>
</ul>
</li>
<li id='refSplash'>
<h3>
splash
</h3>
<p>
<a href='#splashscreen'>More explanation</a>
</p>
<h4>
Properties
</h4>
<dl>
<dt>
image
</dt>
<dd>
an image to display as a splash screen - found from the class path or from the file system
</dd>
</dl>
<h4>
Content
</h4>
<p>
None
</p>
</li>
<li id='refSplitpane'>
<h3>
splitpane
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
oneTouchExpandable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
continuousLayout
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
resizeWeight
</dt>
<dd>
(decimal, from 0 to 1 inclusive)
</dd>
<dt>
dividerSize
</dt>
<dd>
(integer)
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onDividerMoved [<span title='optional' class='optional'>PropertyChangeEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
Two other components.
On the contained components, set <code class='attrib'>position</code> to <code>left</code> or <code>right</code>, or to <code>top</code> or <code>bottom</code> to determine orientation of the split.
The default is <code>left</code>.
</p>
</li>
<li id='refTabbedpane'>
<h3>
tabbedpane
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
tabLayoutPolicy
</dt>
<dd>
<code>wrap</code>, <code>scroll</code>
</dd>
<dt>
tabPlacement
</dt>
<dd>
<code>top</code>, <code>bottom</code>, <code>left</code>, <code>right</code>
</dd>
<dt>
tabMenu
</dt>
<dd>
the name of a popup menu in the current window
<p>
<strong>Note:</strong> if you add a custom tab component, the tab menu will no longer automatically work (because it works by adding a custom tab component of its own).
You should add the menu to the tab component yourself.
</p>
</dd>
<dt>
middleClickAction
</dt>
<dd>
the name of an action to invoke when a tab is middle-clicked
<p>
<strong>Note:</strong> if you add a custom tab component, this action will no longer automatically work (because it works by adding a custom tab component of its own).
You should add the action to the tab component yourself.
</p>
</dd>
<dt>
(shared padding and margin properties)
</dt>
<dd>
<a href='#refPaddingAndMargins'>(see below)</a>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onSelectionChange [<span title='optional' class='optional'>ChangeEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
Child components of the tabbed pane determine the number of tabs and the text that appears on them (see <a href='#refCommon'>Common properties</a>).
</p>
</li>
<li id='refTable'>
<h3>
table
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
rows
</dt>
<dd>
(integer)
</dd>
<dt>
cols
</dt>
<dd>
(integer)
</dd>
<dt>
columnSelectionAllowed
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
rowSelectionAllowed
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
reorderingAllowed
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
selectionModel
</dt>
<dd>
<code>single</code>, <code>singleInterval</code>, <code>multipleInterval</code>
</dd>
<dt>
autoResizeMode
</dt>
<dd>
<code>off</code>, <code>nextColumn</code>, <code>subsequentColumns</code>, <code>lastColumn</code>, <code>allColumns</code>
</dd>
<dt>
showGrid
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
showVerticalLines
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
(overrides <code class='attrib'>showGrid</code>)
</p>
</dd>
<dt>
showHorizontalLines
</dt>
<dd>
<code>true</code>, <code>false</code>
<p>
(overrides <code class='attrib'>showGrid</code>)
</p>
</dd>
</dl>
<h4>
Event handlers
</h4>
<p>
Note: if you want to be notified of selection changes on a table whose cells can be individually selected (rather than entire rows of columns), implement both <code>onRowSelect</code> and <code>onColumnSelect</code>.
One or both methods may be called whenever the selection changes.
</p>
<ul>
<li>
onRowSelect [<span title='optional' class='optional'>ListSelectionEvent</span>]
</li>
<li>
onColumnSelect [<span title='optional' class='optional'>ListSelectionEvent</span>]
</li>
<li>
onColumnMoved [<span title='optional' class='optional'>TableColumnModelEvent</span>]
</li>
<li>
onHeaderClick [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onHeaderDoubleClick [<span title='optional' class='optional'>MouseEvent</span>]
</li>
</ul>
<p>
To find which header column was clicked, try something like this:
</p>
<pre>myTable.convertColumnIndexToModel( myTable.getTableHeader().columnAtPoint( e.getPoint() ) )</pre>
<h4>
Content
</h4>
<p>
The default contents of a table can be set as text content of the <code class='element'>table</code> element.
Use one line per row, and separate columns with the pipe symbol:
</p>
<pre><span class='marker'><</span><span class='element'>table</span><span class='marker'>></span>
Product |Stock |Price
Cat food |1,234 tins |£1.23
Dog biscuits|234 bags |£2.34
Fish flakes |432 packets|£0.85
<span class='marker'></</span><span class='element'>table</span><span class='marker'>></span></pre>
<p>
The first row is used for column headings (normally only visible if your table is inside a scrollpane).
Lining up the columns is optional.
White space is trimmed, so this is equivalent:
</p>
<pre><span class='marker'><</span><span class='element'>table</span><span class='marker'>></span>Product|Stock|Price
Cat food|1,234 tins|£1.23
Dog biscuits|234 bags|£2.34
Fish flakes|432 packets|£0.85<span class='marker'></</span><span class='element'>table</span><span class='marker'>></span></pre>
</li>
<li id='refTextarea'>
<h3>
textarea
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
wrap
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
wrapStyle
</dt>
<dd>
<code>word</code>, <code>char</code>
</dd>
<dt>
editable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onInsert [<span title='optional' class='optional'>DocumentEvent</span>]
</li>
<li>
onRemove [<span title='optional' class='optional'>DocumentEvent</span>]
</li>
<li>
onChanged [<span title='optional' class='optional'>DocumentEvent</span>]
<br>
Note: a change event indicates attribute changes on the text field's document (useless), not for changes to the text (would have been useful).
Swing can be unhelpful.
To respond to text changes, handle both onInsert and onRemove.
</li>
</ul>
<p>
See also <a href='#textComponentFromDocEvent'>How can I get hold of a text component from a document event?</a>
</p>
<h4>
Content
</h4>
<p>
Initial content of the text area
</p>
</li>
<li id='refTextfield'>
<h3>
textfield
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
cols
</dt>
<dd>
(integer)
</dd>
<dt>
horizontalAlignment
</dt>
<dd>
<code>left</code>, <code>right</code>, <code>center</code>, <code>leading</code>, <code>trailing</code>
</dd>
</dl>
<h4>
Event handlers
</h4>
<ul>
<li>
onInsert [<span title='optional' class='optional'>DocumentEvent</span>]
</li>
<li>
onRemove [<span title='optional' class='optional'>DocumentEvent</span>]
</li>
<li>
onChanged [<span title='optional' class='optional'>DocumentEvent</span>]
<br>
Note: a change event indicates attribute changes on the text field's document (useless), not for changes to the text (would have been useful).
Swing can be unhelpful.
To respond to text changes, handle both onInsert and onRemove.
</li>
</ul>
<p>
See also <a href='#textComponentFromDocEvent'>How can I get hold of a text component from a document event?</a>
</p>
<h4>
Content
</h4>
<p>
Initial content of the text field
</p>
</li>
<li id='refToolbar'>
<h3>
toolbar
</h3>
<p>
Toolbars normally appear at the top of a window.
You can add them as a child of a <a href='#refFrame'>frame</a> or <a href='#refDialog'>dialog</a>.
But you can also add them elsewhere, for example next to other components that the tools will affect.
</p>
<h4>
Content
</h4>
<p>
<a href='#refToolbutton'>toolbutton</a>s
</p>
</li>
<li id='refToolbutton'>
<h3>
toolbutton
</h3>
<p>
A <code>toolbutton</code> only makes sense inside a <a href='#refToolbar'>toolbar</a>.
In other contexts, use a <a href='#refButton'>button</a> instead.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
action
</dt>
<dd>
An action to invoke when the tool button is pressed
</dd>
</dl>
<h4>
Content
</h4>
<p>
Replacement text for the action's label
</p>
</li>
<li id='refTree'>
<h3>
tree
</h3>
<h4>
Properties
</h4>
<dl>
<dt>
rootVisible
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
showsRootHandles
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
selectionMode
</dt>
<dd>
<code>single</code>, <code>contiguous</code>, <code>discontiguous</code>
</dd>
<dt>
leafIcon
</dt>
<dd>
(file name)
</dd>
<dt>
openIcon
</dt>
<dd>
(file name)
</dd>
<dt>
closedIcon
</dt>
<dd>
(file name)
</dd>
</dl>
<p>
Icons must be on the classpath, or a suitably qualified file name
</p>
<h4>
Event handlers
</h4>
<ul>
<li>
onSelectionChanged [<span title='optional' class='optional'>TreeSelectionEvent</span>]
</li>
<li>
onTreeWillExpand [<span title='optional' class='optional'>TreeExpansionEvent</span>]
</li>
<li>
onTreeWillCollapse [<span title='optional' class='optional'>TreeExpansionEvent</span>]
</li>
<li>
onTreeExpanded [<span title='optional' class='optional'>TreeExpansionEvent</span>]
</li>
<li>
onTreeCollapsed [<span title='optional' class='optional'>TreeExpansionEvent</span>]
</li>
</ul>
<h4>
Content
</h4>
<p>
The default content of the tree is set by Swing: colours, sports and foods.
You can replace it like this:
</p>
<pre>root
|first level
||second level, 1st item
||second level, 2nd item
|||as deep as you like
|first level again</pre>
<p>
Or you can build a tree model in code and call <code>setModel</code>.
</p>
<pre>myWindow_myTree.setModel( getMyTreeModel() );</pre>
</li>
<li id='refUi'>
<h3>
ui
</h3>
<p>
This is the root element of all Compositor UI descriptors.
</p>
<h4>
Properties
</h4>
<dl>
<dt>
name
</dt>
<dd>
An optional name for the app.
Defaults to the app class name.
You can get this name by calling <code>getAppName()</code>
</dd>
</dl>
<h4>
Content
</h4>
<ul>
<li>
<a href='#refSplash'>splash</a>
</li>
<li>
<a href='#refActions'>actions</a>
</li>
<li>
<a href='#refComponents'>components</a>
</li>
<li>
<a href='#refClones'>clones</a>
</li>
<li>
<a href='#refWindows'>windows</a>
</li>
</ul>
</li>
<li id='refWindows'>
<h3>
windows
</h3>
<h4>
Content
</h4>
<ul>
<li>
<a href='#commonattributes'>commonattributes</a> (optional)
</li>
<li>
<a href='#refFrame'>frame</a> (0 to many times)
</li>
<li>
<a href='#refDialog'>dialog</a> (0 to many times)
</li>
<li>
<a href='#refDelegate'>delegate</a> (0 to many times)
</li>
</ul>
<p>
Each type of window can appear as many times as required.
If your app has more than one frame, you must have a <code>run</code> method that loads the appropriate frame(s) when the UI is displayed.
</p>
</li>
<li id='refCommon'>
<h3>
Common properties
</h3>
<p>
All components share some common properties:
</p>
<dl>
<dt id='namingrules'>
name
</dt>
<dd>
Components can be named as you wish.
There are some rules, though: names should begin with a letter and only contain letters and numbers.
You should definitely avoid using these symbols:
<br>
<code>- _ $ .</code>
</dd>
<dt>
alignmentX
</dt>
<dd>
(floating point, 0 to 1)<br>
Zero means "left".
Useful with <code>boxLayoutY</code>.
The Swing default alignments are sometimes peculiar
</dd>
<dt>
alignmentY
</dt>
<dd>
(floating point, 0 to 1)<br>
Zero means "top".
Useful with <code>boxLayoutX</code>.
The Swing default alignments are sometimes peculiar
</dd>
<dt>
background
</dt>
<dd>
<code>blue</code>, <code>black</code>, <code>cyan</code>, <code>darkGray</code>, <code>gray</code>, <code>green</code>, <code>lightGray</code>, <code>magenta</code>, <code>orange</code>, <code>pink</code>, <code>red</code>, <code>white</code>, <code>yellow</code>
<p>
<code>activeCaption</code>, <code>activeCaptionBorder</code>, <code>activeCaptionText</code>, <code>control</code>, <code>controlDkShadow</code>, <code>controlHighlight</code>, <code>controlLtHighlight</code>, <code>controlShadow</code>, <code>controlText</code>, <code>desktop</code>, <code>inactiveCaption</code>, <code>inactiveCaptionBorder</code>, <code>inactiveCaptionText</code>, <code>info</code>, <code>infoText</code>, <code>menu</code>, <code>menuText</code>, <code>scrollbar</code>, <code>text</code>, <code>textHighlight</code>, <code>textHighlightText</code>, <code>textInactiveText</code>, <code>textText</code>, <code>window</code>, <code>windowBorder</code>, <code>windowText</code>
<p>
an HTML-style colour code (e.g. <code>#2cbc1a</code> is a <span style='color: #2cbc1a'>shade of green</span>)
<p>
Since you don't know what the user's default colours are, you should set both foreground and background if you need control over colours.
Otherwise text might be illegible.
</dd>
<dt>
border
</dt>
<dd>
<code>inset</code> (same as <code>lowered</code>), <code>outset</code> (same as <code>raised</code>), <code>etched</code>, <code>line</code>, <code>none</code>
</dd>
<dt>
borderLayout
</dt>
<dd>
Where to put the component if its container has <code><span class='element'>layout</span>=<span class='string'>'borderLayout'</span></code>.
<p>
<code>north</code>, <code>south</code>, <code>east</code>, <code>west</code>, <code>centre</code>/<code>center</code>/<code>middle</code>
</p>
</dd>
<dt>
cursor
</dt>
<dd>
<code>crosshair</code>, <code>default</code>, <code>e_resize</code>, <code>hand</code>, <code>move</code>, <code>n_resize</code>, <code>ne_resize</code>, <code>nw_resize</code>, <code>s_resize</code>, <code>se_resize</code>, <code>sw_resize</code>, <code>text</code>, <code>w_resize</code>, <code>wait</code>, <code>none</code>, or a custom image which must be on classpath
</dd>
<dt>
cursorX
</dt>
<dd>
Horizontal click point for custom cursor (integer): default is <code>0</code>
</dd>
<dt>
cursorY
</dt>
<dd>
Vertical click point for custom cursor (integer): default is <code>0</code>
</dd>
<dt>
draggable
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
enabled
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
fontSize
</dt>
<dd>
(integer)
</dd>
<dt>
fontWeight
</dt>
<dd>
<code>ultrabold</code>, <code>extrabold</code>, <code>heavy</code>, <code>bold</code>, <code>medium</code>, <code>demibold</code>, <code>semibold</code>, <code>regular</code>, <code>demilight</code>, <code>light</code>, <code>extraLight</code>
</dd>
<dt>
fontUnderline
</dt>
<dd>
<code>lowDashed</code>, <code>lowDotted</code>, <code>lowGray</code>, <code>lowOnePixel</code>, <code>lowTwoPixel</code>, <code>on</code>
</dd>
<dt>
fontPosture
</dt>
<dd>
<code>oblique</code>, <code>regular</code>
</dd>
<dt>
foreground
</dt>
<dd>
Same colours as background.
<br>
Same comments as background.
</dd>
<dt>
layer
</dt>
<dd>
Which layer to put a component in.
Only makes sense if the component is a child of a <code class='element'>layeredpane</code>.
<p>
<code>default</code>, <code>palette</code>, <code>modal</code>, <code>popup</code>, <code>drag</code> or (integer)
</p>
</dd>
<dt>
minWidth
</dt>
<dd>
(integer)
</dd>
<dt>
minHeight
</dt>
<dd>
(integer)
</dd>
<dt>
opaque
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
popupMenu
</dt>
<dd>
the name of a popup menu to attach to this component
</dd>
<dt>
position
</dt>
<dd>
Where the component appears if it's in a <code class='element'>splitpane</code>.
Only makes sense if the component is a child of a <code class='element'>splitpane</code>.
<p>
<code>left</code>, <code>right</code>, <code>top</code>, <code>bottom</code>
</p>
</dd>
<dt>
preferredWidth
</dt>
<dd>
(integer)
</dd>
<dt>
preferredHeight
</dt>
<dd>
(integer)
</dd>
<dt>
tabIcon
</dt>
<dd>
An image to appear on a tab.
If not set, there is no image.
Only makes sense if the component is a child of <code class='element'>tabbedpane</code>
</dd>
<dt>
tabText
</dt>
<dd>
The text to appear on the tab.
If not set, defaults to the component's name.
If no name, the tab is blank.
Only makes sense if the component is a child of <code class='element'>tabbedpane</code>
</dd>
<dt>
visible
</dt>
<dd>
<code>true</code>, <code>false</code>
</dd>
<dt>
toolTip
</dt>
<dd>
(tool tip text)
</dd>
</dl>
</li>
<li id='refCommonEventHandlers'>
<h3>
Common event handlers
</h3>
<p>
All components share some common event handlers:
</p>
<ul>
<li>
onCaretUpdate* [<span title='optional' class='optional'>CaretEvent</span>]
</li>
<li>
onChange* [<span title='optional' class='optional'>ChangeEvent</span>]
</li>
<li>
onClick [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onComponentAdded [<span title='optional' class='optional'>ContainerEvent</span>]
</li>
<li>
onComponentRemoved [<span title='optional' class='optional'>ContainerEvent</span>]
</li>
<li>
onDoubleClick [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onFocusGained [<span title='optional' class='optional'>FocusEvent</span>]
</li>
<li>
onFocusLost [<span title='optional' class='optional'>FocusEvent</span>]
</li>
<li>
onInputMethod* [<span title='optional' class='optional'>InputMethodEvent</span>]
<p>
Input methods are used in languages such as Chinese where the number of characters is much greater than the number of keys on the keyboard.
</p>
</li>
<li>
onItemEvent* [<span title='optional' class='optional'>ItemEvent</span>]
<p>
This occurs when something is selected or deselected.
</p>
</li>
<li>
onKeyPressed [<span title='optional' class='optional'>KeyEvent</span>]
</li>
<li>
onKeyTyped [<span title='optional' class='optional'>KeyEvent</span>]
</li>
<li>
onMouseDragged [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onMouseEntered [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onMouseExited [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onMouseMoved [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onMousePressed [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onMouseReleased [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
onPropertyChange [<span title='optional' class='optional'>PropertyChangeEvent</span>]
</li>
<li>
onResized [<span title='optional' class='optional'>HierarchyEvent</span>]
</li>
</ul>
<p>
* The starred ones aren't really common.
Event handlers will only work for components that support them.
Elsewhere they are silently ignored.
But if you are writing a <code class='class'>Generator</code> for a component that should support these event handlers, they will automatically work.
</p>
</li>
<li id='refPaddingAndMargins'>
<h3>
Padding and margins
</h3>
<p>
Several components share the same padding and margin properties:
</p>
<dl>
<dt>
padding
</dt>
<dd>
(integer)
</dd>
<dt>
paddingTop
</dt>
<dd>
(integer)
</dd>
<dt>
paddingLeft
</dt>
<dd>
(integer)
</dd>
<dt>
paddingBottom
</dt>
<dd>
(integer)
</dd>
<dt>
paddingRight
</dt>
<dd>
(integer)
</dd>
<dt>
margin
</dt>
<dd>
(integer)
</dd>
<dt>
marginTop
</dt>
<dd>
(integer)
</dd>
<dt>
marginLeft
</dt>
<dd>
(integer)
</dd>
<dt>
marginBottom
</dt>
<dd>
(integer)
</dd>
<dt>
marginRight
</dt>
<dd>
(integer)
</dd>
</dl>
</li>
<li id='refKeyMappings'>
<h3>
Key mappings
</h3>
<p>
Keyboard shortcuts come from several places.
</p>
<ul>
<li>
Menu items can have an <code class='attrib'>accelerator</code> (useful in menu bar only - in popup menus, they have no effect, although they are displayed to the user).
</li>
<li>
A window can have an <code class='element'>accelerators</code> element that contains <code class='element'>accelerator</code> elements that map key strokes to actions in that window.
</li>
<li>
Individual components may already have their own key mappings in an <code class='class'>InputMap</code> and <code class='class'>ActionMap</code>.
For examples, a table has keyboard mappings defined by <code class='class'>JTable</code>.
When a component has focus, its own key mappings are used before the window-wide ones defined by menu items or an <code class='element'>accelerators</code> element.
In fact, a component may also define key mappings when any of its parents has focus, or when it is in a focussed window.
</li>
<li>
To fix that last one, a component can have a <code class='element'>keys</code> element.
</li>
</ul>
<p>
A component's own keyboard shortcuts do not come from your app descriptor, and may override your intentions.
You can fix this by adding <code class='element'>keys</code> sub-elements to any component.
Here's an example.
</p>
<pre>
<span class='marker'><</span><span class='element'>table</span> <span class='attrib'>columnSelectionAllowed</span><span class='marker'>=</span><span class='string'>'false'</span> <span class='attrib'>rowSelectionAllowed</span><span class='marker'>=</span><span class='string'>'true'</span><span class='marker'>></span>
<span class='comment'><-- something missing here - see below... --></span>
<span class='marker'><</span><span class='element'>keys</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>focused</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'HOME'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'selectFirstRow'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'END'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'selectLastRow'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'control C'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'copyRow'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'control INSERT'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'copyRow'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>focused</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>keys</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>actions</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>action</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'copyRow'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'copyRowFromTable'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>actions</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>table</span><span class='marker'>></span>
</pre>
<p>
The values for <code class='element'>stroke</code> must work for <a href='https://docs.oracle.com/en/java/javase/14/docs/api/java.desktop/javax/swing/KeyStroke.html#getKeyStroke(java.lang.String)'><code><span class='class'>KeyStroke</span>.getKeyStroke(<span class='class'>String</span>)</code></a>.
</p>
<p>
In this table, only row selection is allowed, and the <kbd>Home</kbd> and <kbd>End</kbd> keys move the selection.
The actions for these mappings are already defined by JTable so we have nothing else to define.
</p>
<p>
The app has an action, <code>copyRowFromTable</code>, defined in the <code class='element'>actions</code> element at the top of the descriptor.
We have to add it to the <code class='element'>actions</code> that this table knows about, and also map keys to it.
Notice that we can map multiple keys to the same action.
</p>
<p>
This example only has key mappings for when the table is <code class='element'>focused</code>.
The other options are <code class='element'>ancestor</code> and <code class='element'>window</code>.
</p>
<p>
There's a problem here.
Tables can have content defined in the descriptor, but the <code class='element'>table</code> element already has child elements where the content should go.
So you can specify a <code class='element'>content</code> element like this.
Indeed, you <strong>must</strong>, even if it's empty.
</p>
<pre>
<span class='marker'><</span><span class='element'>table</span> <span class='attrib'>columnSelectionAllowed</span><span class='marker'>=</span><span class='string'>'false'</span> <span class='attrib'>rowSelectionAllowed</span><span class='marker'>=</span><span class='string'>'true'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>content</span><span class='marker'>></span>
Product |Stock |Price
Cat food |1,234 tins |£1.23
Dog biscuits|234 bags |£2.34
Fish flakes |432 packets|£0.85
<span class='marker'></</span><span class='element'>content</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>keys</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>focused</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'HOME'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'selectFirstRow'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'END'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'selectLastRow'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'control C'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'copyRow'</span> <span class='marker'>/></span>
<span class='marker'><</span><span class='element'>key</span> <span class='attrib'>stroke</span><span class='marker'>=</span><span class='string'>'control INSERT'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'copyRow'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>focused</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>keys</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>actions</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>action</span> <span class='attrib'>name</span><span class='marker'>=</span><span class='string'>'copyRow'</span> <span class='attrib'>action</span><span class='marker'>=</span><span class='string'>'copyRowFromTable'</span> <span class='marker'>/></span>
<span class='marker'></</span><span class='element'>actions</span><span class='marker'>></span>
<span class='marker'></</span><span class='element'>table</span><span class='marker'>></span>
</pre>
</li>
</ol>
</li>
<li id='faq'>
<h2>
FAQ
</h2>
<div class='callout'>
<p>
If the question troubling you isn't answered here, see the end of this page for <a href='#morehelp'>how to get more help</a>.
</p>
</div>
<dl>
<dt>How can I get the descriptor from somewhere else?</dt>
<dd>
Your app class can override <code>getDescriptor</code> to get the XML from anywhere you like.
If you do this, you probably want to include a call to <code>replaceIncludes</code>, but it's optional.
</dd>
<dt>Can I use my own/other people's custom Swing components?</dt>
<dd>
Yes, but you may need to write <code>Generator</code>s for them.
Have a look at the <a href='#customcomponents'>custom components</a> section of the documentation
</dd>
<dt>I can't get part of my UI right because Compositor won't let me... [ <small>use the right layout manager</small> | <small>use SWT components</small> | <small>whatever</small> ]</dt>
<dd>
You can always render part of your UI in plain old Java code.
One way to do this would be to subclass PanelGenerator, just overriding <code>finishMaking</code> where you add components to the panel, doing whatever you feel that Compositor won't let you do.
Then <a href='#declaring'>add this as a custom component</a> and use it in your UI.
</dd>
<dt>How do I get the effect I want with the layout managers available?</dt>
<dd>
A general approach is to break the layout down into smaller and smaller sections, nesting more and more panels/scroll panes/split panes until it works.
You can also read the <a href='layout.html'>layout help</a> that accompanies this page.
</dd>
<dt>How do I choose which type of <a href='#commoncode'>common descriptor code</a> to use?</dt>
<dd>
<ul>
<li>
If you want to apply the same attributes to all widgets of the same type, use <a href='#commonattributes'>common attributes</a>.
</li>
<li>
If you want identical repeated sections, but you don't know how many until run time, use <a href='#clones'>clones</a>.
</li>
<li>
If you want identical repeated sections, and you know how many there will be, use <a href='#entitymacros'>entity macros</a>.
</li>
<li>
If you want repeated sections, but you want to be able to replace some attribute values, use <a href='#includemacros'><code class='element'>include</code> macros</a>.
</li>
<li>
If you want to share some of your UI widgets (and their behaviour) between apps, use <a href='#delegates'>delegates</a>.
</li>
<li>
If you want to break down a large UI or a big app class into more manageable chunks, use <a href='#delegates'>delegates</a> for that too.
</li>
<li>
If you want to make a custom component out of other existing components, use <a href='#delegates'>delegates</a> for that too.
</li>
</ul>
</dd>
<dt>Do I <em>have</em> to prefix the names of "<a href='#referringtocomponents'>magic</a>" fields with <code>x_</code></dt>
<dd>
No.
Although the examples all use this convention, <code>windowName_widgetName</code> works just as well as <code>x_windowName_widgetName</code>.
</dd>
<dt>If I don't put text in a [<code>label</code>|<code>combobox</code>|etc.] because it will get populated at run time, how do I stop it being much too small?</dt>
<dd>
If a text component is loaded with no text, it may take up almost no space in the layout.
<ul>
<li>
One way to fix this is to put some dummy text in the descriptor.
The component will get rendered large enough for the dummy text, and if you chose sensibly, that can be large enough for the text that replaces it at run time.
</li>
<li>
Another way would be to put the component inside a panel with <code>borderLayout</code>.
Then it will fill the available space in the panel.
The component will also resize if the panel is resized.
</li>
<li>
A third way is to add <code>preferredHeight</code> and <code>preferredWidth</code> attributes.
</li>
</ul>
</dd>
<dt>Why don't my components line up sensibly with [<code>boxLayoutX</code>|<code>boxLayoutY</code>]?</dt>
<dd>
Each component lines up in a default way.
The defaults provided by Swing can be... interesting.
You can fix this with the attribute <code>alignmentX</code> or <code>alignmentY</code>.
</dd>
<dt>Are there any security risks?</dt>
<dd>
<ul>
<li>
Java may have security issues.
Compositor can't control that.
You should always update to the latest release.
There are tools to help with this.
</li>
<li>
In theory, it's possible to mess with a Compositor UI, which could have security implications.
<br>
<br>
To change the UI of a Compositor app, you change its descriptor (the XML that defines the UI), and the descriptor is loaded from the classpath, so if an app is distributed as a jar file, you could change the UI by adding a location to the beginning of the classpath and putting an alternate descriptor there.
The app will still work (as long as you keep the original window and widget names and types) but will look different to the user.
<br>
<br>
This might conceivably be a good thing.
A skilled user might adjust a UI to their preference.
But it may also be possible to use this knowledge maliciously.
For example, imagine switching the locations of privacy options in a client for a social network.
The user thinks their post is visible to a small group when in fact it is public.
<br>
<br>
How can we prevent this?
It's possible to start a Java app with any command line you like, including a custom classpath.
But in order to exploit this, an attacker needs to induce the user to run an app with their own command line options.
In that case, I don't think that Compositor is opening a bigger attack surface than is already available.
</li>
</ul>
</dd>
<dt>Why aren't focus handlers consistently named?</dt>
<dd>
<p>
For frames and dialogs, you can define focus event handlers <code>window__onGainedFocus</code> and <code>window__onLostFocus</code>.
On other components, it's <code>window_widget_onFocusGained</code> and <code>window_widget_onFocusLost</code>.
How come?
</p>
<p>
Well, for a window, Compositor adds a <code class='class'>WindowFocusListener</code>, but for a component it's <code class='class'>FocusListener</code>, and Compositor follows the naming of methods on those listener classes.
</p>
<p>
The handlers (and the listeners) also take different event parameters.
The two things seem similar, but not directly related (according to Swing, at least).
</p>
</dd>
<dt id='textComponentFromDocEvent'>How can I get hold of a text component from a document event?</dt>
<dd>
<p>
Text components (<a href='#refEditorpane'>editorpane</a>, <a href='#refTextarea'>textarea</a>, <a href='#refTextfield'>textfield</a>) all maintain their text content as a <code>Document</code>.
The insert and remove events for these components receive a <code>DocumentEvent</code> parameter.
Event objects will usually tell you the source of the event, but not <code>DocumentEvent</code>.
This may be a problem if you want to find the UI component where the event occurred (for example, because you have a <a href='#wildcards'>wild card method</a> that handles events on many components).
</p>
<p>
Compositor lets you retrieve the UI component from the document like this:
</p>
<pre><span class='keyword'>public void</span> window_textFields$_onInsert( <span class='class'>DocumentEvent</span> e ) {
<span class='class'>JTextField</span> textField = ( <span class='class'>JTextField</span> ) e.getDocument()<span class='highlight'>.getProperty( TextComponentGenerator.COMPONENT_KEY )</span>;
}</pre>
</dd>
</dl>
</li>
<li id='morehelp'>
<h2>
Need more help?
</h2>
<p>
That's the end of the documentation.
</p>
<p>
If you need more help, you can try <a href='http://sourceforge.net/projects/compositor/support'>getting in touch at SourceForge</a>.
</p>
</li>
</ol>
<hr>
<p style='float: right'>
<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img width='88' height='31' src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!"></a>
</p>
</body>
</html>