| Home | « Prev Contents Next » | Download |
| JRBuilder: Binding Demo 5 | ||
| Even more on Binding: Translators and Converters. Unit and Type. |
|
|
|
This example is a continuation of the
previous example.
You probably want to look at that one first, if
you haven't yet.
The problem with the last example was that there were two translators exactly alike except that their input and output units were reversed. This example shows the solution I came up with. I had been thinking for a while (a week or so, at this writing it's a little over two weeks since I started writing the Bindery) that units should be classes. My first take was to make Slider and Shade subclasses of Scale. That worked, but it wasn't quite right; a slider and a color shade aren't really the same sort of thing, the scale is just a facet of their behavior. Then I had an aha! moment, and realized that mixins made much more sense. (I remembered then something that Charles Oliver Nutter had said about mapping Java interfaces as Modules, and though it doesn't exactly apply to this case, it resonated in my Java-tinged brain.) I'm still not sure if this is the best solution. Though I can't think of a compelling argument against it, there might well be a better way. As with everything else in this JRBuilder/Bindery project, I welcome your comments and suggestions. |
require 'jrbuilder'
bindery = Bindery::Bindery.new
bindery.binding_context('my_swing_lib') {
module Scale; end
class Shade; include Scale; end
class Slider; include Scale; end
property_change(java.awt.Component) {
unit Shade
type Fixnum
property_name 'background'
min_value 0
max_value 255
predicate { |event,from_attrs|
event.property_name == from_attrs[:property_name].to_s
}
getter { |obj,attribs|
color = obj.send(attribs[:property_name].to_sym)
color.send(attribs[:component])
}
setter { |obj,value,attribs|
prop = attribs[:property_name]
old_color = obj.send(prop.to_sym)
red = old_color.red
green = old_color.green
blue = old_color.blue
case attribs[:component]
when :red : red = value
when :green : green = value
when :blue : blue = value
end
obj.send((prop.to_s+'=').to_sym,java.awt.Color.new(red,green,blue))
}
}
state_changed(javax.swing.JSlider,'value') {
unit Slider
type Fixnum
min_value 0
max_value 100
}
translator(Scale,Scale,Fixnum,Fixnum) { |value,from_attrs,to_attrs|
from_min = from_attrs[:min_value]
from_range = (from_attrs[:max_value] - from_min + 1).to_f
to_min = to_attrs[:min_value]
to_range = (to_attrs[:max_value] - to_min + 1).to_f
(((value - from_min) * (to_range/from_range)) + to_min).round
}
# unneeded translator deleted
}
ctx = JRBuilder.new_swing_context(bindery)
ctx.enter {
attr_reader :my_frame
red_slider_a = nil
green_slider_a = nil
blue_slider_a = nil
red_slider_b = nil
green_slider_b = nil
blue_slider_b = nil
color_box = nil
@my_frame = frame("Binding Demo 5") { size 400,300
border :empty, 10,10,10,10
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 {
x_box {
text_area('The sliders in groups A and B are not connected directly; '+
'all events flow through the color panel',2,10) {
editable false; line_wrap true; wrap_style_word true; border :etched,:LOWERED
}
}
y_strut 10
x_box { border :compound, border(:bevel,:RAISED), border(:empty, 10,10,10,10)
y_box {
border(:titled, 'Slider Group A') { border :etched, :LOWERED }
y_box { border :empty, 10,10,10,10
red_slider_a = slider { background :RED; value 0 }
y_strut 10
green_slider_a = slider { background :GREEN; value 0 }
y_strut 10
blue_slider_a = slider { background :BLUE; value 0 }
}
}
color_box = panel {
border :bevel, :LOWERED
fixed_size 100,100
background :BLACK
}
y_box {
border(:titled, 'Slider Group B') { border :etched, :LOWERED }
y_box { border :empty, 10,10,10,10
red_slider_b = slider { background :RED; value 0 }
y_strut 10
green_slider_b = slider { background :GREEN; value 0 }
y_strut 10
blue_slider_b = slider { background :BLUE; value 0 }
}
}
}
y_strut 35
}
}
# new binding context, inherits from our swing lib
binding_context('my_swing_lib','my_app_ctx') {
# each slider is bound to the color box. notice that none
# of the sliders are bound together -- all the events
# flow through the color box.
bind('red_a') {
proto(red_slider_a)
proto(color_box) { unit Shade; component :red }
}
bind('green_a') {
proto(green_slider_a)
proto(color_box) { unit Shade; component :green }
}
bind('blue_a') {
proto(blue_slider_a)
proto(color_box) { unit Shade; component :blue }
}
bind('red_b') {
proto(red_slider_b)
proto(color_box) { unit Shade; component :red }
}
bind('green_b') {
proto(green_slider_b)
proto(color_box) { unit Shade; component :green }
}
bind('blue_b') {
proto(blue_slider_b)
proto(color_box) { unit Shade; component :blue }
}
}
}
ctx.my_frame.show
|
|
| Home | « Prev Contents Next » | Download |