This gets posted on the ooRexx and BSF4ooRexx developer mailing lists as the information may be
interesting for both groups.
---------------------
/Remark: please note that the net-oo-rexx package (cf.
https://wi.wu.ac.at/rgf/rexx/tmp/net-oo-rexx-packages/) can be used to run BSF4ooRexx850
applications without a need to install BSF4ooRexx. This way ooRexx developers should be able to
quickly and easily run the above samples. (If one wants to use the installed ooRexx, then one could
use the packages-standalone package of net-oo-rexx (cf.
https://wi.wu.ac.at/rgf/rexx/tmp/net-oo-rexx-packages/packages-standalone/)./
---------------------
The bidirectional ooRexx-Java bridge "BSF4ooRexx850" has been developed for almost 25 years and
allows ooRexx programmers to use all of Java by merely sending ooRexx messages to Java objects. Vice
versa (it is bidirectional) it allows for Java programmers to send ooRexx messages to ooRexx
objects, if the Java side received an ooRexx object which gets wrapped up in an instance of the Java
class named org.rexxla.bsf.engines.rexx.RexxProxy supplied by BSF4ooRexx. The RexxProxy class
contains message methods that allow Java programmers to send ooRexx messages.
---------------------------------------------------------------------------------------------------------------------------------------------
Section 1: Java RexxProxy, BSF4ooRexx external functions BsfCreateRexxProxy()
and BsfRexxProxy()
Java defines so called interface classes, which are abstract. A Java class that implements a Java
interface must implement all abstract methods and can then be used wherever the interface class is
expected as an argument. BSF4ooRexx comes with a function named BsfCreateRexxProxy(rexxObject,
[userdata] [, javaInterfaceClass[,...]}) which returns a Java object (an instance of the Java class
RexxProxy). If supplying the name of Java interface classes, than that RexxProxy can be used in any
Java method as an argument, that accepts values of the denoted Java interface class types. With a
little bit of "magic" (implementing a java.lang.Proxy content handler in BSF4ooRexx) such RexxProxy
objects can be registered as Java event handler objects, if the RexxProxies declare to have the
respective Java event handler interface class implemented. Whenever Java invokes the event handler
method as a Java method, the RexxProxy handler will turn that Java method invocation into an ooRexx
message that it sends to its ooRexx proxy; if the Java method carries arguments, the RexxProxy
handler will supply these Java arguments in the received order to the ooRexx message. The RexxProxy
handler will in addition always append a Rexx directory object as a last argument that includes
entries with information about the context of that particular Java event method invocation; this
information is usually not needed.
So, if we want to supply an ooRexx object to a Java method as an argument, we merely need to create
a Java RexxProxy of it, using the BSF4ooRexx external function BsfCreateRexxProxy(...) and use the
resulting Java object as an argument. There is another BSF4ooRexx external function by the name of
BsfRexxProxy(rexxProxy) which returns the ooRexx object that the rexxProxy (a Java instance)
proxies/embeds.
Here a small ooRexx example:
o=.test~new("21") -- set attribute to "21" say "o~hi (message to ooRexx
object):" o~hi say
"o~value :" o~value -- show new value say "o~id2x :" id2x(o) say "---" --
interact from Java
rp=BsfCreateRexxProxy(o) -- create a Java RexxProxy for 'o' say "rp~hi
(message to Java
object):" rp~sendMessage0("hi") -- send the Java RexxProxy a message say
"rp="rp
rp~sendMessage1("value=",12345) -- set attribute to "12345" say "value :"
rp~sendMessage0("value") -- show new value say "rp~id2x :" id2x(rp) say
"---" -- interact from
ooRexx o2=BsfRexxProxy(rp) -- get the proxied/embedded Rexx object say
"o2~hi:" o2~hi say
"o2~value:" o~value -- show new value say "o2~id2x :" id2x(o2) ::requires
"BSF.CLS" -- get
ooRexx-Java bridge
------------------------------------------------------------------- ::class
test ::attribute value ::method init expose value use arg value ::method hi
expose value say
self": hi, my value is:" value ::routine id2x -- make identityHash values
better legible use arg
o numeric digits 18 hash=o~identityHash if .rexxInfo~internalDigits=18 then
-- 64-bit? return
d2x(hash,16)~insert("_",8) return d2x(hash) -- 32-bit
Running it yields:
rexx G:\tmp\bsf4oorexx\rexx_proxy\test.rex o~hi (message to ooRexx object):
a TEST: hi, my value
is: 21 o~value : 21 o~id2x : FFFFFDCF_1F22C9CF --- rp~hi (message to Java
object): a TEST: hi,
my value is: 21 rp=org.rexxla.bsf.engines.rexx.RexxProxy@f2a0b8e value :
12345 rp~id2x :
FFFFFDCF_1F227A1F --- o2~hi: a TEST: hi, my value is: 12345 o2~value: 12345
o2~id2x :
FFFFFDCF_1F22C9CF
---------------------------------------------------------------------------------------------------------------------------------------------
Section 2: JavaFX and FXML
JavaFX is a separate Java module library that allows for the creation of the most complex GUIs in a
quite easy manner. It introduced and employs "Property" classes (of various kinds), which all have
common getter ("get") and setter ("set(newValue)") methods. Properties can be bound to other
Properties, e.g. to automatically communicate changes to a Property value. Quite many fields in
JavaFX are Properties.
JavaFX comes with a comprehensive library of user interface classes, utility classes, including
JavaFX specialized "ObservableList" classes for collections. Some classes like ListView (a single
list of values that can be composed of strings and images) or TextView (a container for columns that
are comprised of javafx.scene.control.cell.TextFieldTableCell) implement all the interaction logic
(like insertions, updates, deletions, column sorting) and can work on "ObservableList"s. One needs
to supply callbacks to ListView or TextView objects that get invoked, if the user interacts with a
ListView or TextView. This alleviates the programmer from many complex implementation needs, but
demands some conceptual overview about the functionality.
Although JavaFX user interfaces can be created by instantiating each user interface object manually
in the code, there is an attractive and powerful alternative available which makes creating
(complex) GUIs easy in JavaFX: one can define GUis simply by using xml marked up text using FXML
tags and attributes. Complex functionality may cause complex textual definitions that may get out of
hand, therefore a GUI tool got created as well to create JavaFX GUIs ("SceneBuilder") which get
saved as a FXML files. This option is very attractive and cuts down GUI design needs quite
drastically for programmers. It is possible to define unique identifiers to GUI elements in the FXML
file (the attribute name is "fx:id") which allows one to address those GUI objects via the JavaFX
infrastructure.
Originally JavaFX came with a scripting language called "FX" (resembled Java and had an incredible
amount of curly brackets) which was used in combination with FXML. This scripting language
implemented the java.script interfaces and JavaFX (actually the FXMLLoader class) uses that
infrastructure to allow script code to be run while loading the FXML file in order to setup a GUI.
This is where ooRexx comes into play: BSF4ooRexx implements the javafx.interfaces (I served as one
of the experts when the javax.script interface got defined sucht that I would know the
specificaitons) and therefore ooRexx can be employed as a scripting language in JavaFX! (Actually,
ooRexx can be employed as a scripting language in *any* Java program that supports the javax.script
package.)
Now, if a FXML file gets loaded and the script engine is set to "rexx", the FXMLLoader will create a
script engine (causing a Rexx interpreter instance to be created and used for that particular FXML
file) and if there are script tags in the FXML file or code is placed into event objects that
scripting engine (ooRexx in our case) gets used to carry out that code. If JavaFX GUI objects in the
FXML file carry a "fx:id" attribute then that value is used to store the created JavaFX object with
the index "fx:id" in the javax.script global ScriptContext and become accessable to ooRexx. The
utility program named " put_FXID_objects_into.my.app.rex" accesses that ScriptContext and saves
those JavaFX objects in ".environment~my.app~fxml_file_name" (a Rexx directory using the "fx:id"
values as index) for later use. Once the FXMLLoader processed the entire FXML file the script engine
gets terminated (terminating the ooRexx instance).
To start up the JavaFX system one must use the abstract "javafx.application.Application" and supply
an implementation for its abstract method "start". Using the Application "launch" method will
initialize the JavaFX runtime, sets up the GUI thread (called "JavaFX Application Thread" which is
different from the awt/swing GUI thread, if used). "launch" will then invokd "start" which carries
out the setup and display of the JavaFX GUI and returns. Once setup JavaFX runs until the user ends
the application by e.g. clicking the close button of a GUI. In ooRexx one can create an ooRexx class
that implements a method named "start" which is supposed to be called by the Application "launch"
method. In order to do so, one simply needs create an instance of that ooRexx class and wrap up the
ooRexx object with the help of BsfCreateRexxProxy(rexxObject, [userdata], "nameOfJavaAbstractClass"
[, optional_arguments]). The resulting RexxProxy object (a Java object) gets the message "launch"
sent which then will invoke the "start" method of the RexxProxy object which will cause an ooRexx
message by the name of "start" to be sent to the embedded/proxied ooRexx object, using the Java
arguments as the arguments for the Rexx message in the same order and appends an ooRexx directory
object as the last argument which contains information about that particular invocation from
BSF4ooRexx.
Well, that is it! :)
---------------------------------------------------------------------------------------------------------------------------------------------
Section 3: Ad BSF4ooRexx JavaFX samples
In "BSF4ooRexx850\samples\JavaFX" there are numerous "nutshell examples" meant to demonstrate some
of the JavaFX features available to ooRexx programmers. In order for ooRexx users to learn about the
purpose of these nutshell examples an "index.html" file is available that briefly describes the
samples. Here the description for the samples "fxml_20", "fxml_25", "fxml_26", fxml_27", and
"fxml_99" that play an important role in this context of debugging ooRexx in "stressful"
multithreading scenarios:
... cut ...
//
/fxml_20/ <directory> /
Demonstrating all major features of a JavaFX /ListView/ in a nutshell.
/fxml_25/ <directory> /
Demonstrating all major features of a JavaFX /TableView/ in a nutshell.
/fxml_26/ <directory> /
Demonstrating all major features of a JavaFX /TableView/ in a nutshell
and shows how to use
/ComboBox/ controls in a /TableColumn/.
/fxml_27/ <directory> /
Demonstrating all major features of a JavaFX /TableView/ in a nutshell.
In addition it shows
how to implement /TableCell/ in Rexx for all columns, such that an
"auto-commit" becomes
possible (commiting cell edit changes in addition when moving away with
the /TAB/ key or
changing focus with the mouse). By default /TableView/ only commits
changes when the /ENTER/
key gets pressed.
/fxml_99/ <directory> /
A comprehensive application implementing a full-fledged, cross-platform
(running unchanged
on Windows, Linux and MacOSX!) address book application in less than
1500 lines of code
(LOC) in Rexx!
... cut ...
//
As mentioned above "ListView" is a single column list, "TableView" allows for multicolumn lists,
where the columns are sortable by clicking on the column headers. In order to take advantage of
"ListView" and "TableView", one needs to use an ObservableList with the objects that should be
displayed, and a couple of factory classes to help populate and/or change the cell values (a
CellFactory to create a table cell, a CellValueFactory to process the objects from the
ObservableList for display in a table cell).
From the number of callbacks from JavaFX to ooRexx "fxml_20" through "fxml_25" increase quite
considerably. The reason is that "fxml_25" has more columns than "fxml_20".
"fxml_25" is the basis for "fxml_26", which extends "fxml_25" by using a "ComboBox", "fxml_27"
extends "fxml_26" by using in addition a "DatePicker" (allowing editing in LocalDate formats!).
One special thing here is the fact, that in order to control everything from ooRexx one must be able
to subclass normal Java classes with ooRexx classes! :) This is the purpose of the routine
bsf.createProxyClass(javaClassName, nameOfProxyClass, arrayOfMethodsToProxy).
These nutshell example exist for the purpose to learn/demonstrate what is needed in ooRexx to create
a full, complex JavaFX GUI application in ooRexx only. Interested ooRexx programmers should be able
to take the code and edit it to fit their purpose.
It is astounding that novice programmers are able to take advantage of these nutshell examples and
create their own complex GUI applications successfully!
--- ad callbacks:
* the persons are Rexx objects stored as RexxProxy objects in an
ObservableList, each time the
ListView, TableView, the Cells need to populate or update anything the
RexxProxy objects
represent, causing Rexx messages to be sent to the contained/proxied ooRexx
objects (callback
from Java to Rexx)
* everytime a factory or one of its instances gets invoked causes ooRexx
messages to be sent from
Java to Rexx
* adding ComBox adds callbacks each time a Cell gets edited or updated, this
includes updates to
the visible user interface by the TableView causing potentially interactions
with the Cells
causing callbacks to ooRexx (therefore the ObservableList is optimized for
JavaFX to cut down
callbacks)
* adding DatePicker adds callbacks each time a Cell ...
---------------------------------------------------------------------------------------------------------------------------------------------
I think you get the overall idea of JavaFX and why callbacks may increase considerably from the
nutshell samples fxml_20 to fxml_25 to fxml_26 and fxml_27.
By comparison fxml_99 does not have a comparable callback intensity, although it isĀ not "low". :)
It adds a lot of bells and whistles that are meant to be helpful for real world applications.
A last note: all these complex GUIs are portable, i.e. they run unchanged on Windows, Apple and
Linux (and any other platform ooRexx and BSF4ooRexx850 are available)! Check out the other JavaFX
samples, they are much simpler, but still incredible feature rich and a treasure trove for ooRexx
programmers!
---rony
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel