Skip to content

Commit

Permalink
Fix up embedded Java docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
davetcc committed Dec 6, 2024
1 parent e845ff6 commit 5f7d120
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 17 deletions.
Empty file added .hugo_build.lock
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ weight = 2
toc_needed = true
+++

Embedded Java for Raspberry PI and embedded Linux is supported from V2.3 onwards directly from the designer UI. We are building out the number of UI options, but presently No Local UI and JavaFX are supported, we will try and add Android longer term. The Java version is well served with remote capabilities offering Serial (USB, Bluetooth, RS232) devices, Ethernet, WiFi and Webserver based protocols. Also, it's easy to write your own additional remote extension point if needed.
Embedded Java for Raspberry PI and Linux works slightly differently to the C++ project creator in that it is a starter project with a webserver and JavaFX UI built in. After project creation you then go about configuring the project how you like, and the designer will keep the menu callbacks up-to-date in the controller, the menu definitions that make up the menu tree, and any menu-in-menu definitions you create.

We will try and add Android support longer term but right now it is tested for Java on a Raspberry PI in kiosk mode. The Java version is well served with remote capabilities offering Serial (USB, Bluetooth, RS232) devices, Ethernet, WiFi and Webserver based protocols. Also, it's easy to write your own additional remote extension points if needed.

## Overview of the embedded Java version

