Hey - thanks for the reply. At some point I was goofing around with things
and forgot to put the curly brackets and para back in - good catch. In any
case, your analysis of it gave me another idea for a solution
button "clear" do
debug @win.stack1.class
@win.stack1.append {[email protected] "yet another"}
end
That way no messy global variables or anything nor any outside window
manager. :)
Again, thanks for your help.
Chris
On Mon, Jul 6, 2009 at 7:04 PM, Ehsanul Hoque <[email protected]>wrote:
>
> Your idea is indeed clever in my opinion, but I'm just a ruby noob. Now
> let's see how one might massage the results you want.
> The real issue is with your append statement. First off, you should put
> that statement after a call to para, and inside a block, like so:
>
> @win.stack1.append { para "yet another" }
>
> But this will give you a seemingly strange result. The para will appear in
> the original window. I don't know the exact route it takes to get there, but
> you should read the Shoes => Rules section of the shoes manual to get an
> idea of why this happens. I'll try to explain in brief here. Basically, some
> way or other, the para call is sent to "self" which in this case is the
> window you create with Shoes.app. Anywhere inside the Shoes.app block, self
> is the app object, and all method calls get directed to self. When you use a
> @stack.append block, self isn't changed, but shoes has some "magic", or
> dynamic code rather, that makes sure the para that gets sent to the app
> object does indeed end up in the stack you want to append to. Now, in this
> case you're calling append on a stack in another app object, which I suppose
> shoes isn't made to deal with. Thus, the para just gets sent to self (the
> main app object), and shows up in your main window.
>
> Ok, perhaps not that brief. In any case, to solve the issue of manipulating
> an stack from outside the app object (like from another class or just
> another app object as in this case), _why has provided, in his infinite
> wisdom, an app() method for every slot (and maybe every element, but you'll
> have to check the manual to verify). What this app() method does is change
> self to the correct app object for the slot/element(?) you call app() on.
> And then, you can proceed to use whatever methods you want on it, such as
> append for example. So knowing this, you might replace the offending line
> this code, which is what I did:
>
> @win.app do
>
> @win.stack1.append { para "yet another" }
> end
>
> And then you'll get another perhaps confusing error. It'll tell you that
> nil has no stack1 method. And more confusing still, it didn't seem to think
> that @win was nil when it applied the app() method to it. So what's going
> on? Well, you have to remember that self was changed by the app block, and
> @win is just an instance variable that is available only inside an app
> instance, where you created it. So when you change self, you no longer have
> access to @win directly. To solve this problem, I set a temporary global
> variable to @win, and refer to this variable instead of @win inside the
> @win.app() block. And that way, it all works.
>
> Now, instead of keeping track of all this inside the Shoes.app block, you
> might want to create a class outside to manage your app objects. Mind you,
> you'll have to still use the app() method, and have all the same problems,
> but it's just cleaner to separate window management into it's own class in
> my opinion. And if you want to access your class instance's attributes when
> you're doing an append, you have to remember to make sure they're all
> available as global variables, or figure some other way to do it, because
> they won't be automatically available, even though the code is in your
> instance method definition. This has bit me a number of times. I just set up
> a globalize() instance method which allows access to all the attributes
> globally as $temp[:attribute_name].
>
> Hmm, I've written too much already. Here's the code with the fixes, just
> copy paste:
>
> $temp = {}
> Shoes.app do
> self.class.class_eval do
> attr_accessor :tribute, :stack1
> end
>
> @tribute = "main app"
> button "new window" do
> @win = window :title => "new window" do
>
> @stack1 = stack {para "this is a paragraph"}
> end
> end
>
> button "clear" do
> debug @win.stack1.class
> $temp[:win] = @win
> @win.app do
> $temp[:win].stack1.append { para "yet another" }
> end
> end
> end
>
> Subject: attribute access among multiple windows
> From: [email protected]
> To: [email protected]
> Date: Mon, 6 Jul 2009 12:12:35 -0700
>
> Hey there - I am having trouble figuring out the best way to access
> attributes among multiple windows. What I want is a main Shoes.app window
> that spawns windows which can exchange data with the main Shoes.app window.
> What I would like to do, is somehow keep track of all of the Shoes::APP
> objects which belong to the main app and be able to access ad modify their
> attributes. I thought that I had a clever idea when I did this
>
>
> Shoes.app do
> self.class.class_eval do
> attr_accessor :tribute, :stack1
> end
>
>
> @tribute = "main app"
> button "new window" do
> @win = window :title => "new window" do
>
> @stack1 = stack {para "this is a paragraph"}
> end
>
> end
> button "clear" do
> debug @win.stack1.class
> @win.stack1.append "yet another"
> end
> end
>
>
> When I hit the "clear" button on the main window the first time, I get
>
> debug => Shoes::Stack
> Error => undefined method `call' for nil:NilClass
>
> The next time I hit it, I get this
>
>
>
> debug => Shoes::Stack
>
> Error => this slot is already being modified by an append, clear, etc
>