Tsukihime 1,489 Posted July 14, 2013 (edited) This tutorial describes how you can create your own window handlers for any windows that you use for your scene. Some other environments call them "event listeners". For more information you can read the wiki article on the general concept. Handlers allow the window to communicate with the scene. For example, when you're in the item menu and selecting an item to use, when you press the OK button, the item window will tell the scene that the OK button was triggered, and the scene calls the "on_item_ok" method accordingly. But how does the window know that it has an OK handler? And how does the window know what method to call? This tutorial will answer the two questions, and you should be able to create your own custom handlers. Assigning Handlers Handlers are usually assigned to windows in the scene, using the `set_handler` method. This method is defined as follows in Window_Selectable: #-------------------------------------------------------------------------- # * Set Handler Corresponding to Operation # method : Method set as a handler (Method object) #-------------------------------------------------------------------------- def set_handler(symbol, method) @handler[symbol] = method endThe symbol is just any name you want to give for your handler.The method is the method that will be called when this handler is called. Look at how Scene_Item creates the item window: def create_item_window wy = @category_window.y + @category_window.height wh = Graphics.height - wy @item_window = Window_ItemList.new(0, wy, Graphics.width, wh) @item_window.viewport = @viewport @item_window.help_window = @help_window @item_window.set_handler(:ok, method(:on_item_ok)) @item_window.set_handler(:cancel, method(:on_item_cancel)) @category_window.item_window = @item_window endThe important part is these two lines:@item_window.set_handler(:ok, method(:on_item_ok)) @item_window.set_handler(:cancel, method(:on_item_cancel))The scene assigns two handlers to the item window, an "ok" handler, which will call the scene's "on_item_ok" method, as well as a "cancel" handler, which will call the "on_item_cancel" method. Both of these methods are defined in the scene. The way these handlers are called is done in the `process_handling` method in Window_Selectable: def process_handling return unless open? && active return process_ok if ok_enabled? && Input.trigger?(:C) return process_cancel if cancel_enabled? && Input.trigger?(: return process_pagedown if handle?(:pagedown) && Input.trigger?(:R) return process_pageup if handle?(:pageup) && Input.trigger?(:L) endYou can see that the selectable window checks for four types of handles, depending on which button is pressed. If you press the "C" button, it will call the method associated with the "ok" handler. If you press the "B" button, it will call the method that is associated with the "cancel" handler. Creating your own handler What you have seen above is basically all there is to handlers: the scene assigns some handlers to the window, giving the handler a name and a callback method, and the window then checks whether any of the handlers are called and calls the appropriate method attached to the handler. The steps for creating your handlers is summarized below. Choose a name for your handler. Something intuitive would be nice. Decide how you want this handler to be triggered. It can be a keypress, or any other boolean expression. For example, maybe you want a handler to be triggered every 5 seconds by checking some sort of timer. Decide what methods will be triggered for each handler. Call `set_handler` and assign a handler to your window, using the name and method that you picked above. add the handling logic inside `process_handling` to your window according to what you have decided in step 2. Following this procedure, you should be able to easily define custom handlers for your windows. Example Here is a working example that adds custom handlers to the item window in the item scene that will be triggered whenever you press the left or right keys. I use the procedure described above. 1. Decide on handler names Since the handlers will be triggered when I press the left or right keys, I will just call them `:left` and `:right` 2. Decide how the handlers are triggered They will be triggered when I press the left or right keys. This can be accomplished using the following calls: if Input.trigger?(:LEFT) if Input.trigger?(:RIGHT)3. Decide what methods will be triggered For demonstration purposes, I will simply print out "left" or "right" to the console, depending on which key I pressed. def on_item_left p 'LEFT' @item_window.activate end def on_item_right p 'RIGHT' @item_window.activate end 4. Assign the handlers to the window This is straightforward enough at this point. Just calling the set_handler method and assigning the two handlers as required: @item_window.set_handler(:left, method(:on_item_left)) @item_window.set_handler(:right, method(:on_item_right))5. Add the handling logic to the window This is also pretty much just copying what you see from the default method return call_handler(:left) if handle?(:left) && Input.trigger?(:LEFT) return call_handler(:right) if handle?(:right) && Input.trigger?(:RIGHT)It is not necessary to check whether the handlers are defined if you are using a custom window because chances are they will be defined. Window_Selectable is only written that way because you may have windows that do not assign all of those handlers. At this point, if you load up your game, add some items to your inventory, and then scroll through your item list, you should see the appropriate string printed out to the console if you press left or right. Here is the full code: class Scene_Item < Scene_ItemBase alias :th_input_handler_create_item_window :create_item_window def create_item_window th_input_handler_create_item_window @item_window.set_handler(:LEFT, method(:on_item_left)) @item_window.set_handler(:RIGHT, method(:on_item_right)) end def on_item_left p 'LEFT' @item_window.activate end def on_item_right p 'RIGHT' @item_window.activate end end class Window_ItemList < Window_Selectable alias :th_input_handler_process_handling :process_handling def process_handling return unless open? && active th_input_handler_process_handling return call_handler(:LEFT) if handle?(:LEFT) && Input.trigger?(:LEFT) return call_handler(:RIGHT) if handle?(:RIGHT) && Input.trigger?(:RIGHT) end end Edited July 25, 2013 by Tsukihime 4 Share this post Link to post Share on other sites
Polidoro 104 Posted July 14, 2013 very nice tutorial. its short, simple, and to the point. i like that you really explain the steps as what they do, why the do, and why its important to 'do'. looking forward to seeing more of these. Share this post Link to post Share on other sites
TroyZ 1 Posted July 18, 2013 nice tutorial tsuki i'm waiting for your another rgss3 tutorial Share this post Link to post Share on other sites
heartbreak61 9 Posted July 18, 2013 Is it possible to pass arguments? such as @new_window.set_handler(:ok, method(a_methos(*args)))btw, nice tutorial you wrote there (: Share this post Link to post Share on other sites
Tsukihime 1,489 Posted July 18, 2013 (edited) You pass arguments when you call the callback method @new_window.set_handler(:ok, method(some_method)) def some_method(your_arg) ... end Then your window handle processing would pass in argumentsdef call_ok_handler @handler[symbol].call("my arg") end Edited July 18, 2013 by Tsukihime Share this post Link to post Share on other sites
estriole 326 Posted July 22, 2013 (edited) hime. i have a problem when making handler in two windows using same button input. i want to make two windows which switch to each other when i press shift. ex: currently active: windows a. press shift. deactivate windows a. activate window b. then press shift again deactivate window b and activate window a. i think i set the handler right. and also give condition to button. but when i press shift. the windows didn't switch. (maybe switch but switch back immediately). apparently the input:A stuck in memory and then when entering the conditional it immediately call the handler. if i add Input.update in the method. it switch correctly. but i cannot press shift button again to return to previous window. here's the code to insert the handler part. window 1 class Window_MagsItem < Window_EquipItem alias est_mags_process_handling process_handling def process_handling est_mags_process_handling return process_shift if handle?(:shift) && Input.trigger?(:A) end def process_shift call_handler(:shift) end end window 2 class Window_MagsSkill < Window_Command alias est_mags_process_handling process_handling def process_handling est_mags_process_handling return process_shift if handle?(:shift) && Input.trigger?(:A) end def process_shift call_handler(:shift) end end in Scene def create_item_window # i only include the part where i set the handler since it's long @item_window = Window_MagsItem.new(wx, wy, ww, wh) @item_window.set_handler(:shift, method(:on_item_shift)) end def create_mags_skill_window # i only include the part where i set the handler since it's long @mags_skill_window = Window_MagsSkill.new(wx, wy, ww, wh) @mags_skill_window.set_handler(:shift, method(:on_mags_shift)) end def on_item_shift @item_window.deactivate @mags_skill_window.activate Input.update end def on_mags_shift @mags_skill_window.deactivate @mags_skill_window.select_last @item_window.activate end if i remove the Input.update line. it will still @item_window which activate after i press shift in @item_window. i also try adding Input.update to below method. but it have no effect. does it have difference because the second window is child of window_command? for now i modify to use ok handler and cancel handler to switch back to previous window but i want to able to switch window using shift. any advice? . Edited July 22, 2013 by estriole Share this post Link to post Share on other sites
Tsukihime 1,489 Posted July 24, 2013 It's the input updating that's causing issues, though I am not too sure why. Share this post Link to post Share on other sites
estriole 326 Posted July 25, 2013 Yeah I think there's something wrong with the input module. I also encounter same issue with parallel process event before. I create event. When I talk to event. I make it show two choices: talk and move. When I choose move. The event will go to page with these setting: Paralel process. With condition input trigger left, right, up, down. But the problem is when using input trigger :c as condition(I want to make when press enter stop move mode). It will executed immediately instead. It's like the input :c already pressed (it read from previous page we press enter to choose 'move'. And it stuck). in that event I finally make turnaround way by adding another conditional selfswitch b on to that input :c. Then turn on selfswitch b when I already made 'movement'. Guess have to think another turnaround with this window too then >.< Share this post Link to post Share on other sites
Tsukihime 1,489 Posted July 25, 2013 (edited) I found the problem. I forgot to update this tutorial post, but you have to check that the window is active def process_handling return unless open? && active est_mags_process_handling return process_shift if handle?(:shift) && Input.trigger?(:A) end Then it should work. In any case, there is no problem with the Input module. You are likely just not understanding how it works and think it is supposed to behave a certain way. You should do more tests to understand the difference between trigger?, repeat?, press?, and how Input.update affects these methods. There is a reason why it is important to call Input.update. Edited July 25, 2013 by Tsukihime 1 Share this post Link to post Share on other sites
estriole 326 Posted July 26, 2013 Ah yes. I thought the return unless open and active 'already' included in the aliased method. But I forgot. It since it's in the aliased method. It return from the aliased method only. Means back to the process handling method. Then execute the next line in the method. Thus extra return unless open and active is needed . Thx hime for pointing it out. Now I can finish the first part of my script. Share this post Link to post Share on other sites
siChainlinks 20 Posted August 20, 2013 Great tutorial! I've been struggling through trying to read how the core modules do this, and then I stumbled on this. You're a life-saver! Share this post Link to post Share on other sites