ActionPerformed being called when JComboBox is clicked in Jtable cell - java

I am using JComboBox in Jtable cell. When I click on the JComboBox and select a value from it, it calls the ActionPerformed fuction. Till here it is working fine but as soon as I click on the JComboBox again, it calls the ActionPerformed function, which it should not. What I want is, to call the ActionPerformed function when the item is selected in the JComboBox. In other words it should work as it worked for the first time when the item was selected from the JComboBox and then the ActionPerformed function was called. I cannot figure out why this problem is occurring. Here are the links that I have looked into and I did some other searches also but still could not find any relative answer to the above mentioned problem.
Adding JComboBox to a JTable cell
How to use ActionListener on a ComboBox to give a variable a value
https://coderanch.com/t/339842/java/ComboBox-ItemListener-calling
Here is the code, you can copy paste it and check it.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class TableExample implements ActionListener{
JFrame frame;
JComboBox skuNameComboBoxTable;
TableExample() {
frame = new JFrame();
String data[][] = {{"101", "Amit", "Choose"},
{"102", "Jai", "Choose"},
{"101", "Sachin", "Choose"}};
String column[] = {"ID", "Name", "Degree"};
JTable table = new JTable(data, column);
table.setBounds(30, 40, 200, 300);
JScrollPane scrollPane = new JScrollPane(table);
frame.add(scrollPane);
frame.setSize(300, 400);
frame.setVisible(true);
String[] array = {"BS(SE)", "BS(CS)", "BS(IT)"};
skuNameComboBoxTable = new JComboBox(array);
skuNameComboBoxTable.addActionListener(this);
TableColumn col = table.getColumnModel().getColumn(2);
col.setCellEditor(new DefaultCellEditor(skuNameComboBoxTable));
}
public static void main(String[] args) {
new TableExample();
}
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "actionPerformed called");
}
}
Kindly tell me why this problem is occurring and how should I solve it.

Unfortunately, you can't do much when using the DefaultCellEditor - that is how it behaves. Within your code you can add a check to ensure that a change in value occured before handling the event. Something like below:
public void actionPerformed(ActionEvent e) {
if (skuNameSelected == null || skuNameComboBoxTable.getSelectedItem() != skuNameSelected)
JOptionPane.showMessageDialog(null, "actionPerformed called: ");
skuNameSelected = (String) skuNameComboBoxTable.getSelectedItem();
}

You can try using ItemListener and filter your action according to the ItemEvent.
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class JComboBoxTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String[] items = {"One", "Two", "Three"};
JComboBox cb = new JComboBox(items);
cb.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Selected " + e.getItem());
} else {
System.out.println("Deselected " + e.getItem());
}
}
});
frame.add(cb);
frame.pack();
frame.setVisible(true);
}
}

This is happening because you are using the same JComboBox as the DefaultCellEditor for column 2.
Whenever you click a cell from column 2 the ComboBox will change to the value that is on the cell at the moment and that triggers the DESELECT (from the old value) and the SELECT (for the new value). This will only happen if the old value and the new value are not the same.
One way to avoid this is to add a CellEditorListener on the DefaultCellEditor that you are using, like below:
TableColumn col = table.getColumnModel().getColumn(2);
DefaultCellEditor cellEditor = new DefaultCellEditor(skuNameComboBoxTable);
col.setCellEditor(cellEditor);
cellEditor.addCellEditorListener(new CellEditorListener() {
#Override
public void editingStopped(ChangeEvent e) {
System.out.println("Value of combo box defined!");
}
#Override
public void editingCanceled(ChangeEvent e) {
System.out.println("Edition canceled, set the old value");
}
});
This way you will be able to only act when the value has been defined by the ComboBox.
I hope this helps.

You should not be using an ActionListener for this. The combo box uses its own ActionListener to update the TableModel when an item is selected.
So instead you should be listening for changes in the TableModel in order to do your custom code. So you should be using a TableModelListener to listen for changes in the data. However, a TableModelListener can fire an event even if just start and stop editing of the cell which might be a problem for you.
In this case you can use the Table Cell Listener. It will only generate an event when the value in the TableModel has changed.

Related

ComboBox not listening to events

