This document is only applicable for Guichan 0.7.0 and upwards, however most part of the document also applies for Guichan 0.6.0.
Events
Guichan comes with a sophisticated event system much like the event system found in Java. Events are very important to understand in order to fully be able to use Guichan.
The event hierarchy
All events in Guichan is a part of the event hierarchy which is made of a couple of classes presented below:
Where Event is the base class, ActionEvent represents an action event triggered by a widget, InputEvent represents an input event, KeyEvent represents a key input event, MouseEvent represents a mouse input event and FocusEvent represents a focus event.
Receiving events
To be able to receive events one must implement a listener which listens for a certain type of event. In Guichan there exists a listener interface for each type of event which can be received. All events concerns a widget and all that is required to receive events concerning a widget is to add an implemented listener to the widget. As soon as an event is fired all listeners of the widget will be notifed.
A widget can listen for events which concerns the widget itself, this is how most widgets in Guichan is implemented, a button for instance implements the MouseListener interface and listens for mouse events on itself. How to implement a listener for a certain type of event and how the event is distributed is explained later on.
Basic events
All events derives from the Event base class. How events are distributed and when they are distributed depends on the event type, but all events have a widget in common called the source widget which is the widget the event concerns. All events can get the source widget by calling the Event::getSource function.
void MyCustomWidget::action(const ActionEvent& actionEvent) { Widget* sourceWidget = actionEvent.getSource(); }
Input events
Input events are events which concerns input. The input is either key input or mouse input. All input events are consumable. However, if an input event is consumed it's merely marked as consumed, it's up the receiver of the event to take a different action if an event has been consumed (this is going to be illustrated later on when discussing mouse input).
To consume an input event the InputEvent::consume function is used. To check if an input event has been consumed the InputEvent::isConsumed is used.
void MyCustomWidget::mouseWheelMovedDown(MouseEvent& mouseEvent) { mouseEvent.consume(); }
Key events
Key events are events which concerns key input. They fire as soon as key input is received by Guichan and will always have the widget with focus as the source widget. Key events are only distributed to the key listeners of the source widget.
Recieving key events
To receive key events one must implement the KeyListener interface.
#include <guichan.hpp> #include <iostream> class MyKeyListener : public gcn::KeyListener { void keyPressed(gcn::KeyEvent& keyEvent) { std::cout << "Key pressed: " << keyEvent.getKey().getValue() << std::endl; } void keyReleased(gcn::KeyEvent& keyEvent) { std::cout << "Key released: " << keyEvent.getKey().getValue() << std::endl; } };
To receive key events from a button add the implementation as a key listener of a button.
MyKeyListener myKeyListener; gcn::Button button; void foo() { button.addKeyListener(&keyListener); }
Most implemented widgets in Guichan which uses key input are key listeners themselves and listen for key events on themselves.
#include <guichan.hpp> #include <iostream> class MyCustomWidget: public gcn::Widget, public gcn::KeyListener { public: MyCustomWidget() { // The widget needs to be focusable in order to receive key events. setFocusable(true); addKeyListener(this); } void keyPressed(gcn::KeyEvent& keyEvent) { std::cout << "Key pressed: " << keyEvent.getKey().getValue() << std::endl; } void keyReleased(gcn::KeyEvent& keyEvent) { std::cout << "Key released: " << keyEvent.getKey().getValue() << std::endl; } };
Mouse events
Mouse events are events which concerns mouse input. They fire as soon as mouse input is received by Guichan. Mouse events are distributed to the mouse listeners of the widget directly under the mouse and to the mouse listeners of the parents of the widget directly under the mouse.
For instance, concider the case where a button is placed in a window and the window is placed in a container. If the button is pressed with the mouse all mouse listeners of the button will receive the mouse press followed by all mouse listeners of the window and finally followed by all mouse listeners of the container. Note that the source of the event will always be the widget directly under the mouse, in this case the button, even if other widget mouse listeners receive the event, such as the mouse listeners of the window and the container.
Mouse events always travels upwards in the placement hierarchy, a bottom up approuch. The reason for this is that if a widget, like the button, is pressed with the mouse the widget's container, like the window, is also pressed and should also receive the mouse event.
There exists one exception to the bottom up distribution and that is mouse entered and mouse exited events, they are only - like key events - distributed to the mouse listeners of the source widget of the event, in this case to the mouse listeners of the widget directy under the mouse.
Chain of responsibility
The design of bottom up distribution introduces a chain of responsibility. If a widget needs to consume an input, like a slider wants to consume mouse wheel events, widgets acting on the same event, such as a scroll area, should discard the input if it has been consumed.
Recieving mouse events
To receive mouse events one must implement a mouse listener.
#include <guichan.hpp> #include <iostream> class MyMouseListener : public gcn::MouseListener { void mousePressed(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseReleased(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseClicked(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse clicked: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseMoved(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse moved: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseEntered(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse entered: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseExited(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse exited: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse wheel down moved: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse wheel up moved: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseDragged(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse dragged: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } };
To receive mouse events from a button add the implementation as a mouse listener of a button.
MyMouseListener myMouseListener; gcn::Button button; void foo() { button.addMouseListener(&MouseListener); }
As with key events most implemented widgets in Guichan which uses mouse input are mouse listeners themselves and listen for mouse events on themselves.
#include <guichan.hpp> #include <iostream> class MyCustomWidget: public gcn::Widget, public gcn::MouseListener { public: MyCustomWidget() { addMouseListener(this); } void mousePressed(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } void mouseReleased(gcn::MouseEvent& mouseEvent) { std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl; } };
Action events
Action events are events which concerns widgets. An action event is fired by a widget and distributed to all action listeners of the widget, thus the source of the event is the widget that fires the event. What makes the widget fire an action event depends on the widget. An example of an action event is a button which is pressed or a list box where an item in the list is selected.
Receiving action events
To receive action events one must implement an action listener. In the example below the action id of the event is printed. The action id is a string which can be set to all widgets by calling Widget::setActionId. A neat thing with the action id is that two widgets can have the same action id and that way two widgets actions can be treated equally with the same action listener.
#include <guichan.hpp> #include <iostream> class MyActionListener : public gcn::ActionListener { void action(const gcn::ActionEvent& actionEvent) { std::cout << "Action : " << actionEvent.getId() << std::endl; } };
To receive action events from a button add the action listener implementation to the action listeners of the button.
MyActionListener myActionListener; gcn::Button button; void foo() { button.addActionListener(&myActionListener); }
Death events
Death events are events which concerns the death of a widget. When a widget dies, or it's destructor is called, it sends a death event to all it's death listener. The source widget is of course the widget. Death events, unlike other events, doesn't have it's own event class but utilises the Event class. This is because the only relavent information of a death of a widget is the source widget.
Receiving death events
To receive death events one must implement a death listener.
#include <guichan.hpp> #include <iostream> class MyDeathListener : public gcn::DeathListener { void death(const gcn::Event& event) { std::cout << "Death : " << event.getSource() << std::endl; } };
To receive death events from a button add the death listener implementation to the death listeners of the button.
MyDeathListener myDeathListener; gcn::Button button; void foo() { button.addDeathListener(&myDeathListener); }
Focus events
Focus events are events which concerns focus of a widget. When a widget gets focus or loses focus a focus event is sent to all focus listeners of the widget. The source widget is of course the widget the focus concerns. Focus events doesn't have it's own event class but utilises the Event class. This is because the only relavent information of a focus event is the source widget.
Receiving focus events
To receive focus events one must implement a focus listener.
#include <guichan.hpp> #include <iostream> class MyFocusListener : public gcn::FocusListener { void focusGained(const gcn::Event& event) { std::cout << "Focus gained: " << event.getSource() << std::endl; } void focusLost(const gcn::Event& event) { std::cout << "Focus lost : " << event.getSource() << std::endl; } };
To receive focus events from a button add the focus listener implementation to the focus listeners of the button.
MyFocusListener myFocusListener; gcn::Button button; void foo() { button.addFocusListener(&myFocusListener); }