Tutorial: Creating your own window handlers
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 end
The 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 end
The 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?(:B) return process_pagedown if handle?(:pagedown) && Input.trigger?(:R) return process_pageup if handle?(:pageup) && Input.trigger?(:L) end
You 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.
1. Choose a name for your handler. Something intuitive would be nice.
2. 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.
3. Decide what methods will be triggered for each handler.
4. Call `set_handler` and assign a handler to your window, using the name and method that you picked above.
5. 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.
Checking active window
One thing to be careful of is to remember that you must check whether the window is open and active. If you look at the process_handling method, you will notice that the first line is to check whether it is open and active.
You must remember to check this otherwise your handlers may not behave correctly.
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