Drag and Drop Operations in Swing
Each drag source (Java-based or otherwise) advertises the set of actions it supports when exporting data. Swing components advertise source actions through the getSourceActions method.
When initiating a drag operation, the user can control which source action is used for the transfer by combining keyboard modifiers with the drag gesture. This is called the user action and can be obtained via getUserDropAction.
Implementing Drop Actions
The target ultimately determines the drop action. For example, a component that only accepts copied data can encode its TransferHandler to only accept data using setDropAction.
This decision happens in the canImport method where the target's TransferHandler determines whether to accept incoming data. An implementation might look like:
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDrop()) return false;
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) return false;
boolean copySupported = (COPY & support.getSourceDropActions()) == COPY;
if (copySupported) {
support.setDropAction(COPY);
return true;
}
return false;
}
Event Handling in Swing
Action Listeners
Action listeners are the most common event handlers. They define what should happen when a user performs an action like clicking a button or pressing Enter in a text field.
To implement an action listener:
- Declare a class that implements
ActionListener - Register an instance of this class using
addActionListener - Implement the
actionPerformedmethod
Example:
button.addActionListener(e -> {
// Handle button click
});
Change Listeners
Change listeners are notified when an object changes state. They're commonly used with sliders, color choosers, and spinners.
Example:
slider.addChangeListener(e -> {
if (!slider.getValueIsAdjusting()) {
int value = slider.getValue();
// Handle value change
}
});
Component Listeners
Component listeners handle events related to component visibility, size, and position changes.
Example:
component.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// Handle resize
}
});
Common Event Handling Patterns
Using Adapter Classes
For listener interfaces with multiple methods, adapter classes provide empty implementations so you only need to override the methods you care about.
Inner Classes and Anonymous Classes
These are useful for keeping event handling code organized and maintaining access to enclosing class members.
EventHandler Utility
The EventHandler class can generate simple event handlers dynamically, though it's primarily intended for use by GUI builders.
Best Practices
- Keep event handlers fast to avoid UI freezing
- Prefer semantic events over low-level events when possible
- Use adapter classes to avoid empty method implementations
- Consider performance implications of inner classes
- For complex components, implement proper drop location rendering
Troubleshooting
- For empty table drop issues, use
setFillsViewportHeight(true) - Ensure drag gestures don't conflict with component's built-in DND support
- Remember that caret updates might not occur on the event dispatch thread