Event Handling in SavvyUI: A Complete Developer Guide
SavvyUI is a powerful and feature‑rich C++ component library for building modern Windows desktop applications. It provides a robust set of UI components, flexible layouts, and native performance — but at the heart of every interactive desktop application lies event handling: the mechanism by which your app responds to user actions like button clicks, menu selections, mouse movements, or keyboard input. :contentReference[oaicite:1]{index=1}
In this complete developer guide, we’ll explore how event handling works in SavvyUI, how to implement it effectively in your applications, what listener interfaces to use, and practical examples you can build on for real‑world software.
Understanding Event‑Driven Architecture in SavvyUI
At its core, SavvyUI uses a traditional event‑driven programming model. Components such as buttons, menus, and list boxes don’t do anything on their own — instead, they generate notifications (events) when user interactions occur. Your application responds to these events by implementing listener interfaces that handle specific event types.:contentReference[oaicite:2]{index=2}
For example, when a user clicks a button, SavvyUI generates an ActionEvent. You can capture this event by implementing the ActionListener interface and overriding its handler method. This approach lets your components remain modular and your business logic centralized.
The Key Listener Interfaces
SavvyUI defines several listener types that correspond to different kinds of events. These listener interfaces are typically declared in the EventListeners.h header included with the SavvyUI SDK.:contentReference[oaicite:3]{index=3}
ActionListener
This is one of the most common listener interfaces in SavvyUI. You implement ActionListener to catch action events such as button presses or menu item selections. It defines the single pure virtual method:
virtual void onAction(const ActionEvent &ev) = 0;
Classes like buttons and toolbar items notify registered listeners when the user triggers an action.:contentReference[oaicite:4]{index=4}
SelectionChangeListener
For controls that support selection — like list boxes, checklists, tree views, or radio groups — implement SelectionChangeListener to respond when the selection changes. For example, when a user selects a new item in a TreeView, this listener can fire and pass along details about the new selection.:contentReference[oaicite:5]{index=5}
RowDoubleClickListener
For components that present rows of data (such as grids or lists), you can implement this listener to react when the user double‑clicks a row. This is useful for actions like opening an item’s details or triggering a dialog.:contentReference[oaicite:6]{index=6}
Other Virtual Event Methods
Beyond explicit listener interfaces, many SavvyUI components also expose virtual callback methods that you can override in derived classes to handle events such as mouse movement, key presses, timers, focus changes, and more. These are part of the internal component structure and give you a finer‑grained control over interaction behavior.:contentReference[oaicite:7]{index=7}
Registering Listeners and Handling Actions
To make your application responsive, you first register listener instances on UI components. For example, buttons support an API like addActionListener(this), which links your class’s listener implementation to the button’s event emitter. When the user interacts with the button, the registered listener will receive an ActionEvent.:contentReference[oaicite:8]{index=8}
class MyAppFrame : public Frame, public ActionListener {
Button myButton;
public:
MyAppFrame() {
myButton.setText(L"Click Me");
myButton.addActionListener(this); // Register listener
}
void onAction(const ActionEvent &ev) override {
if (ev.actionName == L"Click Me") {
DialogFactory::showInfo(this, L"Button clicked!");
}
}
};
In this example, clicking the button triggers onAction, which can inspect the event’s information and react accordingly. This pattern scales cleanly to menus, toolbars, and other components that generate action events.:contentReference[oaicite:9]{index=9}
Responding to Selection Changes
Selecting elements in a list or tree is common in desktop apps. For these components, implement SelectionChangeListener to capture user selections::contentReference[oaicite:10]{index=10}
class MyListView : public GridPanel, public SelectionChangeListener {
ListBox myList;
public:
MyListView() {
myList.addItem(L"Item 1");
myList.addItem(L"Item 2");
myList.addSelectionChangedListener(this);
}
void onSelectionChanged(const SelectionChangeEvent& ev) override {
DialogFactory::showInfo(this, ev.selectionValue, L"Selection Changed");
}
};
When a user changes the selection, onSelectionChanged receives the event, allowing your code to update the UI or perform logic.:contentReference[oaicite:11]{index=11}
Custom Event Handling with Callback Overrides
Some scenarios call for more fine‑tuned control. Components in SavvyUI provide virtual event methods for mouse, keyboard, and timer events. For example, onMousePressed, onKeyTyped, or onTimer allow you to customize behavior at a lower level.:contentReference[oaicite:12]{index=12}
For a component derived from a panel or custom control, override these virtual methods directly:
class InteractivePanel : public GridPanel {
protected:
void onMousePressed(WinHandle hWnd, int x, int y, int clickCount,
BOOL shiftPressed, BOOL ctrlPressed) override {
// Custom mouse logic here
}
};
This approach is ideal when you need granular control — for example, drawing custom elements, tracking drag gestures, or implementing multi‑click actions.:contentReference[oaicite:13]{index=13}
Best Practices for Event Handling
Here are tried and true practices to make your event handling in SavvyUI robust and maintainable:
- Keep handlers focused: Avoid large monolithic
onActionimplementations; split logic into helper functions. - Avoid tight coupling: Pass necessary state into handlers instead of tightly coupling to UI internals.
- Use listener interfaces appropriately: Only implement the listener types you need to reduce overhead.
- Unregister listeners if needed: For dynamic UI components, deregister listeners before destroying objects.
Debugging Event‑Driven Flows
Event‑driven applications can be complex to debug because event firing sequences may depend on user timings. Use logging inside your listener implementations to trace behavior and understand event flow. For example:
void MyListener::onAction(const ActionEvent &ev) {
// ev.actionName
}
This output helps you confirm that your listener is registered correctly and verify that events fire in the expected order.
Conclusion
Effective event handling is the backbone of interactive desktop applications in SavvyUI. By mastering listener interfaces like ActionListener, SelectionChangeListener, and key virtual callbacks, you can build responsive, intuitive UIs that feel native and polished. Whether you’re responding to button clicks, menu selections, list changes, or advanced mouse and keyboard actions, SavvyUI gives you the tools to structure your event logic cleanly and consistently.:contentReference[oaicite:14]{index=14}
Ready to get started? Visit the official SavvyUI home page to download the library, explore components, and dive deeper into the framework.:contentReference[oaicite:15]{index=15}