gutopia-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [rgui-dev] binding only to exposure


From: Massimiliano Mirra
Subject: Re: [rgui-dev] binding only to exposure
Date: Fri, 16 Aug 2002 04:43:21 +0200
User-agent: Mutt/1.3.28i

On Thu, Aug 08, 2002 at 09:02:41PM -0600, Tom Sawyer wrote:
> let me put the problem of only being able to bind to the exposed
> portions of an object via its accessor methods antoher way:
> 
>   class X
>     attr_accessor :a, :b
>     def initialize
>       @a = 'string'
>       @b = [ 'an', 'array' ]
>     end
>   end
> 
> so here's a dummy class. now lets say i want to give this a gui such the
> user sees the values of a and b on the screen, with a as a label and b
> as a list (we'll leave out the window definition and all that jazz for
> the sake of brevity):
> 
>   x = X.new  # Model/Logic/Core-Application (whatever name)
> 


>   la = Label.new; la.value = x.a
>   lb = List.new; lb.items = x.b
> 
> okay so far so good. now we wish to bind to them such that if a or b
> should change (by whatever means), the gui will reflect that.
> 
>   x.bind(:a=) { |x| la.value = x }
>   x.bind(:b=) { |x| lb.items = x }

(As an aside and not strictly related to the subject of the post: the
meaning in the two lines of code above might well be made implicit in
the two lines of code below.)

> 
> cool. when #a= or #b= is called the gui will reflect the change. now
> lets say that class X has an additonal method that does this:
> 
>   def update_from_query
>     @a = query('a')
>     @b << query('b')
>   end
> 
> with this we're going to run into a problem becasue @a and @b are being
> changed "beneath the hood" and our gui bindings won't catch it. our
> programmer might be told, it is incorrect form to use @ in the method
> and he should use the accessor methods instead. okay he says, i'll
> change it:
> 
>   def update_from_query
>     self.a = query('a')
>     self.b << query('b')
>   end
> 
> well, that helps, even though we had to alter our Model to work for the
> gui, at least now a is being caught. But b still is not. how do we
> account for that? the only means (that i can think of, at least) are to
> catch on update_from_query and modify all relevant bindings:
> 
>   x.bind(:update_from_query) {
>     la.value = x.a
>     lb.value = x.b
>   }
> 
> so our problem is solved, but i must ask, at what cost? this is a very
> simple dummy class we are working with. think of how involved it would
> be to do this for something complex. every method that modified any
> pertenant variables would require a binding with a proc specifying how
> each of those variables are to modify the gui. this can quickly become a
> very large task.
> 
> for a simple example of what i mean just imagine trying to give a gui to
> the an object of type Array in and of itself. you'd have to bind on <<,
> sort!, compact!, reverse!, and on and on, for every method that altered
> the contents of the array, so that any changes would be "automagically"
> reflected/ this simply becomes too unweildy.


Here is a costly way (but we're implementing Observer, and Observer
almost always trades performance for simplicity):


class GuiManager 
  def initialize(model)
    @model = model
  end

  def watch_changers(*methods)
    methods.each do |method|
      # append code to each watched method that calls the GuiManager
      # change_event whenever that method is called
    end
  end

  def set_update_proc(&block)
    @update_proc = &block
  end

  def change_event
    @update_proc.call
  end 
end

x = X.new
gui_manager = GuiManager.new(x)

gui_manager.watch_methods 'a=', 'b=', 'update_from_query', ...

gui_manager.set_update_proc do |model|
  label.value = model.a
  list.items = model.b  
end


Now, when a `changer' method is called on the model, the update
procedure defined with set_update_proc is called immediately
afterwards and updates the interface.  The setup is very simple.  

The performance tradeoff is clear: all interface gets refreshed, even
though only a small part of the data has changed.  This is very likely
to cause slowness in the bigger applications.

What workarounds can be used?  Maybe dirty/clean flags somewhere to
tell the changed data (in need of interface update) from the
unchanged.  Or a more precise (yet less quick) setup:

gui_manager.bind_setter_getter('a=', ['a'])
gui_manager.bind_setter_getter('b=', ['b'])
gui_manager.bind_setter_getter('update_from_query', ['a', 'b'])



Massimiliano




reply via email to

[Prev in Thread] Current Thread [Next in Thread]