The code, at the bottom of the question, provides a solution for a fairly specific circumstance where I need to click on a JMenu
and it should act like a JButton
whilst keeping almost all of the formatting of a JMenu
. The difference in formatting between the ActionMenu
and the JMenu
should be after it is clicked, it should return to its normal state (see image).
With the current code it does do this. However; if you are to move your mouse over a different menu or if you move you mouse down/up off the menu and then hover back over it, the menu will go into its selected state (see image). This should not occur.
My question is why is this occurring after the AccessibleSelection
has been cleared and the PopupMenu
has been set to not visible?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
public class Main extends JFrame {
private static final long serialVersionUID = 3206847208968227199L;
private Main() {
setSize(600, 600);
setJMenuBar(new MenuBar());
setVisible(true);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
new Main();
}
private class MenuBar extends JMenuBar {
private static final long serialVersionUID = -2055260049565317972L;
MenuBar() {
add(new ActionMenu("Menu"));
add(new JMenu("Another Menu"));
}
}
private class ActionMenu extends JMenu {
private static final long serialVersionUID = -6885806048559452542L;
public ActionMenu(String name) {
setText(name);
menuItem();
}
JButton butInvis;
private void menuItem() {
butInvis = new JButton();
butInvis.addActionListener(new MenuActionListener());
addMouseListener(new MenuMouseListener());
}
private class MenuMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
clcikComponent(butInvis);
}
private void clcikComponent(JButton comp) {
comp.doClick();
}
}
private class MenuActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
AccessibleJMenu aJ = (AccessibleJMenu) getAccessibleContext();
aJ.clearAccessibleSelection();
getPopupMenu().setVisible(false);
}
}
}
}
Edit
I forgot to mention that orginally I was doing this with setSelected(false)
on the JMenu
(see code below); however, that causes the exact same issue when you hover over another JMenu
.
private class MenuActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
setSelected(false);
}
}
To solve this problem you need to use the AccessibleContext
of the JMenuBar
and not the JMenu
. This can be done with the line of code
getParent().getAccessibleContext().getAccessibleSelection().clearAccessibleSelection();
In this example the code would go in the MenuActionListener
and it would look like the following code.
private class MenuActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
getParent().getAccessibleContext().getAccessibleSelection().clearAccessibleSelection();
}
}
As mentioned by Andrew Thompson, this should not be done because of the Principle of Least Astonishment, unless you are going to change the formatting of the component (Action Menu
in this example) so that it does not look like another component.