Reputation: 1024
I have a Java Swing interface with multiple JTextArea
's and I am implementing an "Edit" menu with various different functions like "Find", "Copy", "Paste", etc. When I click on the JMenuItem
I need to know which JTextArea
had the focus which is achievable through a TextAction
(I haven't gone down the route of a FocusListener
and keeping track of what last had the focus):
JMenuItem miFind = new JMenuItem(new EditHandler("Find"));
class EditHandler extends TextAction {
private String s = null;
public EditHandler(String vs) {
super(vs);
s = vs;
}
@Override
public void actionPerformed(ActionEvent e) {
JTextComponent c = getFocusedComponent();
if (s.equals("Find")) {
showFindDialog(c);
}
}
}
This works well and good but I want to be able to disable the "Find" JMenuItem
under certain contexts (i.e. if the specific JTextArea
is disabled or is empty. I can implement an ActionListener
on a JMenu
but I can't use getFocusedComponent()
to identify what JTextArea
has the focus.
According to the Java docs the JMenu
constructor takes an Action
(like a JMenuItem
) and I have tried the following:
mEdit = new JMenu(new EditHandler("Edit"));
However, although the constructor fires, the actionPerformed()
event isn't firing within my EditHandler
for the JMenu
. If I can get it to fire then I was planning to either enable or disable my "Find" JMenuItem
.
Upvotes: 1
Views: 129
Reputation: 1024
Thanks to @sergiy-medvynskyy I have implemented a Global Focus Listener to keep track of the last JTextArea
to be focused:
KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent e) {
if (e.getNewValue() instanceof JTextArea) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
tFocused = (JTextArea)e.getNewValue();
}
});
}
}
});
I then check the tFocused
object using a MenuListener
on my JMenu
to verify what JTextArea
currently has the focus. I can then call setEnabled()
on my respective JMenuItem
's depending on the context.
Upvotes: 1
Reputation: 11327
The best way for you is using of actions map of the text component to place the corresponding action. In this case you can disable it for some text components.
@Override
public void actionPerformed(ActionEvent e) {
JTextComponent c = getFocusedComponent();
if (s.equals("Find")) {
Action a = c.getActionMap().get("Find");
if (a.isEnabled()) {
// generate new event to modify the source (menu item -> text component)
ActionEvent ae = new ActionEvent(c, e.getID(), e.getCommand());
a.actionPerformed(ae);
}
}
}
For each your text component you must provide an action and register it using the action map of the component.
public class UniversalFindAction extends AbstractAction {
public void actionPerformed(ActionEvent ae) {
JTextComponent c = (JTextComponent) ae.getSource();
showFindDialog(c);
}
}
// registering of action
JTextComponent comp = new JTextArea();
comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK), "Find");
comp.getActionMap().put("Find", new UniversalFindAction());
Upvotes: 1