JComboBox itemStateChanged event called twice at a time - java

resultCombo = new JComboBox();
resultCombo.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent ie) {
sampleText=resultCombo.getSelectedItem().toString();
System.out.println("SampleText : "+sampleText);
}
});
output:
SampleText : selectedword
SampleText : selectedword
Why this event is called twice when selecting item in combobox.?

JComoboBox ItemListener does get called twice for a single change. Once for SELECTED event and once for DESELECTED event.
See this tutorial page on how to write an ItemListener.
Basically what you have to do is
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
//Do any operations you need to do when an item is selected.
} else if(e.getStateChange() == ItemEvent.DESELECTED){
//Do any operations you need to do when an item is de-selected.
}
}

Based on the documentation of ItemListener
Invoked when an item has been selected or deselected by the user. The
code written for this method performs the operations that need to
occur when an item is selected (or deselected).
This suggested that you will receive an event when an item is deselected or selected. Seen as a change in the selected item in the combo box requires that the currently selected item has to be deselected first, it stands to reason that you will receive a ItemEvent.DESELECTED and ItemEvent.SELECTED event

Related

Event handling in Java (JTree + JButton)

private void createEvents()
{
menuFileExit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
System.exit(0);
}
});
////// Events on tree selection
jtStoryViewer.addTreeSelectionListener(new TreeSelectionListener()
{
public void valueChanged(TreeSelectionEvent arg0)
{
DefaultMutableTreeNode selection = (DefaultMutableTreeNode) jtStoryViewer.getLastSelectedPathComponent();
Object nodeObject = selection.getUserObject();
////// Checks if selected node is a String (only story title is a string)
if(selection.getUserObject().getClass().getName() == "java.lang.String" )
{
tfTitle.setText(nodeObject.toString());
////// Action listener for Change Button
btnChange.addActionListener(new ActionListener()
{
////// Title text swap
public void actionPerformed(ActionEvent arg0)
{
selection.setUserObject(tfTitle.getText());
((DefaultTreeModel)jtStoryViewer.getModel()).nodeChanged(selection);
}
});
}
///// checks if the object is a chapter object
if(selection.getUserObject().getClass().getName() == "ISW.common.Chapter")
{
Chapter chapter = (Chapter) selection.getUserObject();
tfTitle.setText(chapter.toString());
////// Action listener for Change Button
btnChange.addActionListener(new ActionListener()
{
////// Title text swap
public void actionPerformed(ActionEvent arg0)
{
chapter.setTitle(tfTitle.getText());
((DefaultTreeModel)jtStoryViewer.getModel()).nodeChanged(selection);
}
});
}
}
});
}
I am using JTree to display and modify some objects. I added a TreeSelectionListener to get the object data on selection. For now I want to be able to change the title of an object, it works fine on first selection on the tree , I change the value in the text box and the "Change" button works just fine, but when I move on to next objects, the change button also modifies the value of all previously selected objects.
I guess it is caused due to my improper usage of the ActionListeners but I can't tell for sure and at this point I'm stuck.
Will be grateful for any hints.
Don't keep adding an ActionListener to the btnChange JButton within the TreeSelectionListener#valueChanged method.
This will cause the button to call EVERY ActionListener you have previously
Instead, give the btnChange a single ActionListener, when clicked, can act on the currently selected node (by checking the JTree it self). You could have the TreeSelectionListener#valueChanged method enable or disable the btnChange based on the validity of the selection
Also, if(selection.getUserObject().getClass().getName() == "ISW.common.Chapter") isn't how String comparison is done in Java, instead you should use something more like if("ISW.common.Chapter".equals(selection.getUserObject().getClass().getName()))

Editable JCombobox avoid multiple DocumentEvents when the selection change from the popup