This application shows a frame that contains different JComboBoxes and a JLabel.
An event should be generated when the user clicks the last one(style combobox) and the text in the JLabel should be formatted according to the selected choices in each combobox.
When I click on the Style combobox nothing happens.
There's also another error that I couldn't figure out:(
OUTPUT
package labtasksix;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MyFrame extends JFrame {
String NameO []= {"Select name:","TimesRoman","Serif","SansSerif","Monospaced"};
String ColorO[]={"Select color:","RED","BLUE","GREEN"};
String SizeO []={"Select size:","8","12","16","20"};
String StyleO[]={"Select style:","BOLD","ITALIC","PLAIN"};
JLabel lbl= new JLabel("Text Formatted");
JComboBox Name= new JComboBox(NameO);
JComboBox Colour= new JComboBox(ColorO);
JComboBox Size= new JComboBox(SizeO);
JComboBox Style= new JComboBox(StyleO);
public MyFrame() {
super("Format Frame");
setLayout(new FlowLayout());
add(Name);
add(Size);
add(Style);
add(Colour);
add(lbl);
Name.setMaximumRowCount(3);
Size.setMaximumRowCount(3);
Style.setMaximumRowCount(3);
Colour.setMaximumRowCount(3);
EventHandler handler= new EventHandler();
Style.addItemListener(handler);
}
class EventHandler implements ItemListener{
#Override
public void itemStateChanged(ItemEvent e) {
//When user chooses from the last combobox (style)
if(e.getSource()==Style)
{
if(Name.getSelectedItem().equals("BOLD"))
{
lbl.setFont(new Font((String)Name.getSelectedItem(),Font.BOLD, (int) Size.getSelectedItem()));
}
if(Name.getSelectedItem().equals("ITALIC"))
{
lbl.setFont(new Font((String)Name.getSelectedItem(),Font.ITALIC, (int) Size.getSelectedItem()));
}
if(Name.getSelectedItem().equals("PLAIN"))
{
lbl.setFont(new Font((String)Name.getSelectedItem(),Font.PLAIN, (int) Size.getSelectedItem()));
}
if(Colour.getSelectedItem().equals("RED"))
{
lbl.setForeground(Color.red);
}
if(Colour.getSelectedItem().equals("BLUE"))
{
lbl.setForeground(Color.BLUE);
}
if(Colour.getSelectedItem().equals("GREEN"))
{
lbl.setForeground(Color.GREEN);
}
}
}
}
}
It is listening, but you're checking the ComboBox.getSelectedItem(), which hasn't been updated at the time the event is fired. The item the event relates to is referenced in the event itself; call e.getItem() to retrieve it:
Object item = e.getItem();
if (item.equals("BOLD")) {
lbl.setFont(new Font((String) item, Font.BOLD, /* wrong: (int) Size.getSelectedItem() */ 8));
}
Your size calculation (commented above) is wrong too. Your size selection box holds Strings, so you'll have to parse them (or change the model to ints).
Also... you'll get two events for each change, ItemEvent.DESELECTED first (for the old item), then ItemEvent.SELECTED. You should check for the event you're interested in:
if (e.getSource() == Style && e.getStateChange() == ItemEvent.SELECTED) {

How to select an item from a JList without using a button?

I've been making a program, and one part of it is the ability to choose an item from a JList and have it display a specific icon in a JLabel. I've made it work so that the user has to select the item from the list and then press a button to initiate the action.
I'm just wondering if there's any way to make it so the button isn't necessary? In other words, the user simply has to click the list item and it immediately initiates the action.
Here is my code:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class Example extends JFrame
{
JList list = null;
Example()
{
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
ArrayList data = new ArrayList();
data.add("Py");
data.add("Piper");
list = new JList(data.toArray());
list.addListSelectionListener(new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent evt)
{
// To avoid double value selected
if (evt.getValueIsAdjusting())
return;
System.out.println("Selected: " + list.getSelectedValue());
}
});
cp.add(new JScrollPane(list), BorderLayout.CENTER);
}
public static void main(String[] s)
{
Example l = new Example();
l.pack();
l.setVisible(true);
}
}
So right here:
list.addListSelectionListener(new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent evt)
{
// To avoid double value selected
if (evt.getValueIsAdjusting())
return;
System.out.println("Selected: " + list.getSelectedValue());
}
});
So what you are actually doing is to "plug" a ListSelectionListener to your JList so that can be notified for any events that occur to the JList. Within the valueChanged you add the code need to be executed when the user select something in the JList.
There is this wonderful resource with the JList JavaDoc.

How to set the title of a JComboBox when nothing is selected?

