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

Reply via email to