Expand All @@ -23,48 +25,70 @@ The main components are shown in the diagram below. In the middle we see the `Me

An important thing to note here is that unlike with the C++ version, it is highly recommended that you use a "namespace" aka package name in lower case, usually using reverse domain name syntax. For example I may create a project that would start with something like "com.thecoderscorner.example". All the classes in this example would be created in `src/main/com/thecoderscorner/example`.

Maven is used as the build system by default. It is set up automatically with the dependencies for your project. You can switch to using Gradle for the build system, but the designer will not automatically add dependencies. Read about [maven build system here](https://maven.apache.org/guides/) and probably start with one of the two getting started guides.
### Getting started

### Reference documentation
To get started with a Java project either create a new project within TcMenu Designer `File -> New` and choose the `Java/Raspberry PI` option, note that you must provide a package name. Alternatively, from the command line in the directory where the project should be created - [see CLI documentation]({{< relref "tcmenu-cli-workflow.md" >}}):

All the classes discussed here are documented, a few key entry points into the reference docs are linked below. Note that this documentation is taken from the source, so most Java IDEs should show it.
tcmenu create-project -p RASPBERRY_PIJ -n my.package.name ProjectNameNoSpaces

* [Using the JavaAPI guide]({{< relref "tcmenu-java-api-to-arduino-remote-control.md">}})
* Consult the Java docs shipped with the API.
The above command will create a Java starter project called `ProjectNameNoSpaces` under the current directory and the base Java package will be `my.package.name`. [Here is the the starter project](https://github.com/TcMenu/tcmenu-examples-starters/tree/main/java/embeddedJavaDeviceUI) that is used as the starting point. It also contains documentation on how each file works.

## Components of the application

This is a summary of the components, there is a deeper guide within the `README.md` of the created project. You should consult that for a more detailed view.

### The MenuConfig app-context

Within the Java local application, we configure up all the components using a [Spring Container](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html), we create an application context that contains all the classes needed to start the application, it is in the class called `MenuConfig` in your created app. You can add extra bean configurations to this class, you can even change existing ones to add extra parameters / functionality, just don't change their method name, as that is how code generator detects that they are there.
Within the Java local application, we configure up all the components using our own very lightweight dependency container, it has far fewer features than most commercial ones, but is very light-weight. We create a "context" that contains all the classes needed to start the application, it is in the class called `MenuConfig` in your created app. You can add extra bean configurations to this class, you can even change existing ones to add extra parameters / functionality. We will not touch this file after the initial creation so you can adjust as needed.

In summary, any method that is annotated with `@TcComponent` will be executed during initialisation and the resulting object will be added to the "context", it is then available for later use. Any parameters to a method annotated as above will be resolved from the context. The following example is taken from the README of the starter project:

Consider the `MenuConfig` class somewhat like a storage object that can hold instances of objects needed for the running of the application. You can add methods to the class that are annotated with `@TcComponent` and these will be added into the `context`, and any such method can take as many parameters as needed, and the parameters will be automatically wired where possible from the objects already available in the context. Some degree of dependency is allowed and supported. Let's take an example that we a `Car` and that object needs an `Engine`. In the menu config we'd add something like:

public class MenuConfig extends BaseMenuConfig {
// other configuration...
public Engine myEngine() {
int cylinders = Integer.parseInt(mandatoryStringProp("engine.cylinders"));
return new Engine();
}
public Car myCar(Engine engine) {
return new Car(engine);
}
// other configuration...
}

### The App java class

The class ending with App in your package is the main class, it will start the application and should not be edited, it will regenerate completely every time generator is run.
The class ending with App in your package is the main class, it will start the application and get everything into a running state. We do not touch this file after project creation.

### The Controller java class

This class contains the mappings for your menu items. You can register as manu controllers as you want, and manually map events to them as discussed below. This controller is automatically added to the menu manager at start up.
The controller class is where you receive updates as events happen on the menu, either locally or remotely. You can then take action based upon the new state. There are several ways that you can get updates:

1. You can get updates when a particular item changes, to do this we create a method that is annotated with `@MenuCallback(id=n)` where `n` is ID of the menu item. The function should follow the signature `void methodName(Object sender, MenuItem item)`. TcMenu Designer will generate these automatically wherever a callback is defined.
2. There is a callback for changes in every menu item, you can hook into this if you prefer and determine yourself which item is updated by overriding: `void menuItemHasChanged(Object sender, MenuItem item)`.
3. You can handle callbacks from list items by providing an additional parameter as follows `@MenuCallback(id=15, listResult=true)` and in this case we must add a parameter of type `ListResponse listResponse` after the `sender` and `item`, and the response tells you how the interaction with the list ended.
4. You can use the controller to populate scroll choice items. Again designer should do this automatically if it detects a scroll choice item. For this you annotate a method with the `@ScrollChoiceValueRetriever(id=n)` where n is the ID of the menu item. You will receive a callback whenever the scroll choice item needs a value and the signature is: `String myScrollChoiceNeedsValue(ScrollChoiceMenuItem item, CurrentScrollPosition position)`

You can create additional `MenuManagerListener` objects at runtime if you wish to further split things up. To do this, simply do not provide a callback in the designer UI, and then manually add it to another controller.

### The menu definition java class

The menu definition file contains a helper method to get each menu item and also the tree of items for your menu. Don't edit this file, it is recreated at every start up.
The menu definition file contains a helper method to get each menu item and also the tree of items for your menu. Don't edit this file, it is recreated at every code generation.

### The pom.xml file

This is the maven build file for the project, in most cases, the dependencies will automatically be added as you add additional plugins.
This is the maven build file for the project, it can be used to import the project into most IDEs and also to build the project.

### The application.properties file

This contains definable properties for your application. So that you can have different properties for different environments, most settings for the application context are kept in this file.

### Any plugins that are included
### Components that are optional

As you include plugins, any files needed by the plugins will reside in the `plugins` package of your application. These are specific to each item and should not be edited.
* `JfxLocalAutoUI` and `LocalTreeComponentManager` provide the local UI, it produces a panel that fills the entire window and represents the menu structure.
* `StatusPanelDrawable` demonstrates how to override drawing with a custom arranged grid for the status submenu. It demonstrates custom drawing too.
* `TcJettyWebServer` and `TcJettyWebSocketEndpoint` both configure and serve up a website that contains EmbedControlJS, which can produce a lightweight remote control application in the browser.

## Working with Menu Manager

Normally, the designer will create a menu manager for us and start it during initialisation. The designer can also add remote control capabilities for most common cases without writing any code. However, should you need to write your own remote control facility, then you implement the `ServerConnectionManager` interface.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ weight = 50
toc_needed = true
+++

Embedded Java for Raspberry PI can present the menu using OpenJFX. Below we provide an overview of the components involved in rendering with this plugin.
Both EmbedControl remote and local work using the same UI components, and they can take a tcMenu Designer created menu tree and convert it automatically into a displayable graph. The "embedded/local" version does this with the menu tree embedded within it, while the "remote" version does so using a menu tree that it bootstrapped from a remote device.

{{< figure src="/products/arduino-libraries/images/electronics/arduino/tcMenu/java-embedded-open-jfx-overview.jpg" alt="High level overview of Raspberry PI OpenJFX rendering" title="High level diagram of OpenJFX rendering" >}}
In order to do this we need an `AutoUI`. The "Automatic UI" reads the components in the tree and presents them using standard UI components that are available in Java FX. For any submenu, you can override the drawing by providing a custom panel for it, and then manage which components are displayed yourself.

Both Auto and Custom panels are told of changes coming in from the remote, such as command acknowledgements, updates to menu items, and connectivity changes. Below is a high level design diagram of the components, showing the rough class layout:

{{< figure src="/products/arduino-libraries/images/electronics/arduino/tcMenu/java-embedded-open-jfx-overview.jpg" alt="High level overview of Raspberry PI OpenJFX rendering" title="High level diagram of OpenJFX rendering" >}}

## PanelPresentable and stacks of panels

We'll now discuss how the UI works based on the screenshot below.

{{< figure src="/products/arduino-libraries/images/electronics/arduino/tcMenu/status-panel-example-java.png" alt="an example screenshot of the Java embedded UI" title="JavaFX embedded UI example panel" >}}

1. A `NavigationManager` provides the navigation support and place to present title widgets (3), if the user can go back in the stack, then the back button is presented on the left. The title of the current panel on display is presented here too. It is responsible for the stack of panels presented in the center view. Only one panel is on display at a time, and it is the current top of stack.
2. A stack of `PanelPresentable` components, which are all managed by the above navigation manager. Only the top one is on display. You can create your own panel presentables and push them onto the display using navigation manager. Panel presentable is more than just a panel, it is the instructions on how to draw the panel, and information about it too.
3. Title widgets can be added to the navigation manager at any time, they can be simple as a display of current state, to a button that presents a panel. These are added via the navigation manager.

In the above screenshot we are presenting a custom panel for the status menu item. In order to present custom panels we simply tell the above navigation manager about it using `navigationManager.addCustomMenuPanel(menuItem, panelPresentable);` where we provide the sub menu item that should be drawn custom, and the panel presentable for it. If the panel implements `UpdateablePanel` or `BaseCustomPanel` it will receive updates from the API when there are changes. It is recommended for all menu item panels you use these as a starting point.

## Manually handling navigation at any time

You can manually navigate between items from the navigation manager and push any `PanelPresentable` onto the display using `pushNavigation(panelPresentable)` which causes immediate navigation to that panel. You can also force navigation to a particular menu item using `pushMenuNavigation` but this is rarely used.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5f7d120

Please sign in to comment.