I want to have a JCombobox in my Swing application, which shows the title when nothing is selected. Something like this:
COUNTRY ▼
Spain
Germany
Ireland
I want "COUNTRY" to show when the selected index is -1 and thus, the user wouldn't be able to select it. I tried to put it on the first slot and then overriding the ListCellRenderer so the first element appears greyed out, and handling the events so when trying to select the "title", it selects the first actual element, but I think this is a dirty approach.
Could you lend me a hand?
Overriding the ListCellRenderer is a good approach, but you tried something overly complicated. Just display a certain string if you are rendering the cell -1 and there is no selection (value is null). You are not limited to display elements on the list.
The following is an example program that demonstrates it:
Full Code:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
public class ComboBoxTitleTest
{
public static final void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
new ComboBoxTitleTest().createAndShowGUI();
}
});
}
public void createAndShowGUI()
{
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JPanel buttonsPanel = new JPanel();
frame.add(mainPanel);
frame.add(buttonsPanel, BorderLayout.SOUTH);
String[] options = { "Spain", "Germany", "Ireland", "The kingdom of far far away" };
final JComboBox comboBox = new JComboBox(options);
comboBox.setRenderer(new MyComboBoxRenderer("COUNTRY"));
comboBox.setSelectedIndex(-1); //By default it selects first item, we don't want any selection
mainPanel.add(comboBox);
JButton clearSelectionButton = new JButton("Clear selection");
clearSelectionButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
comboBox.setSelectedIndex(-1);
}
});
buttonsPanel.add(clearSelectionButton);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class MyComboBoxRenderer extends JLabel implements ListCellRenderer
{
private String _title;
public MyComboBoxRenderer(String title)
{
_title = title;
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean hasFocus)
{
if (index == -1 && value == null) setText(_title);
else setText(value.toString());
return this;
}
}
}
index == -1 in the renderer is the head component that, by default, displays the selected item and where we want to put our title when there's no selection.
The renderer knows that there's nothing selected because the value passed to it is null, which is usually the case. However if for some weird reasons you had selectable null values in your list, you can just let the renderer consult which is the explicit current selected index by passing it a reference to the comboBox, but that is totally unrealistic.

Combo Boxes in netbeans

i have a gui in netbeans. 3 textfields animal id(i.e MAM001) , type of animal(LION) and nickname(SIMBA). when the three textfields are entered the user can click on the submit button which will store the values from the three textfields in a database.
what i want to do but don't know how to do it, is to use a combo box with three different fields in it (MAMMAL,BIRD REPTILE). when i select mammal from the combo box it will the change mysql statements in the background so that the data entered into the textfields will go into the mammal table in the database. if i click on the "bird" field in the combo box the same thing will happen except the data will go into the bird table in the database.
Any help would be greatly appreciated
Thank you.
I assume, that you want to react on an action event on your combo box. You can do this with the help of an ItemListener. For more details see the java api.
One approach could be the following:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class DemoFrame {
private JFrame frame;
private JComboBox comboBox;
private String[] items = {"IT1","IT2","IT3"};
public DemoFrame() {
frame = new JFrame("Demo Frame");
frame.setSize(300, 300);
comboBox = new JComboBox(items);
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
//perform here your database querys for specific items.
if(e.getItem().equals(items[0]) && e.getStateChange() == ItemEvent.SELECTED) {
//db query for it "IT1"
}
}
});
frame.add(comboBox);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new DemoFrame();
}
});
}
}

Find selected item of a JList and display it in real time

I have a JList, where i am displaying some ID's. I want to capture the ID the user clicked and dis play it on a JLabel.
String selected = jlist.getSelectedItem().toString();
The above code gives me the selected JList value. But this code has to be placed inside a button event, where when i click the button it will get the JList value an assign it to the JLabel.
But, what i want to do is, as soon as the user clicks an item of the JList to update the JLabel in real time. (without having to click buttons to fire an action)
A simple example would be like below using listselectionlistener
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class JListDemo extends JFrame {
public JListDemo() {
setSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
final JLabel label = new JLabel("Update");
String[] data = { "one", "two", "three", "four" };
final JList dataList = new JList(data);
dataList.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent arg0) {
if (!arg0.getValueIsAdjusting()) {
label.setText(dataList.getSelectedValue().toString());
}
}
});
add(dataList);
add(label);
setVisible(true);
}
public static void main(String args[]) {
new JListDemo();
}
}
Why don't you put a ListSelectionListener on your JList, and add your above code in to it.
I'm assuming you already know how to create listeners on JButtons, based on your question, so you just need to tweak it to create a ListSelectionListener instead, then assign the listener to your JList using jlist.addListSelectionListener(myListener);
There is a nice tutorial here that should get you started, or refer to the documentation
You should be aiming for something like this...
jlist.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {
if (!event.getValueIsAdjusting()){
JList source = (JList)event.getSource();
String selected = source.getSelectedValue().toString();
}
}
});
Use a ListSelectionListener:
JList list = new JList(...);
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
if (!evt.getValueIsAdjusting()) {
// code here
}
}
});

Categories