<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<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'>
<style type='text/css'>
* { margin: 0; padding: 0 /*; border: 1px dashed red */ }
ul, ol, dd { margin-left: 2em }
#panel, #contents { position: fixed; width: 225px }
#panel { left: 2em; top: 0; bottom: 0 }
#contents { top: 221px; bottom: 0; overflow: auto }
#logo { margin: 50px }
#intro, #content, #news { margin-left: 225px }
#intro { margin-top: 2em; margin-bottom: 2em; margin-right: 2em }
#content { padding-left: 1em; padding-right: 1em }
hr { margin: 2em 100px 2em 300px }
body { background: #fefefe; color: black; padding: 2em 4em; font-family: sans-serif }
h1 { color: maroon }
#intro q { font-style: italic; font-weight: bold; color: maroon }
h2, h3 { color: #003 }
h2, h3, h4, h5, h6 { font-family: 'Times New Roman', serif }
h2, h3, h4, h5, h6, p { margin: 2ex 0 }
p, li { text-align: justify }
h2 { margin-top: 1em; padding: 0.5ex }
h4 { font-style: italic; color: navy; font-variant: small-caps }
.methods h4, .classes h4 { font-style: normal; font-variant: normal; font-family: monospace }
span.comment { color: #008000 }
span.marker { color: #0000ff }
span.element, code.element, col.element { color: #606000; font-family: monospace }
span.attrib, code.attrib { color: #800040 }
span.string { color: #ff00ff }
span.number { color: #cc00cc }
span.keyword, code.keyword { color: #0000ff }
span.class, code.class, col.class { color: #990000; font-family: monospace }
span.optional { font-size: small; font-style: italic; color: #aaaaaa }
pre { border: 1px solid silver; padding: 1em; overflow: auto; background: white; }
table { border-collapse: collapse; }
th, td { border: 1px solid silver; padding: 0.25em }
th { color: black; font-family: sans-serif; text-align: left }
#contents h2 { text-align: center; margin: 0; color: maroon; font-family: sans-serif }
#contents li { font-weight: normal; padding: 0.25ex 0 }
#contents li li { font-size: 90% }
#contents li li li { font-size: 80% }
#contents li { text-align: left }
ul li { margin: 0.75ex 0 }
dt { font-weight: bold }
dd { margin-bottom: 0.5em }
a img { border: 1px white solid }
a img:hover { border: 1px outset }
dl { margin-left: 1em }
.noscript { padding: 0 1em; font-size: 9pt; font-style: italic }
div.callout { border: 1px solid gray; margin-left: 1em; padding: 0 1em; font-style: italic; background: #eee; float: right; width: 15em }
div.callout p:before { content: "Note"; font-weight: bold; display: block; margin-bottom: 0.25em }
p.warning:before { content: "Warning!"; font-weight: bold; font-size: 80% }
p.warning { border: 1px solid silver; background: #ffffe6; padding: 0.5em }
</style>
<script type='text/javascript'>
function initContents ()
{
for ( var i = 0; i < document.images.length; i++ )
{
var img = document.images [ i ]
if ( img.src.match ( 'resources/expand\.png$' ) )
{
img.style.display = 'inline'
}
}
}
function viewList ( source )
{
var elem = source
var img = source
if ( 'IMG' == elem.nodeName )
{
elem = elem.parentNode
}
else
{
img = elem.firstChild
}
for ( var i = 0; elem && i < 5; i++ )
{
elem = elem.nextSibling
if ( elem && ( 'OL' == elem.nodeName || 'UL' == elem.nodeName ) )
{
var d = elem.style.display
if ( d && 'none' == d )
{
elem.style.display = 'block'
img.src = 'resources/collapse.png'
}
else
{
elem.style.display = 'none'
img.src = 'resources/expand.png'
}
break
}
}
return false
}
</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>
</div>
<div id='panel'>
<img id='logo' src='resources/logo.png' width='138' height='135' border='0' alt=''>
<p style='display: none'>
<a href='#content'>Skip navigation</a>
</p>
<div id='contents'>
<h2>
Contents
</h2>
<ol>
<li>
<a href='#whatis'>What is Compositor?</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' style='display: none'></a>
<ul style='display: none'>
<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='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#building'>Building Compositor from source</a>
</li>
</ul>
</li>
<li>
<a href='#howto'>Writing a simple Compositor app</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' 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>
</ol>
</li>
<li>
<a href='#referringtocomponents'>Referring to components from code</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' 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>
</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='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' 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='resources/expand.png' alt='' border='0' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#methodsthatmighthelp'>Methods</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' style='display: none'></a>
<ul style='display: none'>
<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='#writeStatus'>writeStatus</a>
</li>
</ul>
</li>
<li>
<a href='#classesthatmighthelp'>Classes</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' 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='#imagecomparer'>ImageComparer</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='#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='#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='#logging'>Logging</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='resources/expand.png' alt='' border='0' style='display: none'></a>
<ul style='display: none'>
<li>
<a href='#examples'>Examples</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' style='display: none'></a>
<ol type='i' style='display: none'>
<li>
<a href='#calx'>Calx</a>
</li>
<li>
<a href='#decoder'>Decoder</a>
</li>
<li>
<a href='#dismatch'>Dismatch</a>
</li>
<li>
<a href='#dixtionary'>Dixtionary</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='#ftree'>FTree</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='#multiedit'>MultiEdit</a>
</li>
<li>
<a href='#namebug'>NameBug</a>
</li>
<li>
<a href='#quircus'>Quircus</a>
</li>
<li>
<a href='#ratedate'>RateDate</a>
</li>
<li>
<a href='#retest'>RETest</a>
</li>
<li>
<a href='#showgc'>ShowGc</a>
</li>
<li>
<a href='#sidetabs'>SideTabs</a>
</li>
<li>
<a href='#simpleedit'>SimpleEdit</a>
</li>
<li>
<a href='#spsh'>Spsh</a>
</li>
<li>
<a href='#tilex'>Tilex</a>
</li>
<li>
<a href='#why'>Why</a>
</li>
<li>
<a href='#wwx'>WWX</a>
</li>
<li>
<a href='#xibbon'>Xibbon</a>
</li>
<li>
<a href='#xibbonmacro'>XibbonMacro</a>
</li>
<li>
<a href='#xide'>Xide</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='resources/expand.png' alt='' border='0' 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='#jython'>Jython</a>
</li>
<li>
<a href='#clojure'>Clojure</a>
</li>
<li>
<a href='#jruby'>JRuby</a>
</li>
<li>
<a href='#anythingelse'>Anything else</a>
</li>
</ul>
</li>
<li>
<a href='#reference'>Reference material</a> <a href='#.' onclick='viewList ( this )'><img src='resources/expand.png' alt='' border='0' style='display: none'></a>
<ol type='i' style='display: none'>
<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='#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='#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='#refPanel'>panel</a>
</li>
<li>
<a href='#refPassword'>password</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='#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='#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'>FAQ</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>
<div id='news' style='font-size: small'>
<h2 style='margin: 0; padding: 0'>News:</h2>
<ul>
<li>
<a href='https://sourceforge.net/projects/compositor/files/0.4/'>0.4 available for download</a>
</li>
</ul>
</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>
Why bother?
Writing a simple UI for a Swing 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='hasntthis'>
<h3>
Hasn't this been done before?
</h3>
<p>
There are several other similar projects.
Thinlets and SwiXML are 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 XML descriptor translates fairly obviously into GUI 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 and Scala, but any language that runs in the JVM 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 with <a href='http://ant.apache.org/ivy/'>Ivy</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 things you probably shouldn't try to do are:
<ul>
<li>syntax coloured editor</li>
<li>HTML rendering (beyond the very basic support provided by <code><editorpane contentType='text/html'></code>)</li>
<li>image editor</li>
</ul>
To build those kind 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>
<p>
You can download <a href='https://sourceforge.net/projects/compositor/files/'>stable Compositor releases from SourceForge</a>.
There is a jar file which is all you need to use Compositor, but the full source distribution is recommended so that you can examine the <a href='#exampleapps'>examples</a>, try you own apps in the <a href='#playarea'>playarea</a>, and build the Javadoc.
(Added bonus: Compositor includes a alternative doclet, <a href='#smokedoc'>SmokeDoc</a> - see the <code>build.xml</code> for an example of use)
</p>
<p>
The latest source is also available from the <a href='https://sourceforge.net/projects/compositor/develop'>Compositor git repository</a>.
It should compile and work because it's in use all the time, but you never know...
</p>
<ul>
<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.
The only other thing you'll need is <a href='http://ant.apache.org/'>Ant</a>.
When Ant is installed and you can you can run it successfully (e.g. <kbd>ant -h</kbd> works), then do this:
</p>
<pre>cd [wherever you put compositor]
cd build
ant</pre>
<p>
The default is to compile and test.
To list other ant targets: <kbd>ant -p</kbd>
</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>
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>
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 Java 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 intention 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 - 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 <code><span class='class'>KeyStroke</span>.getKeyStroke(<span class='class'>String</span> s)</code>.
</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>.
</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'>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='keyword'>new </span>MyApp();
}
<span class='comment'>// We must define a method like this to handle the "boo" action.</span>
<span class='keyword'>public void </span>doBoo()
{
<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 a <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 - 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 <code class='element'>panel</code> 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 <code class='element'>splitpane</code> element (which generates a <code class='class'>JSplitPane</code>).
This divides two components so that the user can move the divider.
</p>
<p>
A <code class='element'>scrollpane</code> (which generates a <code class='class'>JScrollPane</code>) is a container for a single component, and provides scrolling as required.
</p>
<p>
A <code class='element'>tabbedpane</code> (which generates <code class='class'>JTabbedPane</code>) shows components grouped under tabs.
</p>
<p>
A <code class='element'>grid</code> (which generates <code class='class'>JPanel</code> with <code class='class'>GridBagLayout</code>) shows components in rows and columns.
</p>
<p>
A <code class='element'>buttonpanel</code> (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 all of the Compositor elements to Swing components.
</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>
<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>
</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='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'>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>
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> 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> doFoo( <span class='keyword'>final</span> <span class='class'>ActionEvent</span> e )
{
<span class='comment'>// Do something...</span>
}</pre>
<p>
In many cases you won't need the event parameter, so this works too:
</p>
<pre><span class='keyword'>public void</span> doFoo()
{
<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 labels 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'>'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> main_below_onClick( <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> main_below_onClick()
{
msgBox( <span class='string'>"You clicked a label!"</span> );
}</pre>
<p>
If you want several components to respond to events in the same way, you can use <code>$</code> as a wild card.
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>
An event on a frame or dialog has no widget, 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> main__onLoad()
{
<span class='comment'>// Do some initialisation here...</span>
}</pre>
</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> main_below;
<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> + x_main_below.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 = getFrame( <span class='string'>"myFrameName"</span> );</code>
</dd>
<dt id='dialogs'>
Dialogs
</dt>
<dd>
<code><span class='class'>JDialog</span> myDialog = getDialog( <span class='string'>"myDialogName"</span> );</code>
</dd>
<dt id='windows'>
Windows
</dt>
<dd>
<code><span class='class'>Window</span> myWindow = getWindow( <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 = getMenu( <span class='string'>"myMenuName"</span> );</code>
</dd>
<dt id='toolbars'>
Tool bars
</dt>
<dd>
<code><span class='class'>JToolBar</span> myToolBar = getToolBar( <span class='string'>"myToolBarName"</span> );</code>
</dd>
<dt id='actions_2'>
Actions
</dt>
<dd>
<code><span class='class'>CompositorAction</span> myAction = getAction( <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 = get( <span class='string'>"myFrameOrDialog.myComponentName"</span> ).getComponent();</code>
</li>
<li>
<code>CompositorComponent myComponent = get( <span class='string'>"myFrameOrDialog.myComponentName"</span> );</code>
</li>
<li>
<code><span class='class'>JComponent</span> myComponent = myFrameOrDialog_myComponentName; <span class='comment'>// ...if 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'>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'>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'>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='comment'>// Set up the dialog contents.</span>
x_showMsg_msg.setText( <span class='string'>"Hello world"</span> );
<span class='comment'>// Show the dialog.</span>
showDialog( 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> showMsg_ok_onPress( <span class='keyword'>final</span> <span class='class'>ActionEvent</span> e )
{
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='keyword'>public void</span> run()
{
<span class='comment'>// This code is on another thread, so can call UI updates like this:</span>
invokeLater( <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='class'>EventQueue</span>.invokeLater ( <span class='keyword'>new</span> <span class='class'>Runnable</span> () { <span class='keyword'>public void </span>run () {
setMessage( <span class='string'>"Done."</span> );
} } );
<span class='comment'>// This way is more verbose, but type-safe, and</span>
<span class='comment'>// 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> newItem = <span class='keyword'>new</span> <span class='class'>JMenuItem</span>( menuText );
newItem.addActionListener
(
new <span class='class'>ActionListener</span>()
{
<span class='keyword'>public void</span> actionPerformed( <span class='keyword'>final</span> <span class='class'>ActionEvent</span> e )
{
<span class='comment'>// Do whatever's appropriate</span>
}
}
);
getMenu( <span class='string'>"myFrameName_myMenuName"</span> ).add( newItem );
}</pre>
</li>
<li id='commoncode'>
<h3>
Common descriptor code
</h3>
<p>
As an app grows in complexity, its descriptor 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'>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> widgets
<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>
&widgets;
<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>
&widgets;
<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 include macros.
The idea here is that you put the structure of the repetitious part in a separate file, then include it with (optional) customisations.
Here's the same pet example done with include 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'>forEach</span> <span class='attrib'>tag</span>=<span class='string'>'p:dlg'</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>dialog</span> <span class='attrib'>name</span>=<span class='string'>'${dlgName}'</span> <span class='attrib'>title</span>=<span class='string'>'${dlgTitle}'</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 ${petType=pet}:<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 <code class='element'>forEach</code> part.
For each <code class='element'>p:dlg</code> tag you nest in the include in your descriptor, the contents of the <code>forReach</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 include 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'>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'>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 include 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'>clones</span><span class='marker'>></span>
<span class='marker'><</span><span class='element'>scrollpane </span><span class='attrib'>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 "file" 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>) buildClone( <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>) buildClone( <span class='string'>"fileWidget"</span>, <span class='string'>"main"</span>, main_files, widgetName );
}</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 you main app class, which may grow large as your app gains funtionality.
</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'>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 delegate class here is <code>com.example.SomeDialog</code> so its descriptor will be <code>SomeDialog.xml</code>.
The class would look like this.
</p>
<pre><span class='comment'>// package, imports</span>
<span class='keyword'>public class</span> SomeDialog
<span class='keyword'>extends</span> Delegate
{
<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 descriptor for a frame or dialog delegate is not very different from what you would put in an app descriptor, except the frame/dialog is wrapped in a uifragment element.
Here's an example.
</p>
<pre><span class='marker'><</span><span class='element'>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'>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 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> Delegate
{
<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 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'>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 worfk, 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>
</ul>
</li>
<li id='environmentvariables'>
<h3>
Environment variables
</h3>
<p>
Besides dollar-curly variables in <a href='#includemacros'>include 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 form 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'>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 setting, 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.util.compositor.<span class='class'>TextFieldGenerator</span></code>.
</li>
<li>
Otherwise, write you own class extending <code class='class'>Generator</code> overriding whichever methods are appropriate.
<dl>
<dt>Constructor</dt>
<dd>
Must take an <code class='class'>App</code> parameter.
Can take a <code class='class'>String</code> class name parameter - if not, the class is assumed by the generator.
Must call the superclass constructor, passing the app and a class name.
</dd>
<dt><code>setAttributes</code></dt>
<dd>
Takes a bunch of parameters - allows you to handle attributes from the descriptor and call appropriate methods on the component that is being generated
You only need to implement this method if you have some attributes to handle.
</dd>
<dt><code>addListener</code></dt>
<dd>
This generator method is called once for each app method that is named correctly for a component.
You should decide if the method is handled by the app - just because an app has <code>..._onFoo</code> doesn't mean that your component will respond.
Then add appropriate listeners which will call the app method.
You only need to implement this method if you have some events to listen for.
</dd>
<dt><code>finishMaking</code></dt>
<dd>
This method is called after the component has been built, and (if it's a container) after all it's 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><code>setContent</code></dt>
<dd>
If your component doesn't have a setText method, implement this in your generator.
</dd>
</dl>
</li>
<li>
If your component responds to some unusual events, your generator might need an <code>addListener</code> method to ensure that the right event handller method is called.
See the existing generators for how this works.
</li>
</ul>
<p>
Handling user interaction with 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>How to refer to this component in your UI descriptor - an XML namespace will prevent tears later<br>(required)</dd>
<dt><code class='attrib'>generator</code></dt>
<dd>A class name for your <code class='class'>Generator</code><br>(required)</dd>
<dt><code class='attrib'>class</code></dt>
<dd>The class name of the component<br>(optional - depends if the generator's constructor needs it)</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'>'c:tfwm'</span>
<span class='attrib'>generator</span><span class='marker'> = </span><span class='string'>'net.sf.compositor.util.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'>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]_onDragGestureRecognized( <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]_onDrop( <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> );
}
[catch blocks]
}</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]_onDragOver( <span class='keyword'>final</span> <span class='class'>DropTargetDragEvent</span> e )
<span class='keyword'>public void</span> [window]_[component]_onDropActionChanged( <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]_onDragEnter( <span class='keyword'>final</span> <span class='class'>DropTargetDragEvent</span> e )
<span class='keyword'>public void</span> [window]_[component]_onDragExit( <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 - 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 override <code>storeState</code> and <code>restoreState</code>, and data class methods that perform undoable edits must create a <code class='class'>StateEdit</code> object, something like this:
</p>
<pre><span class='comment'>// Create an edit</span>
<span class='keyword'>final</span> <span class='class'>StateEdit</span> edit = <span class='keyword'>new</span> <span class='class'>StateEdit</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>
edit.end();
<span class='comment'>// Post the edit to the undo system</span>
m_undoSupport.postEdit( edit );
</pre>
</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>
<ul>
<li id='methodsthatmighthelp'>
<h3>
Methods
</h3>
<p>
All of these are inherited from <code>App</code> so you can call them anywhere in your app.
They're listed in alphabetical order.
</p>
<ul class='methods'>
<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>
A common use for this is to restore focus.
If the user clicked a toolbar button, the button willl 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> ( ask (
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'>protected void</span> beforeUIBuilt () {
readWriteConfig( somePath, config, VERSION );
runAfterUiBuilt( new <span class='class'>Runnable</span>() { <span class='keyword'>public void</span> run() {
<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> + getAppName() + <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( getKeyDetails( keyEvent ) );
log.debug( getKeyListeners( 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> handleEventQueueException( <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 is 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 calls a method on your app by name by posting 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().invokeLater(
<span class='string'>"commandLineHandler"</span>, <span class='keyword'>new</span> <span class='class'>Object</span>[]{ 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>
</li>
<li>
<h4 id='msgBox'>
msgBox
</h4>
<p>
These methods produces 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 ResourceLoader, 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 at shutdown.
</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 you 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>
<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>
<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 grphical rather than text, these methods won't help you.
</p>
</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 itself to you component as a <code>StatusTarget</code> 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 them in rough order of usefulness, but obviously that's subjective.
</p>
<ul class='classes'>
<li>
<h4 id='actiondelayer'>
ActionDelayer
</h4>
<p>
This 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 repsond.
</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 =
new ActionDelayer( <span class='number'>500</span> );
<span class='keyword'>public void</span> main_list_onSelect() {
m_selectDelayer.delay (
new <span class='class'>Runnable</span>() {
<span class='keyword'>public void</span> run() {
invokeLater( <span class='string'>"delayedListSelect"</span> );
}
}
);
}
<span class='keyword'>public 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 = ResourceLoader.getImage( 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 = ResourceLoader.readUTF8File( 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">'c:fileTree'</span>
<span class="attrib">generator</span>=<span class="string">'net.sf.compositor.FileTreeGenerator'</span>
<span class="attrib">class</span>=<span class="string">'net.sf.compositor.FileTree'</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">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: copy, move, rename, mkdir and delete.
Its advantage is that these operations use <code>java.nio</code> from Java 1.7 on wards, but <code>java.io</code> for earlier versions.
Its disadvantage is that it doesn't fully implement all those operations (yet).
</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> <span class="class">MyAppConfig</span> s_config = new <span class="class">MyAppConfig</span>();
<span class="keyword">@Override
protected void</span> beforeUIBuilt() {
readWriteConfig(
Env.USER_HOME + Env.FILE_SEP + <span class="string">"myapp.properties"</span>,
s_config,
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 (not ISO friendly)
</li>
<li>
the amount of time elapsed between to 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='imagecomparer'>
ImageComparer
</h4>
<p>
This class compares images.
It's useful in tests.
</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="keyword">new</span> Info (
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 },
},
<span class="keyword">new</span> Info.Extras (
<span class="string">"Showing \"About\" box..."</span>,
this,
mapToShowOnDialog,
getSysProps(), <span class="comment">// Displays behind "more" button</span>
<span class="keyword">new</span> <span class="class">ImageIcon</span>( getFrame( <span class="string">"main"</span> ).getIconImage() )
)
);
}</pre>
<p>
The resulting dialog would look something like this (on Windows XP, classic theme):
</p>
<img src='resources/infodialog.png' alt='[dialog image]' title=''>
</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> {
NativeEditor.open( <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 text editor.
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> {
NativeBrowser.open( someUrl );
} <span class="keyword">catch</span> ( <span class="keyword">final</span> <span class="class">IOException</span> x ) {
msgBox( x_main, <span class="string">"Could no open URL:"</span> + Env.NL + x.getMessage () );
}</pre>
<p>
See also <a href='#nativeeditor'><code>NativeEditor</code></a>
</p>
</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="attrib">class</span>=<span class="string">'net.sf.compositor.RotatedLabel'</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.
A case 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='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>StackPropbe.getMyClass()</code>.
</p>
<p>
Similarly, <code>StackPropbe.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='logging'>
Logging
</h4>
</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.
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
java -cp .;..\classes;..\resources Examples</pre>
</li>
<li>
Everyone else:
<pre>cd pathToCompositor/examples
java -classpath .:../classes:../resources Examples</pre>
</li>
</ul>
<ul>
<li id='examples'>
<h3>
Examples
</h3>
<ol type='i'>
<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='dismatch'>
<h4>
Dismatch
</h4>
<p>
This app searches for matching files, including simple image comparison, so that you can delete duplicates.
</p>
<p>
You can <a href='http://j_banana.users.sourceforge.net/ws/dismatch/dismatch.jnlp'>run Dismatch by WebStart</a>.
</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>
<p>
You can <a href='http://j_banana.users.sourceforge.net/ws/dixtionary/dixtionary.jnlp'>run Dixtionary by WebStart</a>.
</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 handlle 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 freedback with the appropriate mouse cursor.
</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 <code>FileOps</code> to manipulate the file system
</li>
<li>
how to use a <code>FileTree</code> to display a directory structure
</li>
<li>
how to use <code>ActionDelayer</code> to allow multiple user inputs before reacting to them
</li>
<li>
how to use <code>Configurator</code> with a settings dialog
</li>
<li>
how to use <code>FileGrid</code> to display files
</li>
<li>
how to use <code>Roller</code>, an alternative to tabs for switching between components
</li>
</ul>
</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 know game, just for fun.
</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='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='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='quircus'>
<h4>
Quircus
</h4>
<p>
Qu<em><strong>e</strong></em>rcus is Latin name for oak trees.
Qu<em><strong>irc</strong></em>us is a little IRC client.
</p>
<p>
I've used IRC for a long time via the Opera browser's built-in client.
I thought I'd have a go at writing a client.
</p>
<p>
You can <a href='http://j_banana.users.sourceforge.net/ws/quircus/quircus.jnlp'>run Quircus by WebStart</a>.
</p>
</li>
<li id='ratedate'>
<h4>
RateDate
</h4>
<p>
You can rate whatever you like against dates and times.
</p>
<p>
This is a simple example of extending <a href='#filebasedapps'><code>FileApp</code></a>.
</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>
<p>
You can <a href='http://j_banana.users.sourceforge.net/ws/retest/retest.jnlp'>run RETest by WebStart</a>.
</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>
<p>
You can <a href='http://j_banana.users.sourceforge.net/ws/showgc/showgc.jnlp'>run ShowGc by WebStart</a>.
</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 vary 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='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='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='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='why'>
<h4>
Why
</h4>
<p>
This is an example of how little you need do to get a working UI.
It is inspired by a Ruby-based project called Shoes that did some similar things to Compositor.
The name comes from WhyTheLuckyStiff, the <span lang='fr' style='font-style: italic' title='pen name'>nom de plume</span> of the person behind Shoes.
</p>
<p>
Starting minimal is good.
Don't try to get everything working at the start.
</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 most web sites.
</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='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='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 <code>cd...</code> button 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 Java code, but you are using a language other than 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 instatiates 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='jython'>Jython</dt>
<dd>
<p>
Make a class that extends AppJython and instatiate 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='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='refAction'>
<h3>
action
</h3>
<p>
An action can only de 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 correspoding 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'>action</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.
</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>
Radio 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>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>
</dd>
<dt>
fill
</dt>
<dd>
<code>none</code>, <code>horizontal</code>, <code>vertical</code>, <code>both</code>
</dd>
<dt>
weightX
</dt>
<dd>
(number)
</dd>
<dt>
weightY
</dt>
<dd>
(number)
</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 radio button 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='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>
<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 won 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>
</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'>component</a>
</li>
<ul>
</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>
</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>
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:
<br>
<br>
<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>
</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 - <code>text/html</code> and <code>application/rtf</code> should work.
</dd>
</dl>
<h4>
Content
</h4>
<p>
The text that appears in the pane
</p>
</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>
</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 <code class='element'>accelerators</code> element, containing <code class='element'>accelerator</code> 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 <code class='element'>menubar</code> element containing <code class='element'>menu</code> elements with a <code class='attrib'>label</code> attribute and an optional <code class='attrib'>name</code> attribute.
These in turn contains <code class='element'>menuitem</code> elements with an optional <code class='attrib'>action</code> attribute and an optional <code class='attrib'>accelerator</code> accelerator attribute.
Menu items with no attributes produce a separator.
</li>
<li>
Optional <code class='element'>popupMenus</code> element containing <code class='element'>popupMenu</code> 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>
<h4>
Properties
</h4>
<dl>
<dt>
layout, align, gridRows, gridCols, gridHGap, gridVGap
</dt>
<dd>
See <a href='#refPanel'>panel</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>.
</p>
<p>
Glue can be useful if you want to have something centred horizontally or vetically: you can put glue on either side of the centred component.
</p>
<p>
You can also use an empty panel with border layout in trhis 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>
<code class='element'>row</code> elements, which in turn contain <code class='element'>cell</code> 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
</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 include the markup in a CDATA section so that it is seen as the content on 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>![CDATA[<html>
<style>
body{font-family:monospace}
</style>
<body>
<h1>Yay!</h1>
<p>
<em>Fancy</em> text
</p>
</body>
</html>]]<span class='marker'>></</span><span class='element'>label</span><span class='marker'>></span></pre>
<h4>
Notes
</h4>
<p>
An example of how to display an icopn 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>
</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>
</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|dog|fish<span class='marker'></</span><span class='element'>list</span><span class='marker'>></span></pre>
</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>
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='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.getValue()</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>
Cells
</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>
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>
hScrollUnitIncremement
</dt>
<dd>
(integer)
</dd>
<dt>
vScrollUnitIncremement
</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>
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>
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='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.
</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>
(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'>TreeSelectionEvent</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>
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).
To respond to text changes, handle both onInsert and onRemove.
</li>
</ul>
<h4>
Content
</h4>
<p>
Initial content of the text field
</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>
<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='#refActions'>actions</a>
</li>
<li>
<a href='#refComponents'>components</a>
</li>
<li>
<a href='#refWindows'>windows</a>
</li>
</ul>
</li>
<li id='refWindows'>
<h3>
windows
</h3>
<h4>
Content
</h4>
<ul>
<li>
<a href='#refFrame'>frame</a>
</li>
<li>
<a href='#refDialog'>dialog</a>
</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> - default alignments are sometimes peculiar
</dd>
<dt>
alignmentY
</dt>
<dd>
(floating point, 0 to 1)<br>
Zero means "top".
Useful with <code>boxLayoutX</code> - 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>
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.
</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>, or a custom image which must be on classpath
</dd>
<dt>
cursorX
</dt>
<dd>
Horizontal click point for custom cursor (integer)
</dd>
<dt>
cursorY
</dt>
<dd>
Vertical click point for custom cursor (integer)
</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>palette</code>, <code>default</code>, <code>drag</code>, <code>modal</code>, <code>popup</code> or (integer)
</p>
</dd>
<dt>
minWidth
</dt>
<dd>
(integer)
</dd>
<dt>
popupMenu
</dt>
<dd>
the name of a popup menu to attach to this component
</dd>
<dt>
position
</dt>
<dd>
Where the component apppears if it's in a <code class='element'>splitpane</code>.
Only makes sense if the component is a child of a <code class='element'>layeredpane</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>
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>
CaretUpdate* [<span title='optional' class='optional'>CaretEvent</span>]
</li>
<li>
Change* [<span title='optional' class='optional'>ChangeEvent</span>]
</li>
<li>
Click [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
DoubleClick [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
FocusGained [<span title='optional' class='optional'>FocusEvent</span>]
</li>
<li>
FocusLost [<span title='optional' class='optional'>FocusEvent</span>]
</li>
<li>
InputMethod* [<span title='optional' class='optional'>InputMethodEvent</span>]
</li>
<li>
ItemEvent* [<span title='optional' class='optional'>ItemEvent</span>]
</li>
<li>
KeyPressed [<span title='optional' class='optional'>KeyEvent</span>]
</li>
<li>
KeyTyped [<span title='optional' class='optional'>KeyEvent</span>]
</li>
<li>
MouseDragged [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
MouseEntered [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
MouseExited [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
MouseMoved [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
MousePressed [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
MouseReleased [<span title='optional' class='optional'>MouseEvent</span>]
</li>
<li>
PropertyChange [<span title='optional' class='optional'>PropertyChangeEvent</span>]
</li>
</ul>
<p>
* These aren't really common.
Event handlers will only work for components that support them.
Elsewhere they are silently ignored.
</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 has no effect).
</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 <code><span class='class'>KeyStroke</span>.getKeyStroke(<span class='class'>String</span> s)</code>.
</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>
<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 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'>include 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 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 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.
</dd>
<dt>If I don't put text in a [label|combobox|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.
One way to fix this is to put some dummy text in the descriptor.
The component will get rendered large enough for the dummmy text, and if you chose sensibly, that can be large enough for the text that replaces it at run time.
</dd>
<dt>Why don't my components line up sensibly with [boxLayoutX|boxLayoutY]?</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 update to the latest release.
There are tools to help with this - for example, on Windows, Secuina have some simple tools for regular checks on what needs updating.
</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>
</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>