187 lines
10 KiB
Plaintext
187 lines
10 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta name="generator" content="HTML Tidy for HTML5 for Apple macOS version 5.8.0">
|
|
<title>JMRI: Use of Swing</title>
|
|
<meta name="author" content="Bob Jacobsen">
|
|
<meta name="keywords" content="JMRI technical code standards recommendation Swing">
|
|
<!--#include virtual="/help/en/parts/Style.shtml" -->
|
|
</head>
|
|
<body>
|
|
<!--#include virtual="/help/en/parts/Header.shtml" -->
|
|
|
|
<div id="mBody">
|
|
<!--#include virtual="Sidebar.shtml" -->
|
|
|
|
<div id="mainContent">
|
|
<h1>JMRI Code: Use of Swing</h1>
|
|
<strong>Note:</strong> This page describes a toolkit for creating JMRI's GUI that's been
|
|
slowly developed as part of JMRI. Please use this if you're creating new JMRI user
|
|
interfaces. Note that there are proposals to move JMRI to other, non-specific toolkits in
|
|
this area. Before you do work to extend or improve this toolkit itself, please ask on
|
|
jmri-developers about that status of that work.
|
|
<p>We use Java Swing for our GUI development. It's a lot more powerful than the original AWT,
|
|
and the price is right. In particular, we try to use the "Bean format" of setting and getting
|
|
members, call-backs to notify of changes, etc, to make it easier to build applications from
|
|
JMRI components.</p>
|
|
|
|
<h2>General Principles</h2>
|
|
|
|
<p>We have been evolving a particular pattern for using Swing, described here. The JMRI
|
|
codebase contains several generations of implementations, so not all of it looks like this,
|
|
but we're moving classes in this direction as time allows.</p>
|
|
<a href="images/SwingStructureExample.png"><img src="images/SwingStructureExample.png"
|
|
alt="class structure"></a>
|
|
<p>The basic structure is:</p>
|
|
|
|
<ul>
|
|
<li>Keep Swing code in packages with <code>swing</code> in the package path. For example,
|
|
prefer putting Swing code in <code>jmri.jmrit.vsdecoder.swing</code> or a subpackage of
|
|
that, instead of putting it in <code>jmri.jmrit.vsdecoder</code> itself. This helps keep
|
|
the <u>other</u> code non-Swing-specific, e.g. so it can be used with other toolkits or on
|
|
systems without graphics. This pattern is similar to the way that <a href=
|
|
"XmlPersistance.shtml">ConfigureXml code</a> lives in separate <code>.configurexml</code>
|
|
packages.
|
|
</li>
|
|
|
|
<li>Implement graphical tools as JmriPanel objects. These are JPanels with enough extra
|
|
structure that the JMRI applications can directly work with them. For example, a JmriPanel
|
|
subclass can be instantiated and placed in a properly laid out window by creating a
|
|
JmriNamedPanel action with just the name of the JmriPanel class, which in turn can be done
|
|
with various automated tools.<br>
|
|
Do not create JmriJFrame or JFrame subclasses with lots of specific function<br>
|
|
This pattern lets us write a tool panel just once, and then use it in lots of various
|
|
places, embedded into windows in several ways. It also greatly reduces the number of
|
|
classes that need to be loaded at startup time, because there are not separate *Action and
|
|
*Frame classes, and JmriPanel subclasses don't have to be loaded just because they are
|
|
listed in a menu.</li>
|
|
|
|
<li>Use the Swing and AWT native support for decoding events. Do not write your own code
|
|
for decode clicks, mouse down, drags or other user interactions; use the Swing classes for
|
|
that. For example, use <a href=
|
|
"https://docs.oracle.com/javase/8/docs/api/java/awt/event/MouseAdapter.html"><code>MouseAdapter</code></a>
|
|
as a way of getting events for mouse pressed, mouse clicked, and mouse released. These will
|
|
differ on different platforms and with different hardware, and it extremely unlikely that
|
|
any code you write will do a better job of decoding all that.
|
|
</li>
|
|
</ul>
|
|
|
|
<h2 id="life">JMRI Pattern for Swing Window Creation</h2>
|
|
|
|
<p>The <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/util/swing/package-summary.html">jmri.util.swing</a>
|
|
package contains the support code.</p>
|
|
|
|
<h3>Life Cycle of a JmriPanel</h3>
|
|
First the ctor runs, then initComponents. That second part should be the place for
|
|
connections to other components, as all lower level objects have been created. (subclasses
|
|
for particular systems might have e.g. more initComponents methods, called later)
|
|
<p>Dispose is called at the end. (Note that JPanels don't have a dispose(), that's normally
|
|
only part of JFrames, but we provide it here for cleanup)</p>
|
|
|
|
<h3 id="display">Displaying a JmriPanel</h3>
|
|
|
|
<p>JmriPanels are best created by name with JmriNamedPaneAction, which has the advantage of
|
|
greatly reducing the number of classes that need to be loaded to populate a menu.</p>
|
|
|
|
<p>To create an action, e.g. for a menu item, the simplest form is:</p>
|
|
<div class="wide">
|
|
<pre><code>
|
|
new jmri.util.swing.JmriNamedPaneAction("Log4J Tree", "jmri.jmrit.log.Log4JTreePane");
|
|
</code></pre></div>
|
|
<p>The first argument is the human-readable name, and the 2nd is the name of the
|
|
panel class.</p>
|
|
<p>An example of a fuller form:</p>
|
|
<div class="wide">
|
|
<pre><code>
|
|
new jmri.util.swing.JmriNamedPaneAction(Bundle.getMessage("MenuItemLogTreeAction"),<br>
|
|
new jmri.util.swing.sdi.JmriJFrameInterface(),<br>
|
|
"jmri.jmrit.log.Log4JTreePane");
|
|
</code></pre></div>
|
|
<!-- without <br> does not reflow on iPad when viewd online, causing rest of the page to shrink-->
|
|
|
|
<ul>
|
|
<li>The first argument is the human-readable name for the action, e.g. what will show in
|
|
the menu or on the button. That's internationalized here by using <a href=
|
|
"I8N.shtml">Bundle</a>.
|
|
</li>
|
|
|
|
<li>The second argument is the context in which to display it, which in this case is a new
|
|
plain window. (See below for more info on the options here)</li>
|
|
|
|
<li>And the third argument is the name of the specific JmriPanel class to be instantiated
|
|
and used when the action is invoked. The class isn't loaded until first used, because we've
|
|
put a String name here, which saves a bunch of time at startup for large menus.</li>
|
|
</ul>
|
|
See the <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/util/swing/JmriNamedPaneAction.html">JmriNamedPaneAction
|
|
Javadoc</a> for more information.
|
|
<p>If you need specialized initialization that can't be built into the JmriPanel itself via
|
|
it's <code>initComponents</code> and <code>initContext(..)</code> methods, perhaps to make
|
|
decision about connections, make a specialized Action class by extending
|
|
<code>jmri.util.swing.JmriNamedPaneAction</code>, providing the appropriate constructors, and
|
|
including a <code>@Override public JmriPanel makePanel()</code> method that does any
|
|
case-specific initialization that's needed before the panel can be used. For an example (may
|
|
have been changed) see </p>
|
|
<div class="wide"><a href=
|
|
"https://github.com/JMRI/JMRI/blob/master/java/src/jmri/jmrix/loconet/swing/LnNamedPaneAction.java">
|
|
jmri.jmrix.loconet.swing.LnNamedPaneAction</a>.</div>
|
|
|
|
<p>If none that can be used, look into using JmriAbstractAction as the base for a separate
|
|
class implementing Action.</p>
|
|
|
|
<h3>Menus, ToolsBars, Buttons, etc</h3>
|
|
<p>If you're using JmriPanels as described above, JMRI also provides tools for creating menus,
|
|
toolbars, button fields, etc more easily.</p>
|
|
<p>Generic creation of menus, toolbars and navigation trees from XML definition files are
|
|
provided by the <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/util/swing/JMenuUtil.html">jmri.util.swing.JMenuUtil</a>,
|
|
<a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/util/swing/JToolBarUtil.html">jmri.util.swing.JToolBarUtil</a>,
|
|
and <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/util/swing/JTreeUtil.html">jmri.util.swing.JTreeUtil</a>
|
|
classes</p>
|
|
|
|
<p>I18N of those menus, toolbars and trees is then done via the XML content in the <a href=
|
|
"I8N.shtml">usual way</a>.</p>
|
|
|
|
<h2 id="windows">Window Control</h2>
|
|
<p>JMRI provides three different ways of embedding JmriPanels in windows:</p>
|
|
<ul>
|
|
<li>The jmri.util.swing.sdi package provides the traditional JMRI "single-document
|
|
interface", where there are multiple independent windows</li>
|
|
|
|
<li>The jmri.util.swing.multipane package provides a "multi-pane" or IDE-style interface",
|
|
where each window is tiled with inter-related panes. This is used for the (new)
|
|
DecoderPro.</li>
|
|
|
|
<li>The jmri.util.swing.mdi package provides a "multi-document interface", where a primary
|
|
window contains multiple independent sub-windows. This currently isn't used by a JMRI app,
|
|
at least not as far as we know, but it's available if wanted.</li>
|
|
</ul>
|
|
|
|
<p>Each of those then provides an implementation of WindowInterface that creates new windows,
|
|
subwindows or other constructs as needed, so as to put panels in the right place.</p>
|
|
|
|
<p>(See the <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/util/swing/package-summary.html">jmri.util.swing package
|
|
Javadocs</a> for more information</p>
|
|
|
|
<h2 id="misc">Misc</h2>
|
|
|
|
<p>Prefer use of jmri.util.swing.WrapLayout to java.awt.FlowLayout, because
|
|
WrapLayout properly handles the case of its contents wrapping into two lines.
|
|
When that happens, FlowLayout will often not display the second line.</p>
|
|
|
|
<p>jmri.util.swing.JmriJOptionPane is preferred over javax.swing.JOptionPane.
|
|
The Modality of the latter will block the whole JVM UI until they are closed.
|
|
This causes issues with Always on Top Frames, which will also be blocked,
|
|
potentially with the Dialog hidden behind the Frame.</p>
|
|
|
|
<!--#include virtual="/help/en/parts/Footer.shtml" -->
|
|
</div> <!-- closes #mainContent-->
|
|
</div> <!-- closes #mBody-->
|
|
<script src="/js/help.js"></script>
|
|
</body>
|
|
</html>
|