Ahh, that's smart. A much more elegant solution, I wish I had thought of this before. Well, now I can use this idea to clean up some of my code. :)
Subject: Re: attribute access among multiple windows From: [email protected] To: [email protected] Date: Mon, 6 Jul 2009 20:45:52 -0700 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 _________________________________________________________________ Insert movie times and more without leaving HotmailĀ®. http://windowslive.com/Tutorial/Hotmail/QuickAdd?ocid=TXT_TAGLM_WL_HM_Tutorial_QuickAdd_062009
