Ruby/Tk: How to access surrounding class from Tk Callback?

Discussion in 'Ruby' started by Ronald Fischer, Feb 27, 2006.

  1. Assume that I'm modelling a visible form, consisting of entry fields,
    buttons etc., as a class:

    require 'tk'
    class Form
    def initialize(...)
    @foo=1234
    ...
    @root=TkRoot.new() { title "My Form" }
    action_button=TkButton.new(@root) {
    text "Action!"
    command {
    # Do something with @root and @foo
    puts @root.foo # DOES NOT WORK
    }
    }
    action_button.pack("side" => "right");
    end
    end

    The problem is with the command routine inside the action_button:
    Both @root and @foo are undefined here. Obviously, the class context
    is not present anymore inside this callback function.

    How would one model this situation in Ruby? In C++ terms: How do
    I pass the 'this' pointer of my class into the command callback
    of the button?

    In my case, I happen to have only one instance of the Form, so
    I could use a global variable, $form, to hold a reference to my
    Form object and access it via this global, but of course this
    solution would be ugly beyond imagination...

    Kind regards,

    Ronald





    --
    Sent by mn-pg-p-e-b-consultant-3.com from siemens subdomain of com
    This is a spam protected message. Please answer with reference header.
    Posted via http://www.usenet-replayer.com
    Ronald Fischer, Feb 27, 2006
    #1
    1. Advertising

  2. From: -mobilphone.net (Ronald Fischer)
    Subject: Ruby/Tk: How to access surrounding class from Tk Callback?
    Date: Mon, 27 Feb 2006 21:18:35 +0900
    Message-ID: <>
    > @root=TkRoot.new() { title "My Form" }
    > action_button=TkButton.new(@root) {
    > text "Action!"
    > command {
    > # Do something with @root and @foo
    > puts @root.foo # DOES NOT WORK
    > }
    > }


    It may be a FAQ.
    A block given to <TkWidget-class>.new method is
    evaluated by <the widget>.instance_eval(<the block>).
    That is, in the block, 'self' is the widget object.
    So, @root in your button's command is an instance variable
    of the button widget.
    To avoid it, you have to give attention to scope of variables.
    For example,
    ------< example 1 >------------------------------------------
    def initialize(...)
    foo = @foo=1234
    ...
    root = @root = TkRoot.new() { title "My Form" }
    action_button=TkButton.new(@root) {
    text "Action!"
    command {
    # use local variables
    puts foo # same as @foo
    puts root # same as @root
    }
    }
    action_button.pack("side" => "right");
    end
    -------------------------------------------------------------
    ------< example 2 >------------------------------------------
    def initialize(...)
    @foo=1234
    ...
    @root = TkRoot.new() { title "My Form" }
    action_button=TkButton.new(@root,
    :text=>"Action!",
    :command=>proc{
    puts @foo
    puts @root
    })
    action_button.pack("side" => "right");
    end
    -------------------------------------------------------------
    ------< example 3 >------------------------------------------
    def initialize(...)
    @foo=1234
    ...
    @root = TkRoot.new() { title "My Form" }
    cmd = proc{
    puts @foo
    puts @root
    }
    action_button=TkButton.new(@root) {
    text "Action!"
    command cmd
    }
    action_button.pack("side" => "right");
    end
    -------------------------------------------------------------
    --
    Hidetoshi NAGAI ()
    Hidetoshi NAGAI, Feb 27, 2006
    #2
    1. Advertising

  3. Re: Re: Ruby/Tk: How to access surrounding class from Tk Callback?

    Hidetoshi NAGAI wrote:
    > From: -mobilphone.net (Ronald Fischer)
    > > @root=TkRoot.new() { title "My Form" }
    > > action_button=TkButton.new(@root) {
    > > text "Action!"
    > > command {
    > > # Do something with @root and @foo
    > > puts @root.foo # DOES NOT WORK
    > > }
    > > }

    >
    > It may be a FAQ.


    Arigatou gozaimasu! But where can I find the FAQ? I was able to
    locate one only in Japanese, and my Japanese is barely sufficient
    to order some Yakitori, let alone reading such a FAQ.... :-(

    Aside from a FAQ, a Ruby/Tk reference manual might be handy. Right
    now I am "learning" Ruby/Tk by looking at examples I find on the
    net, and *guessing* how they could work - not a very satisfying
    means to grasp a new language.

    > A block given to <TkWidget-class>.new method is
    > evaluated by <the widget>.instance_eval(<the block>).
    > That is, in the block, 'self' is the widget object.
    > So, @root in your button's command is an instance variable
    > of the button widget.


    I understand.

    > To avoid it, you have to give attention to scope of variables.
    > For example,
    > ------< example 1 >------------------------------------------
    > def initialize(...)
    > foo = @foo=1234
    > ...
    > root = @root = TkRoot.new() { title "My Form" }
    > action_button=TkButton.new(@root) {
    > text "Action!"
    > command {
    > # use local variables
    > puts foo # same as @foo
    > puts root # same as @root
    > }
    > }
    > action_button.pack("side" => "right");
    > end


    I amazed that this works, but I don't know how. foo is a local
    variable inside initialize, isn't it? So it should go out of scope
    as soon as initialize ends. How then can I refer to it from inside
    my action command?

    > ------< example 2 >------------------------------------------
    > def initialize(...)
    > @foo=1234
    > ...
    > @root = TkRoot.new() { title "My Form" }
    > action_button=TkButton.new(@root,
    > :text=>"Action!",
    > :command=>proc{
    > puts @foo
    > puts @root
    > })
    > action_button.pack("side" => "right");
    > end


    Here I have two questions: What is the meaning of the
    colon in front of "command", and why can I access @root
    now from inside command, but not in my original code?

    > ------< example 3 >------------------------------------------
    > def initialize(...)
    > @foo=1234
    > ...
    > @root = TkRoot.new() { title "My Form" }
    > cmd = proc{
    > puts @foo
    > puts @root
    > }
    > action_button=TkButton.new(@root) {
    > text "Action!"
    > command cmd
    > }
    > action_button.pack("side" => "right");
    > end


    This looks clever too. From a design point of view, I like solution 2
    best, because it avoids the need for additional variables. Still would
    like to understand, *why* it works.

    Ronald






    --
    Spam protected message from:
    Sent by mn-pg-p-e-b-consultant-3.com from siemens in field com
    Posted via http://www.usenet-replayer.com
    Ronald Fischer, Mar 1, 2006
    #3
  4. Re: Re: Re: Ruby/Tk: How to access surrounding class from Tk Callback?

    > > ------< example 2 >------------------------------------------
    > > def initialize(...)
    > > @foo=1234
    > > ...
    > > @root = TkRoot.new() { title "My Form" }
    > > action_button=TkButton.new(@root,
    > > :text=>"Action!",
    > > :command=>proc{
    > > puts @foo
    > > puts @root
    > > })
    > > action_button.pack("side" => "right");
    > > end

    >
    > Here I have two questions: What is the meaning of the
    > colon in front of "command", and why can I access @root
    > now from inside command, but not in my original code?


    I think, I figured this out by myself: Instead of setting
    text and command in an initialization procedure for the button,
    you supply them as parameter :)command denotes the named parameter
    "command" - I had used only positional parameters before, so I
    was not aware of this possibility). Since the command procedure
    is defined inside the list of actual parameters to the TkButton
    constructor, they can access any variable within the scope of
    the initialize function body; in particular, they can access
    the member variables of the surrounding class.

    Ronald







    --
    Spam protected message from:
    Sent by mn-pg-p-e-b-consultant-3.com from siemens part of com
    Posted via http://www.usenet-replayer.com
    Ronald Fischer, Mar 1, 2006
    #4
  5. From: -mobilphone.net (Ronald Fischer)
    Subject: Re: Ruby/Tk: How to access surrounding class from Tk Callback?
    Date: Wed, 1 Mar 2006 17:48:37 +0900
    Message-ID: <>
    > Arigatou gozaimasu! But where can I find the FAQ?


    If I am right, I'd wrote a same answer on this ML. ;-)

    > Aside from a FAQ, a Ruby/Tk reference manual might be handy. Right
    > now I am "learning" Ruby/Tk by looking at examples I find on the
    > net, and *guessing* how they could work - not a very satisfying
    > means to grasp a new language.


    I want to compose Ruby/Tk manuals/documents.
    But I don't have enough time and collaborators to do that.
    And it is so hard for me to translate them to English,
    because I'm poor at English.

    > > ------< example 1 >------------------------------------------

    (snip)
    > I amazed that this works, but I don't know how. foo is a local
    > variable inside initialize, isn't it? So it should go out of scope
    > as soon as initialize ends. How then can I refer to it from inside
    > my action command?


    A Proc object keeps its binding.

    > > ------< example 2 >------------------------------------------

    (snip)
    > Here I have two questions: What is the meaning of the
    > colon in front of "command",


    ":command" is a symbol.
    Current Ruby/Tk can accept a string or a symbol as a key of an option.

    FYI, a has of options is a little faster than method calls.
    For example,
    ---------------------------------------------------------------------
    action_button=TkButton.new(@root, :text=>"Action!",:command=>cmd)
    ---------------------------------------------------------------------
    this calls the Tk interpreter only once.
    But,
    ---------------------------------------------------------------------
    action_button=TkButton.new(@root) { # <= 1
    text "Action!" # <= 2
    command cmd # <= 3
    })
    ---------------------------------------------------------------------
    this calls Tk interpreter three times.

    > and why can I access @root
    > now from inside command, but not in my original code?


    It depends on the difference of scope.
    In the block given to TkButton.new, 'self' is the button object.
    But the proc object is defined in the scope of 'initialize'.

    > > ------< example 3 >------------------------------------------

    (snip)
    > This looks clever too. From a design point of view, I like solution 2
    > best, because it avoids the need for additional variables. Still would
    > like to understand, *why* it works.


    The answer is same as the one for < example 1 >.
    --
    Hidetoshi NAGAI ()
    Hidetoshi NAGAI, Mar 8, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Simon Harvey
    Replies:
    4
    Views:
    552
    Jon A. Cruz
    Jul 22, 2003
  2. Doug Estep
    Replies:
    4
    Views:
    733
    Oliver Bonten
    Feb 2, 2004
  3. Piet
    Replies:
    1
    Views:
    592
  4. Luke Randall
    Replies:
    1
    Views:
    112
    Reyn Vlietstra
    Oct 7, 2005
  5. Bryan Richardson
    Replies:
    0
    Views:
    110
    Bryan Richardson
    Jan 28, 2009
Loading...

Share This Page