I have an editable JComboBox with a single listener on it.
It is a documentListener that execute some code when the user insert or remove some text inside the combobox textfield:
((JTextComponent)combobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(..)
My problem is that when the user select an element from the popup and the content of the combobox textfield changes there are two events executed into the documentListener, one is a removeUpdate() corresponding to the deletion of the previous content and the other is a insertUpdate() corresponding to the insertion of the new value.
I want that only one execution of my code is done and not two. How can I avoid that the code is executed two times when the user select an entry from the popup?
I tried various combination of different listener but for now without result.
What I want in the end is that my code is execute only one time when:
- The user change the text into the combobox textfield.
- The user select an element from the combobox popup
Thanks in advance.
[EDIT 1]
As requested I updated adding SSCCE
myCombobox = new javax.swing.JComboBox<String>();
myCombobox.setEditable(true);
((JTextComponent)myCombobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(
new DocumentListener(){
#Override
public void insertUpdate(DocumentEvent e) {
System.out.println("insert performed");
}
#Override
public void removeUpdate(DocumentEvent e) {
System.out.println("remove performed");
}
#Override
public void changedUpdate(DocumentEvent e) {
System.out.println("change performed");
}
});
myCombobox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent event) {
if (event.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Action performed");
}
}
});
Note that in this case I have an ItemEvent instead of an ActionEvent because I'm continuing to modify my code searching for a solution in any case the behavior should not be influenced by this.
You can check ((JTextComponent)combobox.getEditor().getEditorComponent()).hasFocus() to be sure user types in the editor.

Java - JComboBox Invalidade Item Selection in ItemListener

I am trying to add a condition inside my ItemListener and only if the condition is verified the item gets selected, otherwise I dont want the user to be able to select that item.
How can I invalidade a selection on item listener? Make a new selection inside the item listener? won't that be a infinite loop? :o
Thanks alot in advance.
Here is my code:
private final class classeComboBoxItemListener implements ItemListener {
#Override
public void itemStateChanged(ItemEvent e) {
try {
if(e.getStateChange() == ItemEvent.DESELECTED)
updateLabelLugares(true, (Classe) e.getItem());
if(e.getStateChange() == ItemEvent.SELECTED)
updateLabelLugares(false, (Classe) e.getItem());
} catch (Exception e1) {
/// HERE I WANT TO INVALIDATE THE SELECTION
/// Returning to the item selected before!
}
}
}
How can I invalidade a selection on item listener? Make a new
selection inside the item listener? won't that be a infinite loop? :o
remove ItemListener from JComboBox, then call JComboBox.setSelectedIndex(-1), add ItemListener back to JComboBox (standard and good practicies)
create two void (standard and good practicies) in one add listener, in second remove listener
don't wrap if(e.getStateChange() == ItemEvent.DESELECTED) inside boolean for the reason, to block code executions untill reset status ended
use if - else for if(e.getStateChange() == ItemEvent.DESELECTED){ .... } else { ... }

Toggling JCheckBox value

im trying to toggle my jcheckbox. I have set the default to check jcb2. my jcb1 is working fine but my jcb2 can't seem to be toggled on. I added a println and found that it gets printed but my jcb2 does not get check.
class CheckBoxHandler implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
if(jcb1.isSelected())
{
jcb1.setSelected(true);
jcb2.setSelected(false);
}
if(jcb2.isSelected())
{
jcb1.setSelected(false);
jcb2.setSelected(true);
System.out.println("1");
}
}
}
If the first check-box is selected, they will both be selected the moment you select the second check-box. This means the first if-condition will be met, such that the second check-box will be deselected right away.
So instead of checking which check-boxes are selected, you should use the ItemEvent e to see which check-box you just selected.
if(e.getStateChange() == ItemEvent.SELECTED) {
if(e.getItem() == jcb1) {
jcb2.setSelected(false);
} else {
jcb1.setSelected(false);
}
}

Why is itemStateChanged on JComboBox is called twice when changed?

