JRBuilder: Binding Demo 3
Home «  Prev    Contents    Next  » Download
JRBuilder: Binding Demo 3
Still more on Binding: Binding across applications. Unbind, Rebind, Remove.             
This example builds on the the previous example. It demonstrates binding properties from two applications, and shows the use of the binding management statements unbind, rebind, unbind_context, rebind_context, and remove_context. It also shows the use of named bindings.

This example is all but self-explanatory (if you've gone through the previous examples), but I'll touch on a few points. As with the previous example, the notable code (those lines that differ from the previous example) are shown in blue.

In this example, the binding contexts and bindings that were defined in each Swing context have been removed, and replaced by an externally-defined binding context. The properties to be bound in each Swing context have been given accessors so they may be bound externally. Furthermore, the properties of each application are now bound to those of the other, whereas previously they were only bound to other internal properties.

You'll notice that each binding now has a name. That permits them to be managed individually. All the previous bindings shown have been anonymous bindings, which may be fine in many applications, so long as they are defined in a named binding context, rather than the default context. An anonymous binding in the default context is there to stay; because the default context cannot be unbound, and an anonymous binding cannot be unbound, there is no way to clean up once your application terminates. If all bindings are intra-application, that may not matter much, but it is generally a good idea to unbind and remove bindings when they are no longer needed.

The balance of the example shows the use of the various binding management statements. Here's a brief summary:

unbind([ctx_name,]name) Unbinds a single binding. Listeners and/or interceptors are removed, but the binding is retained for later rebind or remove.

rebind([ctx_name,]name) Rebinds an unbound binding. Listeners/interceptors are reinstalled.

remove_binding([ctx_name,]name) Permanently removes a single binding. The binding must previously have been unbound.

unbind_context(ctx_name) Unbinds all bindings in the context; all listeners and/or interceptors are removed. The binding context is retained for a later rebind_context or remove_context. Inheritors retain access to prototypes, translators and converters.

rebind_context(ctx_name) Rebinds all bindings in the context; all listeners and/or interceptors are reinstalled (even if previously they had been individually unbound).

remove_context(ctx_name) Permanently removes the binding context. The context must previously been unbound. Inheritors retain access to prototypes, translators and converters.

require 'jrbuilder'

bindery = Bindery::Bindery.new

# create a named binding context with some
# useful prototypes
bindery.binding_context('my_swing_lib') {

    undoable_edit_happened(javax.swing.text.Document) {
      getter { |obj,attribs| attribs[:obj].text }
      setter { |obj,value,attribs| attribs[:obj].text = value }
    }
    
    state_changed(javax.swing.JSlider,'value')
}
# create two Swing contexts that share the same bindery
ctx1 = JRBuilder.new_swing_context(bindery)
ctx2 = JRBuilder.new_swing_context(bindery)

ctx1.enter {
  attr_reader :my_frame, :sliders, :field1, :field2

  @sliders = []
  @field1 = nil
  @field2 = nil
  
  @my_frame = frame('Binding Demo 3A') { size 200, 400; location 200, 100
    layout :grid,2,1; border :bevel, :RAISED
    on_window_closing { my_frame.dispose }
    menu_bar { 
      menu('File') {  mnemonic :VK_F; background :WHITE
        menu_item('Exit') { mnemonic :VK_X; background :WHITE
          on_click { my_frame.dispose }
        }
      }
    } 
    y_box { border(:titled, 'Horizontal Sliders') { border :etched, :LOWERED }
      y_glue
      4.times {
        @sliders << slider(:HORIZONTAL) { value 0 }
        y_glue
      }
    }
    y_box { border(:titled, 'Text Fields') { border :etched, :LOWERED }
      y_glue
      text_area('Type text in one box, and watch it appear in the other') {
        line_wrap true; wrap_style_word true; editable false;
        border :etched, :RAISED; fixed_size 175,40
      }
      y_glue
      @field1 = text_field('Enter text here',15) {
        border :bevel, :LOWERED; fixed_size 175,24
        on_focus_gained { @field1.select_all }
      }
      y_glue
      @field2 = text_field('Enter text here',15) {
        border :bevel, :LOWERED; fixed_size 175,24
        on_focus_gained { |event,obj| obj.select_all }
      }
      y_glue
    }
  }
  # binding moved outside of Swing context
}
ctx1.my_frame.show

ctx2.enter {
  attr_reader :my_frame, :sliders, :field1, :field2

  @sliders = []
  @field1 = nil
  @field2 = nil
  
  @my_frame = frame('Binding Demo 3B') { size 200, 400; location 500, 100
    layout :grid,2,1; border :bevel, :RAISED
    on_window_closing { my_frame.dispose }
    menu_bar { 
      menu('File') {  mnemonic :VK_F; background :WHITE
        menu_item('Exit') { mnemonic :VK_X; background :WHITE
          on_click { my_frame.dispose }
        }
      }
    } 
    y_box { border(:titled, 'Horizontal Sliders') { border :etched, :LOWERED }
      y_glue
      4.times {
        @sliders << slider(:HORIZONTAL) { value 0 }
        y_glue
      }
    }
    y_box { border(:titled, 'Text Fields') { border :etched, :LOWERED }
      y_glue
      text_area('Type text in one box, and watch it appear in the other') {
        line_wrap true; wrap_style_word true; editable false;
        border :etched, :RAISED; fixed_size 175,40
      }
      y_glue
      @field1 = text_field('Enter text here',15) {
        border :bevel, :LOWERED; fixed_size 175,24
        on_focus_gained { @field1.select_all }
      }
      y_glue
      @field2 = text_field('Enter text here',15) {
        border :bevel, :LOWERED; fixed_size 175,24
        on_focus_gained { |event,obj| obj.select_all }
      }
      y_glue
    }
  }
  # binding moved outside of Swing context
}
ctx2.my_frame.show

puts 'Binding all objects'
# create a binding context that inherits from
# our lib, and bind the objects from each app
bindery.binding_context('my_swing_lib', 'my_ctx') {
  bind('sliders') {
    ctx1.sliders.each do |slider| proto(slider); end
    ctx2.sliders.each do |slider| proto(slider); end 
  }
  bind('text fields') {
    proto(ctx1.field1.document) { obj ctx1.field1 }
    proto(ctx1.field2.document) { obj ctx1.field2 }
  
    proto(ctx2.field1.document) { obj ctx2.field1 }
    proto(ctx2.field2.document) { obj ctx2.field2 }  
  }  
}
puts 'All objects bound, try them out'
# wait a bit for the user to try them
sleep 12
puts 'Unbinding sliders, check it out'
bindery.unbind('my_ctx','sliders')
# wait a bit for the user to try them
sleep 10
puts 'Unbinding text fields, rebinding sliders, check it out'
bindery.unbind('my_ctx','text fields')
bindery.rebind('my_ctx','sliders')
# wait a bit for the user to try them
sleep 10
puts 'Rebinding text fields, check it out'
bindery.rebind('my_ctx','text fields')
# wait a bit for the user to try them
sleep 10
puts 'Unbinding context, check it out'
bindery.unbind_context('my_ctx')
# wait a bit for the user to try them
sleep 10
puts 'Rebinding context, check it out'
bindery.rebind_context('my_ctx')
# wait a bit for the user to try them
sleep 10
puts 'Unbinding and removing context, check it out'
bindery.unbind_context('my_ctx')
bindery.remove_context('my_ctx')
puts 'bye'
Home «  Prev    Contents    Next  » Download