I have menu in my application, and I want to set menu item normal state icon, and pressed state icon. Normal state icon is added, but when I press menu item, normal state icon is not changed by pressed state icon. What is problem here:
JMenu m=new JMenu(text);
m.setBackground(getTheme().colors.menuColor());
m.setOpaque(false);
m.setIcon(core.getIcon(text, "normal"));
m.setPressedIcon(core.getIcon("webmaps", "pressed"));
This issue has been seen before. The inherited setPressedIcon does not change the background Icon on the the JMenu (or indeed JMenuItem). You could use a MenuListener on the component as a workaround:
m.addMenuListener(new MenuListener() {
#Override
public void menuSelected(MenuEvent e) {
JMenu menu = (JMenu) e.getSource();
menu.setIcon(core.getIcon("webmaps", "pressed"));
}
#Override
public void menuDeselected(MenuEvent e) {
JMenu menu = (JMenu) e.getSource();
menu.setIcon(core.getIcon(text, "normal"));
}
#Override
public void menuCanceled(MenuEvent e) {
JMenu menu = (JMenu) e.getSource();
menu.setIcon(core.getIcon(text, "normal"));
}
});
Related
I'm adding a PopUp menu to one of my widgets, a Table. It is not working! I only achieved to make work accelerator shortcuts if they are on top menu bar items, and not in popup context menu items. Why?
This is my code, but the table is inside a Composite which is inside another composite:
membersTable.setMenu(createMembersPopUpMenu(this));
private Menu createMembersPopUpMenu(Composite parent) {
Menu popUpMenu = new Menu(parent);
//Copy
copyMemberItem = new MenuItem(popUpMenu, SWT.PUSH);
copyMemberItem.setText("Copiar Miembro");
copyMemberItem.setAccelerator(SWT.MOD1 + 'C');
copyMemberItem.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
copyMember();
}
});
//Paste
pasteMemberItem = new MenuItem(popUpMenu, SWT.PUSH);
pasteMemberItem.setText("Pegar Miembro");
pasteMemberItem.setAccelerator(SWT.MOD1 + 'V');
pasteMemberItem.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
pasteMember();
}
});
return popUpMenu;
}
I am developing a Java Swing application that will have several panels in it, one of which is NASA's WorldWind. In this WorldWind panel I need to have a right click menu for various actions. I was successful in adding the right click menu and all is good, until the user resizes the window.
I am not sure what about that action would be causing the right click menu to stop working. The mouse listener is working fine still, but the menu no longer shows up. None of the objects get garbage collected, nothing seems to change.
Here is a quick sample of how my code is set up:
class ClickListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e) == true) {
showRightClickMenu(e);
} else {
addPoint(e);
}
}
}
void showRightClickMenu(MouseEvent e) {
System.out.println("In Right Click");
if (menu == null) {
setupRightClickMenu();
}
menu.show(e.getComponent(), e.getX(), e.getY());
}
void setupRightClickMenu() {
menu = new JPopupMenu("RightClick");
JMenuItem button1 = new JMenuItem("Show Waypoint Table");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// ptTable.showTable();
}
});
menu.add(button1);
JMenuItem button2 = new JMenuItem("Clear Waypoints");
button2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
ptLayer.removeAllRenderables();
}
});
menu.add(button2);
}
I can set the size to whatever I want at application launch and the right click works, but once I resize, it fails. Any ideas?
UPDATE
Actually after playing with it a bit more and talking with someone else I am working with, it looks like it may be drawing the menu behind the WorldWind canvas. I am not sure why this is, but I need to make sure it shows in front of it.
I tried changing the JPopupMenu property talked about here, but that does not seem to help.
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.
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());
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.
I have a JPopupMenu which contains an inner JMenu and a separator with addSeparator(). Due to some odd handling, I've added a MouseListener to the JPopupMenu which makes it invisible on a mouseExited event. This works fine, except that when the mouse tries to cross over the separator, it's triggering the event (even though the JPopupMenu is the super component).
If I remove the addSeparator() line, it works as expected.
Is there any way to work around this? Or have I not set up the listener properly?
The code is like the following:
JPopupMenu popupMenu = new JPopupMenu();
JMenu innerMenu = new JMenu("Inner");
// ... add JMenuItems
popupMenu.add(innerMenu);
popupMenu.addSeparator();
popupMenu.add(new JMenuItem("Exit"));
popupMenu.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
popupMenu.setVisible(false);
}
});
Full Compilable Example
Simply comment and uncomment the popupMenu.addSeparator() line to notice the different behaviors
public class Test {
public static void main(String[] args) throws Exception {
if(!SystemTray.isSupported()) {
throw new UnsupportedOperationException("SystemTray is not supported.");
}
final TrayIcon trayIcon = new TrayIcon(ImageIO.read(new File("resources/icon.gif")));
final JPopupMenu popupMenu = new JPopupMenu();
JMenu intervalMenu = new JMenu("Interval");
ButtonGroup itemGroup = new ButtonGroup();
JRadioButtonMenuItem oneSecondMenuItem = new JRadioButtonMenuItem("1 sec");
itemGroup.add(oneSecondMenuItem);
JRadioButtonMenuItem twoSecondMenuItem = new JRadioButtonMenuItem("2 sec");
itemGroup.add(twoSecondMenuItem);
intervalMenu.add(oneSecondMenuItem);
intervalMenu.add(twoSecondMenuItem);
popupMenu.add(intervalMenu);
popupMenu.addSeparator();
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
SystemTray.getSystemTray().remove(trayIcon);
System.exit(0);
}
});
popupMenu.add(exitMenuItem);
//Thanks to Artem Ananiev for this implementation idea
//https://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html
trayIcon.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON3) {
popupMenu.setLocation(e.getX() - 40, e.getY() - 40);
popupMenu.setInvoker(popupMenu);
popupMenu.setVisible(true);
}
}
});
popupMenu.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
popupMenu.setVisible(false);
}
});
SystemTray.getSystemTray().add(trayIcon);
}
}
Wow, you are using a sytem tray icon. That information might have been important to know. That is why a SSCCE should be posted with EVERY question.
Anyway the following seems to work:
if (! popupMenu.contains( e.getPoint() ) )
popupMenu.setVisible(false);
Edit:
It looks like the problem is that the JSeparator does not listen for MouseEvents by default so all the mouse events are passed to its parent. So when you leave a JMenuItem, the mouseEntered() event is generated for the popup menu and then when you re-enter another JMenuItem the mouseExited() event is generated.
If you enable MouseEvents for the JSeparator then it look like the JPopupMenu doesn't get the event
//popupMenu.addSeparator();
popupMenu.add( new MySeparator() );
...
static class MySeparator extends JSeparator
{
public MySeparator( )
{
super( JSeparator.HORIZONTAL );
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* Returns the name of the L&F class that renders this component.
*
* #return the string "PopupMenuSeparatorUI"
* #see JComponent#getUIClassID
* #see UIDefaults#getUI
*/
public String getUIClassID()
{
return "PopupMenuSeparatorUI";
}
}
I'm trying to create system tray icon with two popup menus, one should be called with left mouse button and another with right. AWT offers simple way to create PopupMenu but it's not posible to call menu with left mouse button without making invisible JFrame or something. So, I find out that swing JPopupMenu can be called by any of mouse buttons. But JPopupMenu have bug (I don't know if this is really a bug or I'm not so good in Java) that it's not hiding when I press mouse outside JPopupMenu. I've tried to use mouse listener's function mouseExited, but it works only on JPopupMenu border. If mouse leaves JPopupMenu border it hides and I can't press any of JPopupMenu buttons. Maybe, anyone had the same problem and could help me find out how to make it work right.
public static JPopupMenu jpm;
public static TrayIcon ti;
public static void main(String args[]) throws IOException, AWTException,
ClassNotFoundException, InstantiationException,
IllegalAccessException, UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SystemTray st = SystemTray.getSystemTray();
Image icon = ImageIO.read(SipLogin.class
.getResource("/resources/phone-yellow-small.png"));
ti = new TrayIcon(icon, "Sip login", null);
jpm = new JPopupMenu();
JMenuItem jmi1 = new JMenuItem("JMenuItem1");
JMenuItem jmi2 = new JMenuItem("JMenuItem2");
JMenuItem jmi3 = new JMenuItem("JMenuItem3");
JMenuItem jmi4 = new JMenuItem("JMenuItem4");
ti.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
jpm.setLocation(e.getX(), e.getY());
jpm.setInvoker(jpm);
jpm.setVisible(true);
}
}
});
jpm.add(jmi1);
jpm.add(jmi2);
jpm.add(jmi3);
jpm.add(jmi4);
jpm.addMouseListener(new MouseAdapter() {
public void mouseExited(MouseEvent e) {
jpm.setVisible(false);
}
});
st.add(ti);
}
Take that one mouse listener and separate the left and right click:
Change from
ti.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
jpm.setLocation(e.getX(), e.getY());
jpm.setInvoker(jpm);
jpm.setVisible(true);
}
}
});
to
ti.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if(e.getclickCount < 2){
if(e.getButton().equals(MouseEvent.Button1){
showPopup1();
}
if(e.getButton().equals(MouseEvent.Button3){
showPopup2();
}
}
}
});
thanks for very useful conversation, but I need to add some words:
Sometimes when you add menuItems the JPopupMenu behaves in unpredictable manner (it is not closed, when you mouseover your mouse from it).
In this case you need to delete the mouse motion listeners from your menu items
JMenuItem jmi1 = new JMenuItem("JMenuItem1");
jmi1.removeMouseMotionListener(jmi1.getMouseMotionListeners()[0]);
jmi1.removeMouseListener(jmi1.getMouseListeners()[0]);