Java swing drop down selection listener - java

I have a JCombobox with the large list of items. Upon selecting an Item, I need something done.
I tried with actionListener and with itemListner
myComboBox.addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
String selection = (String)myComboBox.getSelectedItem();
System.out.println("Selected: "+selection ) ;
}
}
});
With Action listener, I tried the same thing
The problem, I am facing is this
When user rolls through the open drop down he inadvertently keep selecting each item he does not need. (or if uses the mouse wheel, etc...).
So, I want to be able to catch ONLY that selection that user makes.
How can it be done ?

The problem, I am facing is this When user rolls through the open drop down he inadvertently keep selecting each item he does not need.
You can prevent the listener from firing by using:
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
For example:
/*
This works on non editable combo boxes
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
import javax.swing.text.*;
public class ComboBoxAction extends JFrame implements ActionListener
{
public ComboBoxAction()
{
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.addActionListener( this );
comboBox.addItem( "Item 1" );
comboBox.addItem( "Item 2" );
comboBox.addItem( "Item 3" );
comboBox.addItem( "Item 4" );
// This prevents action events from being fired when the
// up/down arrow keys are used on the dropdown menu
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
getContentPane().add( comboBox );
getContentPane().add( new JTextField(), BorderLayout.SOUTH );
}
public void actionPerformed(ActionEvent e)
{
System.out.println( e.getModifiers() );
JComboBox comboBox = (JComboBox)e.getSource();
System.out.println( comboBox.getSelectedItem() );
// make sure popup is closed when 'isTableCellEditor' is used
// comboBox.hidePopup();
}
public static void main(String[] args)
{
ComboBoxAction frame = new ComboBoxAction();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
}

The problem, I am facing is this When user rolls through the open drop
down he inadvertently keep selecting each item he does not need.
Reason for that is, when press arraw up and down it is also state change. So my solution is you can add keyTyped actionListener. Then you can get the code for arrow key and check for arraw press. Like below:
myComboBox.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
String x = String.valueOf(myComboBox.getSelectedItem());
if(evt.getKeyCode() == 40) {
System.out.println(x);
//System.out.println(evt.getKeyCode());
}
}
});

Please use ActionListeners, like this:
combo.addActionListener (new ActionListener () {
public void actionPerformed(ActionEvent e) {
// doSomething();
}
});

Related

Java ComboBox how to populate on click add item not working

it's really simple. I want to populate a jcomboBox but only after the user press the arrow on the combobox.
I think the code is right cause i test it in a separate button and it populate the Combobox but when i create an action listener for the combobox itself it doesn't populate, Here are the code.
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
comboBox.addItem("Item");
comboBox.addItem("Second Item");
}
It's a country city neighborhood situation . What i want is the second to be populated when the first is selected .
The first box is easy to populate (The country box) But the second box (City) I added a switch for it but it just won't populate , What i want to know is there an action i should put my code into for it to populate ?
I want to populate a jcomboBox but only after the user press the arrow on the combobox.
Why would the user look at an empty combo box and then click on the arrow? If the contents of the combo box are based on some other user Action, then that Action should cause the combo box to be populated.
Anyway, maybe you are trying to popuplate the combo box when the dropdown is displayed?
That is the user could click anywhere on the combo box, not just the down arrow.
In this case you can use a PopupMenuListener
comboBox.addPopupMenuListener(new PopupMenuListener()
{
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
JComboBox comboBox = (JComboBox)e.getSource();
comboBox.addItem("Item1");
comboBox.addItem("Item2");
comboBox.addItem("Item3");
comboBox.addItem("Item4");
}
public void popupMenuCanceled(PopupMenuEvent e) {}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
});
Edit:
It's a country city neighborhood situation .
Which is a requirement that should have been included with your original question. As people has suggested your approach is wrong. The child combo boxes should be updated when the parent is changed, not when you click the child.
See How to Update Multiple Combo Boxes for a better solution. The example there only shows 2 combo boxes, but the concept is the same for the second and third.
Pressing a JComboBox arrow doesn't trigger the ActionListener. Only making a selection does, and so your combo box will need to be populated before the arrow has been pressed. You'll have to re-think your design such as populating the combo box before the user interacts with it.
If you absolutely needed to add an action listener to the arrow button, it can be done, such as via a recursive method:
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class Foo extends JPanel {
private JComboBox<String> combo = new JComboBox<>();
public Foo() {
add(combo);
combo.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
// this doesn't work!!!
System.out.println("mouse pressed");
super.mousePressed(e);
}
});
recursiveAddAxnListener(combo);
}
private void recursiveAddAxnListener(Component comp) {
if (comp instanceof AbstractButton) {
((AbstractButton) comp).addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("added to combo's button");
}
});
} else if (comp instanceof Container) {
Component[] comps = ((Container) comp).getComponents();
for (Component component : comps) {
recursiveAddAxnListener(component);
}
}
}
private static void createAndShowGUI() {
Foo paintEg = new Foo();
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
But do I recommend it? No, not at all.
Edit
You have edited your question and have added:
It's a country city neighborhood situation . What i want is the second to be populated when the first is selected .
The first box is easy to populate (The country box) But the second box (City) I added a switch for it but it just won't populate , What i want to know is there an action i should put my code into for it to populate ?
You may be asking an XY-Problem type question where you ask how do I solve X code problem when the best solution is to use an entirely different approach. In this situation I strongly recommend that you not populate the second combobox on mouse press, but rather populate it only once and do it when the first combobox selection has been made. In other words, populate the 2nd combo box in the first combo box's ActionListener. This will simplify things greatly and prevent re-population of the 2nd combobox unnecessarily.
Thank you all for your help , you have been just awesome.
I found the problem I had to have the combobox.removeallItems(); before the switch not in the switch.
This is the testing version of it.and it worked.
JComboBox comboBox = new JComboBox();
comboBox.addItem("");
comboBox.addItem("first");
comboBox.addItem("second");
comboBox.addItem("third");
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
comboBox_1.removeAllItems();
String test = comboBox.getSelectedItem().toString();
switch (test) {
case "first":
comboBox_1.addItem("Tesing");
break;
case "second":
comboBox_1.addItem("Tesing2");
break;
case "third":
comboBox_1.addItem("Tesing three");
break;
default:
break;
}
}
});
Again , i appreciate all the help , Thank you so much.

Java Popup Button

Note: You may have to compile and run my example to fully understand my question. If this is not kosher, I apologize in advance.
I am trying to create a Swing control that is based on a JToggleButton and a JPopupMenu.
The toggle button is selected iff the popup menu is visible, and the toggle button is deselected iff the popup menu is not visible. Thus, the behavior is similar to a JComboBox, except that the popup can contain arbitrary components.
The code that follows is an example of how I would create the control (except that it would be in its own class... something like a JPopupToggleButton). Unfortunately, it exhibits different behavior under different look and feels (I have tested it with Metal and Nimbus).
The code as posted here behaves as expected in Metal, but not in Nimbus. When using Nimbus, just show and hide the popup by repeatedly clicking the toggle button and you will see what I mean.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
public class PopupButtonExample extends JFrame
{
public static void main( String[] args )
{
java.awt.EventQueue.invokeLater( new Runnable()
{
#Override
public void run()
{
PopupButtonExample example = new PopupButtonExample();
example.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
example.setVisible( true );
}
});
}
public PopupButtonExample()
{
super( "Components in Popup" );
JPanel popupPanel = new JPanel();
popupPanel.setLayout( new BorderLayout() );
popupPanel.add( new JLabel( "This popup has components" ),
BorderLayout.NORTH );
popupPanel.add( new JTextArea( "Some text", 15, 20 ),
BorderLayout.CENTER );
popupPanel.add( new JSlider(), BorderLayout.SOUTH );
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add( popupPanel );
final JToggleButton popupButton = new JToggleButton( "Show Popup" );
popupButton.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if( popupButton.isSelected() )
popupMenu.show( popupButton, 0, popupButton.getHeight() );
}
});
popupMenu.addPopupMenuListener( new PopupMenuListener()
{
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {}
#Override
public void popupMenuCanceled(PopupMenuEvent pme) {}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
Point componentLoc = popupButton.getLocationOnScreen();
mouseLoc.x -= componentLoc.x;
mouseLoc.y -= componentLoc.y;
if( !popupButton.contains( mouseLoc ) )
popupButton.setSelected( false );
}
});
JPanel toolBarPanel = new JPanel();
toolBarPanel.add( popupButton );
JToolBar toolBar = new JToolBar();
toolBar.add( toolBarPanel );
setLayout( new BorderLayout() );
add( toolBar, BorderLayout.PAGE_START );
setPreferredSize( new Dimension( 640, 480 ) );
pack();
}
}
Commeting out the following lines makes the code behave as expected in Nimbus, but not in Metal. Again, just keep clicking the toggle button to see what I mean.
// Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
// Point componentLoc = popupButton.getLocationOnScreen();
// mouseLoc.x -= componentLoc.x;
// mouseLoc.y -= componentLoc.y;
// if( !popupButton.contains( mouseLoc ) )
So here are my two questions:
(1) In Nimbus, why does the click that hides the popup panel not get passed to the toggle button, as it does with Metal?
(2) How can I solve this problem so that it works with all look and feels?
Nimbus is too buggy (and development ended somewhere in the middle) I see that you need three mouse click to the JToggleButton in compare with Metal
every standard L&F have got own specific issues, especially SystemLookAndFeel
use JWindow rather that JPopup, because with JPopup there are another Bugs too e.g. JPopup with JCombobox
After some investigation, I found the cause for the difference between Nimbus and Metal. The following flag is used (at least by BasicPopupMenuUI) to control the consumption of events when a popup is closed:
UIManager.getBoolean( "PopupMenu.consumeEventOnClose" );
When using Nimbus, this returns true. When using Metal, this returns false. Thus, the method popupMenuWillBecomeInvisible should be defined as follows:
if( UIManager.getBoolean( "PopupMenu.consumeEventOnClose" ) )
{
popupButton.setSelected( false );
}
else
{
Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
Point componentLoc = popupButton.getLocationOnScreen();
mouseLoc.x -= componentLoc.x;
mouseLoc.y -= componentLoc.y;
if( !popupButton.contains( mouseLoc ) )
{
popupButton.setSelected( false );
}
}

How to show a tooltip on a mouse click

I have a JTreeTable and have successfully implemented a MouseMotionListener to show a tooltip whenever the mouse is over one of the cells. However when clicking on the cell the tooltip does not show up. I've tried several things like setting the text on the mouseClicked and mouseReleased events but that doesn't work. I found this code -
Action toolTipAction = treeTable.getActionMap().get("postTip");
if(toolTipAction != null){
ActionEvent postTip = new ActionEvent(treeTable,ActionEvent.ACTION_PERFORMED, "");
toolTipAction.actionPerformed(postTip);
}
to use in the mouseReleased method, which does make the tooltip popup, but it's then in the wrong position. So next i tried overriding the getTooltipLocation method on the JTreeTable, and this works fine for mouseMoved events but doesn't get called with the above method. Can anyone shed some light on how to do this?
Thanks
Andy
You can use the following approach to show the tooltip (there will be a slight delay). Then you can override the getToolTipLocation() method since a MouseEvent will now be generated:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToolTipOnRelease extends JPanel
{
public ToolTipOnRelease()
{
JLabel label = new JLabel( "First Name:" );
add( label );
JTextField textField = new JTextField(15);
add( textField );
MouseListener ml = new MouseAdapter()
{
public void mouseReleased(MouseEvent e)
{
JComponent component = (JComponent)e.getSource();
component.setToolTipText("Mouse released on: " + component.getClass().toString());
MouseEvent phantom = new MouseEvent(
component,
MouseEvent.MOUSE_MOVED,
System.currentTimeMillis(),
0,
0,
0,
0,
false);
ToolTipManager.sharedInstance().mouseMoved(phantom);
}
};
label.addMouseListener( ml );
textField.addMouseListener( ml );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("ToolTipOnRelease");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new ToolTipOnRelease() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
org.apache.jorphan.gui.JTreeTable extends javax.swing.JComponent
javax.swing.JComponent#setToopTipText() doesn't work?
I do realize that you want to use Action but for tooltips? I would use Action when multiple UI actions would need to share it.

java swing, highligth item in jcombobox popup

i want to highlight an item inside popup list.
I say "highlight" becouse i don't want to select it (for example by calling setSelectedItem) but only make it selected inside the jcombobox popup.
How can i do?
The following sort of works in that an item other than the first is selected. However, if you use the keyboard to change selection, it always starts from the first because that is the one that is selected.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.*;
public class ComboBoxSelect extends JFrame
{
public ComboBoxSelect()
{
String[] items = { "Item1", "Item2", "Item3", "Item4", "Item5" };
JComboBox comboBox = new JComboBox( items );
add( comboBox );
comboBox.addPopupMenuListener(new PopupMenuListener()
{
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
JComboBox comboBox = (JComboBox)e.getSource();
BasicComboPopup popup = (BasicComboPopup)comboBox.getAccessibleContext().getAccessibleChild(0);
JList list = popup.getList();
list.setSelectedIndex(2);
}
public void popupMenuCanceled(PopupMenuEvent e) {}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
});
}
public static void main(String[] args)
{
ComboBoxSelect frame = new ComboBoxSelect();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}
This write-up provides guidance on how you could modify JComboBox:
http://www.orbital-computer.de/JComboBox/
Although it's written for auto-complete functionality, a custom mechanism to highlight without selecting would be very similar (and probably easier).

How to enable ESC-Close for an JPopupMenu, if the underlying window closes on ESC?

Imagine two common situations combined: A JDialog(or JFrame) which closes on VK_ESCAPE (set as key binding on the root pane) and an inner JPopupMenu which is supposed to close on ESC as well. The problem is: pressing escape always closes the dialog - event if the popup is visible. Apparently the popup doesn't even receive the key event so it can't be consumed by the popup. Is there any way to get this working correctly, so that on the first ESC-event the popup is closed and on the second the dialog closes?
By the way: It does work with a JComboBox, which by default closes when escape is pressed.
Finding a generic solution was a bit of a challenge. We need to consider when:
a light weight popup is used
a heavy weight popup is used
I determined that in both cases the root pane actually has focus when the escape key is pressed.
In the first case I just search the root pane to see if a JPopupMenu has been added to the GUI. If so, then we can just close the popup.
In the second case a Window is created to contain the JPopupMenu so I do a search to see if a visible custom popup Window is displayed. If so, then I dispose of the window.
If neither of the above two cases is true then you can just close the dialog.
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
public class DialogEscape extends JDialog
{
private JPopupMenu popup;
public DialogEscape()
{
popup = new JPopupMenu();
popup.add( new JMenuItem("SubMenuA") );
popup.add( new JMenuItem("SubMenuB") );
popup.add( new JMenuItem("SubMenuC") );
popup.add( new JMenuItem("SubMenuD") );
String[] items = { "Select Item", "Color", "Shape", "Fruit" };
JComboBox comboBox = new JComboBox( items );
add(comboBox, BorderLayout.NORTH);
JTextField textField = new JTextField("Right Click For Popup");
textField.setComponentPopupMenu(popup);
add(textField);
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action escapeAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
boolean openPopup = false;
Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
// Check if light weight popup is being used
List<JPopupMenu> popups = SwingUtils.getDescendantsOfType(JPopupMenu.class, (Container)c, true);
for (JPopupMenu p: popups)
{
p.setVisible( false );
openPopup = true;
}
// Check if a heavy weight popup is being used
Window window = SwingUtilities.windowForComponent(c);
Window[] windows = window.getOwnedWindows();
for (Window w: windows)
{
if (w.isVisible()
&& w.getClass().getName().endsWith("HeavyWeightWindow"))
{
openPopup = true;
w.dispose();
}
}
// No popups so close the Window
if (! openPopup)
// SwingUtilities.windowForComponent(c).setVisible(false);
SwingUtilities.windowForComponent(c).dispose();
}
};
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
getRootPane().getActionMap().put("ESCAPE", escapeAction);
}
public static void main(String[] args)
{
String laf = null;
laf = "javax.swing.plaf.metal.MetalLookAndFeel";
// laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
// laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
try { UIManager.setLookAndFeel(laf); }
catch (Exception e2) { System.out.println(e2); }
JDialog dialog = new DialogEscape();
dialog.setDefaultCloseOperation( HIDE_ON_CLOSE );
dialog.setSize(200, 200);
dialog.setLocationRelativeTo(null);
dialog.setVisible( true );
}
}
You will also need to download the Swing Utils class.
I encountered the problem as well. The solution provided by #camickr didn't seem very nice to me. So I checked out what's going on under the hood. When opening a popup, the component that is the invoker of the popup loses focus. The focus goes over to the JRootPane of the JDialog which then delegates to the popup. So instead of registering the "ESC" shortcut on the JRootPane, i simply put it on the ContentPane. This way, the dialog only closes on ESC when anything other than the JRootPane is focused.
final JComponent contentPane = (JComponent) dialog.getContentPane();
contentPane.getInputMap( JComponent.WHEN_IN_FOCUSED_WINDOW ).put( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), "EXIT" );
contentPane.getActionMap().put( "EXIT", new AbstractAction()
{
#Override
public void actionPerformed( final ActionEvent e )
{
dialog.dispatchEvent( new WindowEvent( dialog, WindowEvent.WINDOW_CLOSING ) );
}
} );

Categories

Resources