I'm using a JComboBox with an ItemListener on it. When the value is changed, the itemStateChanged event is called twice. The first call, the ItemEvent is showing the original item selected. On the second time, it is showing the item that has been just selected by the user. Here's some tester code:
public Tester(){
JComboBox box = new JComboBox();
box.addItem("One");
box.addItem("Two");
box.addItem("Three");
box.addItem("Four");
box.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e){
System.out.println(e.getItem());
}
});
JFrame frame = new JFrame();
frame.getContentPane().add(box);
frame.pack();
frame.setVisible(true);
}
So when I changed the Combo box once from "One" to "Three" the console shows:
One
Three
Is there a way I can tell using the ItemEvent maybe, that it's the second item (ie. the user selected item)? And if someone can explain why it gets called twice, that would be nice too!
Thanks
Have a look at this source:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Tester {
public Tester(){
JComboBox box = new JComboBox();
box.addItem("One");
box.addItem("Two");
box.addItem("Three");
box.addItem("Four");
box.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e){
System.out.println(e.getItem() + " " + e.getStateChange() );
}
});
JFrame frame = new JFrame();
frame.getContentPane().add(box);
frame.pack();
frame.setVisible(true);
}
public static void main(String [] args) {
Tester tester = new Tester();
}
}
Use the getStateChange to determine if an item is selected or deselected
According to this thread,
It gets tripped when you leave one result and then called again when set to another result
Don't listen for itemStateChanged. Use an ActionListener instead, which is good for handling events of the combo.
You need a ItemStateListener if you need to separately handle deselection / selection depending on the item involved.
Changing the state of the item within itemStateChanged causes itemStateChanged to be fired... this called "reentrance".
I wanted to get the index string after selected and set in combobox
comboBox1.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getStateChange() == ItemEvent.SELECTED) {
comboBox1ItemStateChanged();
}
}
});
Yo can do it like this:
import java.awt.event.*;
jComboBox1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Hello");
}
});
private void dropDown_nameItemStateChanged(java.awt.event.ItemEvent evt) {
if(evt.getStateChange() == ItemEvent.SELECTED)
{
String item = (String) evt.getItem();
System.out.println(item);
}
}
Good Luck!
The code is:
public class Tester {
private JComboBox box;
public Tester() {
box = new JComboBox();
box.addItem("One");
box.addItem("Two");
box.addItem("Three");
box.addItem("Four");
box.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == 1) {
JOptionPane.showMessageDialog(box, e.getItem());
System.out.println(e.getItem());
}
}
});
JFrame frame = new JFrame();
frame.getContentPane().add(box);
frame.pack();
frame.setVisible(true);
}
}
Have a look here,
box.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e){
if(e.getStateChange()== ItemEvent.SELECTED) {
//this will trigger once only when actually the state is changed
JOptionPane.showMessageDialog(null, "Changed");
}
}
});
When you select a new option, it will only once call the JOptionPane, indicating that the code there will be called once only.
Quote from Java Tutorial:
"Only one item at a time can be selected in a combo box, so when the user makes a new selection the previously selected item becomes unselected. Thus two item events are fired each time the user selects a different item from the menu. If the user chooses the same item, no item events are fired."
When the anyitem is selected from the combo box, it internally triggers selection change, i.e. it will call the function setSelectedItem.
If an explicit itemStateChanged event listener is implemented, the setSelectedItem will call itemStateChanged. So, when an item is selected it calls setSelectedItem then it calls itemStateChanged.
As the value of the combo box changes, even that too triggers itemStateChanged and hence itemStateChanged gets called.
I had written listener for item change to handle change in value of combo box when set internally from the code and that caused the function getting called twice.
Here are the 2 back traces, which gets invoked when a value is selected from combo box.
1st time on actual value change:
dataMgr.MainInterface.jComboBoxPaymentStatusValueChangeHandle(MainInterface.java:1431),
dataMgr.MainInterface.jComboBoxPaymentStatusItemStateChanged(MainInterface.java:1676),
dataMgr.MainInterface.access$600(MainInterface.java:28),
dataMgr.MainInterface$7.itemStateChanged(MainInterface.java:437),
javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223),
javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1271),
javax.swing.JComboBox.contentsChanged(JComboBox.java:1330),
javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118),
javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93),
javax.swing.JComboBox.setSelectedItem(JComboBox.java:576), javax.swing.JComboBox.setSelectedIndex(JComboBox.java:622), javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased(BasicComboPopup.java:852), java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290), java.awt.Component.processMouseEvent(Component.java:6533), javax.swing.JComponent.processMouseEvent(JComponent.java:3324), javax.swing.plaf.basic.BasicComboPopup$1.processMouseEvent(BasicComboPopup.java:501), java.awt.Component.processEvent(Component.java:6298), java.awt.Container.processEvent(Container.java:2236), java.awt.Component.dispatchEventImpl(Component.java:4889), java.awt.Container.dispatchEventImpl(Container.java:2294), java.awt.Component.dispatchEvent(Component.java:4711), java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888), java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525), java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466), java.awt.Container.dispatchEventImpl(Container.java:2280), java.awt.Window.dispatchEventImpl(Window.java:2746), java.awt.Component.dispatchEvent(Component.java:4711), java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758), java.awt.EventQueue.access$500(EventQueue.java:97), java.awt.EventQueue$3.run(EventQueue.java:709), java.awt.EventQueue$3.run(EventQueue.java:703), java.security.AccessController.doPrivileged(Native Method), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86), java.awt.EventQueue$4.run(EventQueue.java:731), java.awt.EventQueue$4.run(EventQueue.java:729), java.security.AccessController.doPrivileged(Native Method), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), java.awt.EventQueue.dispatchEvent(EventQueue.java:728), java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201), java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116), java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93), java.awt.EventDispatchThread.run(EventDispatchThread.java:82)]
2nd time from the due to operation on combobox
dataMgr.MainInterface.jComboBoxPaymentStatusValueChangeHandle(MainInterface.java:1431),
dataMgr.MainInterface.jComboBoxPaymentStatusItemStateChanged(MainInterface.java:1676),
dataMgr.MainInterface.access$600(MainInterface.java:28),
dataMgr.MainInterface$7.itemStateChanged(MainInterface.java:437),
javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223),
javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1280),
javax.swing.JComboBox.contentsChanged(JComboBox.java:1330),
javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118),
javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93),
javax.swing.JComboBox.setSelectedItem(JComboBox.java:576),
javax.swing.JComboBox.setSelectedIndex(JComboBox.java:622),
javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased(BasicComboPopup.java:852),
java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290),
java.awt.Component.processMouseEvent(Component.java:6533),
javax.swing.JComponent.processMouseEvent(JComponent.java:3324),
javax.swing.plaf.basic.BasicComboPopup$1.processMouseEvent(BasicComboPopup.java:501),
java.awt.Component.processEvent(Component.java:6298), java.awt.Container.processEvent(Container.java:2236),
java.awt.Component.dispatchEventImpl(Component.java:4889), java.awt.Container.dispatchEventImpl(Container.java:2294),
java.awt.Component.dispatchEvent(Component.java:4711), java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888),
java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525), java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466),
java.awt.Container.dispatchEventImpl(Container.java:2280), java.awt.Window.dispatchEventImpl(Window.java:2746),
java.awt.Component.dispatchEvent(Component.java:4711), java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758),
java.awt.EventQueue.access$500(EventQueue.java:97), java.awt.EventQueue$3.run(EventQueue.java:709),
java.awt.EventQueue$3.run(EventQueue.java:703), java.security.AccessController.doPrivileged(Native Method),
java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76),
java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86),
java.awt.EventQueue$4.run(EventQueue.java:731), java.awt.EventQueue$4.run(EventQueue.java:729),
java.security.AccessController.doPrivileged(Native Method), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), java.awt.EventQueue.dispatchEvent(EventQueue.java:728), java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201), java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116), java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93), java.awt.EventDispatchThread.run(EventDispatchThread.java:82)]
JComboBox.setFocusable(false) will do the trick.

Categories