-
Notifications
You must be signed in to change notification settings - Fork 30
Developer overview
JRubyFX is effectively three projects in one: a JavaFX DSL + builder, patches for JavaFX <=> JRuby interop, and FXML integration, each building on the prior.
The DSL and builders is the first "pillar" of JRubyFX. It comprises roughly of the following files:
- jrubyfx/module.rb
- jrubyfx/dsl.rb
- jrubyfx/utils/common_utils.rb
module.rb is where the JRubyFX
module is defined and contains two very important methods: build
and with
. Whenever a class imports the JRubyFX
module, they gain these two methods.
with
takes an object, a list of properties, and an optional block. It first applies the properties to the object, then calls the block in the context of the object. This enables you to avoid having to type the object's name each time you set a property. On the downside, local instance variables and methods are inaccessable and must be accessed from local closure variables.
build
is similar, but instead of giving it an object, you give it a type, which it then constructs and calls with
, returning the finished object.
dsl.rb is exactly what it sounds like: the heart of the DSL (Domain Specific Language, in this case the domain is JavaFX, hence we have a JavaFX Specific "Language"). NAME_TO_CLASSES
is the first half of the DSL; it maps DSL methods to JavaFX classes. Most of it is generated from the imports list (see Random Other Stuff section at the bottom) and thus appears very small. When it is generated, it will for example map "tree_view"
to the javafx.scene.controls.TreeView
class. This information is then used by the method_missing
function (a ruby metaprogramming construct). The method_missing
function is called when an unknown method is called in a class that has included the DSL. It first checks to see if the method name is in the NAME_TO_CLASSES
map, and if it is not, it "throws" the missing method back up to see if somebody else knows about it. On the other hand, if it does find it in the map, it calls build
with the mapped class, which in turn creates the object and calls with
, which in turn sets properties and executes a block in the scope of the object so you can easily set stuff on the new object.
Both the previous two files use this file to split, set, and convert properties on objects.
These three files allow you to instead of saying the java-ish
btn = Java::javafx.scene.controls.Button.new
btn.text = "Good Evening, Jeeves!"
btn.set_on_action do
...
end
to say this:
button(text: "Good Evening, Jeeves!") do
set_on_action do
...
end
end
The core converters "pillar" is composed of three parts: the actual converters, static class references to the converters, and descriptors to build more class converters. This section is contained in the following files:
- jrubyfx/utils/common_converters.rb
- jrubyfx/core_ext/*.rb
- jrubyfx/core_ext/exts.yml
- jrubyfx/dsl.rb
- jrubyfx/core_ext/precompiled.rb
This file contains several bits: metaprogramming helpers for the core_ext/*.rb files and actual converters. Most of the operations it does are pretty standard so I won't go into much detail.
This folder contains lots of static overrides and converter declarations that are not supported (yet) in the yaml file or which are just plain methods like FileChooser.add_extension_filter
.
This YAML file declaratively declares what extra DSL methods should be appended to precompiled.rb for given classes.
This is the heart of this stage. When you either directly or indirectly run rake reflect
this code runs to generate precompiled.rb from exts.yml. write_enum_converter
is the prime bit of code and does three things:
- Reflexively find all methods with enums and add symbol => enum converters on them
- Reflexively find all methods with colors and add symbol => Color converters on them
- Read exts.yml and add specified converters/dsl methods on them
All this new information is then massaged into precompiled.rb, which is then much faster to load each time than re-computing it every load as it rarely changes.
As of 2.0, FXML support uses the native JavaFX FXMLLoader. The old JRubyFX-FxmlLoader is no longer needed and can be removed
- fxml_helper.rb
- controller.rb
- module.rb
Aka where the action is. All FXML controlers must include JRubyFX::Controller
to work properly.
Once it has been included, a class gains several methods and metaprogramming constructs. The most important ones are probbably:
-
fxml
&fxml_root
load_into
on
css
fxml
enables a controller to specify the default fxml file it is a controller for if the filename is not the same as its class name.
Example:
fxml_root File.dirname(__FILE__)
# only need this once. Says that all fxml files are in the same dir as this file
class MyObject
include JRubyFX::Controller
fxml "MyObject.fxml"
end
This is the primary way to create the main scene's controller (use new
for custom control controllers). The only required argument is the scene to load it into, but it has more options such as the filename to load, scene properties, initialization arguments, etc.
Example:
MyController.load_into(stage)
If you want to have one method for multiple events of different names, use on
instead of def
. The reason for it to exist was because of original limitations in the 0.9.x series where you needed to use it instead of def
, but that requirement has vanished now that we have JRubyFX-FxmlLoader`.
Example:
class MyController
inclue JRubyFX::Controller
def normal_event_handler(event)
# ...
end
on :on_style_event_handler do |event|
# ...
end
on [:on, :multiple, :handler, :names] do |event|
# this block is defined for #on, #multiple, #handler, and #names callbacks
# ...
end
end
These are conveinence methods for calling scene.lookup
and friends
At the end of this file are several class methods that enable you to easily define FXML-exportable properties. Since FXML is all strings, these define a propertynameGetType method that returns the ruby class that corresponds to the type of the properties
Astute readers will notice there is a small bit I have not talked about yet. Rake tasks, binaries, and the imports & plumbing.
This binary allows you to give it an fxml file and it outputs a controller skeleton, similar to SceneBuilder's one for Java.
This binary allows you to generate a jar file from the jruby-complete.jar. This is not a full soloution and needs a bit of improvement.
Several things like jarification are in jrubyfx_tasks.rb
This is a launcher that uses java_fx_impl.rb to properly launch javafx from ruby.
This imports all JavaFX classes so we can use them and creates the javaFX tree that several other classes use.