JMRI Code: Application Structure
This page discusses the structure of JMRI application(s). For the structure of the JMRI library itself, see the Introduction to JMRI Library Structure page. JMRI ships with several main "applications":- DecoderPro
-
From
apps.gui3.dp3.DecoderPro3
: This is an example of a "new structure" application. - PanelPro
-
From
apps.PanelPro.PanelPro
: This is an example of a "original structure" application. - JmriFaceless
-
From
app.JmriFaceless
, this is a version of PanelPro that's been optimized to run on computers without displays and mice, i.e. a Raspberry PI. It uses the original structure.
New Application Structure
The currently-recommended application form had the main application class descending from theapps.gui3.Apps3
class.
Most of the required customization for a new application consists of overriding apps.Apps methods that control the display during startup: providing the main image, name and program link, etc.
Beyond that, the new application class can override implementations that create menus, load help, configure preferences, etc.
The startup sequence for e.g. DecoderPro, starting with DecoderPro#main(..)
is quite short:
public static void main(String args[]) { preInit(args); DecoderPro3 app = new DecoderPro3(args); app.start(); } static public void preInit(String[] args) { apps.gui3.Apps3.preInit(applicationName); setConfigFilename("DecoderProConfig3.xml", args); }
apps.gui3.Apps3.preInit
initializes conditions for basic running: set up logging, set up the console, etc.apps.gui3.Apps3.setConfigFilename
sets the filename (pathname) for the configuration file, either from system properties, launch arguments, or if needed from a default argument.- The DecoderPro constructor just refers up to the App3 constructor, which in turn handles some GUI initiatlization and relies on the AppsBase constructor for the rest.
- Apps3.start() is then responsible for the program's dynamics.
Some useful milestones:
- Windows, toolbars and menus
- The Gui3 support (see the JMRI Swing page) is used to define toolsbars and menus. For example, apps.gui3.dp3.DecoderPro3#getMenuFile() loads from xml/config/parts/jmri/jmrit/roster/swing/RosterFrameMenu.xml and apps.gui3.dp3.DecoderPro3#getToolbarFile() loads from xml/config/parts/jmri/jmrit/roster/swing/RosterFrameToolBar.xml
- Load configuration
-
apps.AppsBase.jmri.ConfigureManager()
loads the configuration file, and in the process loads and activates many of the user level objects in the system. In particular, this is the start of loading the system connections.
For more information, see the apps.gui3.Apps3
Javadoc.
Older Application Structure
The older, original application form had the main application class descending from theapps.Apps
class.
Most of the required customization for a new application consists of overriding apps.Apps methods that control the display during startup: providing the main image, name and program link, etc.
Beyond that, the new application class can override implementations that create menus, load help, configure preferences, etc.
The startup sequence for e.g. PanelPro, is then:
PanelPro#main(..)
starts and does some initial interactions by invoking methods fromapps.Apps
- It then constructs a
PanelPro
object, most of whose behavior is inherited fromapps.Apps
. - Finally, it uses the
apps.Apps#createFrame
method to complete the setup.
For more information, see the apps.Apps
Javadoc.
Minimal Application Structure
(This may be out of date)The apps.SampleMinimalProgram class provides a minimal example of starting a program that uses JMRI. It's got a hard-coded layout configuration. See the internal comments for more info.
The preferred way is to use the JMRI configuration system to read a configuration file and do the initialization. There's commented out code in apps.SampleMinimalProgram that shows how to do that.
The JMRI applications themselves use a more powerful "profile" mechanism that's inherited from the apps.Apps and apps.AppsBase classes.