JavaFX Script and other musing Clarkeman's Weblog

Sunday Apr 20, 2008

Recently, I have been heads down preparing JavaFX demos for JavaONE. I ran into an interesting binding issue that I will share with you.
I call this the "Bounding Bridge".

First I have a Main class that contains a "matchCase" boolean attribute. Next, I have a Search class that also contains a "matchCase" boolean attribute. The Search class contains a CheckBox gui object that has a boolean selected field. What I want to have happen is that if the user selected the CheckBox then the "matchCase" attribute in Main will be true. Also, if the program sets the "matchCase" attribute in Main the CheckBox should be checked.

 Broken Binding

My first implementation looked like this (stripped down to essentials):

========== Main.fx =========

import javax.swing.*;
import javafx.gui.*;
public class Main extends Component {
    public attribute matchCase: Boolean;
    public function createJComponent(): JComponent {
        var canvas = Canvas {
            content: Search {
               matchCase: bind matchCase with inverse
            }
        };
        canvas.getJComponent();
    }
}
Frame {
    visible: true
    title: "JavaFXPad"
    content: Main{}
}

========== Search.fx ========= 

import javafx.gui.*;

public class Search extends CustomNode {
    public attribute matchCase: Boolean;
   
    public function create(): Node {
           ComponentView {
                component: CheckBox {
                    text: "Match Case",
                    font: Font.font("VERDANA", FontStyle.BOLD, 11)
                    selected: bind matchCase with inverse
                }
            }
    }
 }

===================

This all compiles, however when I run it I get:

Exception in thread "main" com.sun.javafx.runtime.BindingException: Both components of bijective bind must be mutable

The error is that the targets of the binds from CheckBox and  Main both point to the same "matchCase" attribute in Search so there is a collision  of sorts. To fix this, I implemented a "bridge" pattern.

The only class that needs to change is Search . The bridge consists of introducing a new boolean attribute, "pMatchCase" that in turn is bound to the selected attribute in CheckBox.  The bridging is done by adding an on replace block to both the "matchCase" and "pMatchCase" attributes, with each respective on replace block causing the other attribute to be updated when it is updated.

Bridged Binding

========== Search.fx =========

import javafx.gui.*;
import javax.swing.*;

public class Search extends CustomNode {
    public attribute matchCase: Boolean on replace {
        pMatchCase = matchCase;
    };
    public attribute pMatchCase: Boolean on replace {
        matchCase = pMatchCase;
    };
   
    public function create(): Node {
           ComponentView {
                component: CheckBox {
                    text: "Match Case",
                    font: Font.font("VERDANA", FontStyle.BOLD, 11)
                    selected: bind pMatchCase with inverse
                }
            }
    }
 }

 

===================
 

 

Comments:

Hi James, Your post was very helpful in that I had a binding problem when trying to bind a drag handle to a slider. Thanks because I am not sure how else I would have accomplished my task if it wasn't for your post. You can see the applet on http://ericonjavafx.com/?p=1

Posted by warrines on January 29, 2009 at 02:00 PM EST #

hej, isnt this a bit inefficient, cos when checkbox will change then matchCase will change by on replace clause and then this will trigger on replace on pmatchCase and so on over and over again... or javafx has some build-in mechanism to control such a situation?

Posted by kamiseq on March 23, 2009 at 05:38 PM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed