Adding New Item to JComboBox Does Not Display - java

I have a JComboBox that is editable. When the user enters a new item, I want that added to the list and display it as the selected item. I am able to add it to the list but I cannot seem to make it display as the selected item. By default I display an empty string ("") which is what the user would edit to add the new item.
public class EventComboBoxListener implements ActionListener {
private JComboBox<String> eventBox=null;
public EventComboBoxListener(JComboBox<String> event_) {
eventBox=event_;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Selected: " + eventBox.getSelectedItem());
System.out.println(", Position: " + eventBox.getSelectedIndex());
if (eventBox.getSelectedIndex() < 0) {
eventBox.addItem(eventBox.getSelectedItem().toString());
eventBox.setSelectedItem(eventBox.getSelectedItem().toString());
}
}
}
It doesn't make sense to me that I have to use setSelectedItem with the getSelectedItem. That it does not work is no surprise but I don't know what else to do. The newly added item shows up in the list as it should but how do I make it the selected item in the display at the same time? I can select it after but that should not be necessary.
Added MVCE:
Main
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
public class Test {
public static void main(String[] args) {
String[] list= {"","A","B","C"};
TestTableModel model=new TestTableModel(null,new String[] {"col1","col2"});
JTable table=new JTable(model);
JDialog dialog=new JDialog();
JScrollPane scroller=new JScrollPane(table);
JComboBox<String> box=new JComboBox<String>(list);
box.setEditable(true);
box.setSelectedIndex(0);
box.addActionListener(new EventComboBoxListener(box));
JTextField field=new JTextField();
field.setPreferredSize(new Dimension(75,30));
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setLayout(new FlowLayout());
dialog.setSize(new Dimension(400,100));
dialog.add(scroller);
dialog.pack();
dialog.setVisible(true);
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(box));
table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(field));
model.insertRow(0,new Object[] {"","placeholder"});
}
}
TestTableModel class
import javax.swing.table.DefaultTableModel;
public class TestTableModel extends DefaultTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
public TestTableModel(Object[][] data_,String[] columnNames_) {
super(data_,columnNames_);
}
}

First of all some comments about the MCVE (since you will be including one with every question in the future).
We expect the code so be in a single source file so we can easily copy/paste compile and test. We don't want 3 files lying around on our machine that we need clean up after testing.
Only relevant code directly related to the problem should be included. Why do you have the TestTableModel class. Are the "column names" relevant to the problem? The point is always test your MCVE using standard JDK classes when possible.
Regarding the EventComboListener class. Again, this can be added to the combo box by using and annoymouse inner class or a lambda. This keeps the code in a single class.
The newly added item shows up in the list as it should but how do I make it the selected item in the display at the same time?
I found that playing with your MCVE the ActionListener of the combo box is invoked at different times.
So my suggestion is to add the ActionListener to the editor of the combo box. Then we know for sure the ActionListener is only invoked when you press the Enter key. Once you press the Enter key the editor is stopped and the value is saved to the model.
So the logic would be something like:
//box.addActionListener(new EventComboBoxListener(box));
ComboBoxEditor editor = box.getEditor();
JTextField textField = (JTextField)editor.getEditorComponent();
textField.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
String item = textField.getText();
DefaultComboBoxModel model = (DefaultComboBoxModel)box.getModel();
if (model.getIndexOf(item) == -1)
{
box.addItem(item);
box.setSelectedIndex( box.getItemCount() - 1 );
}
}
});
So the trick is to set the select index (not the selected item). But first the logic checks to make sure the item has not already been added to the combo box.

Related

JComboBox ItemListener error

Looking at adding event listeners to JComboBoxes.
Ive done the usual window etc. Created a new JComboBox and then .addItem() islands into it.
I have then attempted to use .addItemListener(this) on my newly created combobox
But theres a problem, its mentioning abstract class which means i have not done something. Can anyone see where ive gone wrong?
Ive tried .addItemListener(this) on the individual entries and that did not work. Ive tried declaring the JComboBox inside and outside of the constructor.
It may be worth noting the method itemStateChange is from the book, I have had to build around that block.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class ComboBoxPractice extends JFrame implements ItemListener
{
//create islands
JLabel selection = new JLabel();
JComboBox islands = new JComboBox();
public ComboBoxPractice()
{
// set a window
super("action");
setSize(300,100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
// set a container
Container content = getContentPane();
FlowLayout layout = new FlowLayout();
content.setLayout(layout);
//add item listener
islands.addItemListener(this);
// add items to list
islands.addItem("Corfu");
islands.addItem("Crete");
islands.addItem("Canada");
islands.addItem("Canary Islands");
//add island and label to container
content.add(islands);
content.add(selection);
}
public void itemStateChange(ItemEvent event)
{
String choice = event.getItem().toString();
selection.setText("chose" + choice);
}
}
#Override
public void itemStateChanged(ItemEvent event)
{
String choice = event.getItem().toString();
selection.setText("chose" + choice);
}
Try changing it to that. with the #Override on top. This then doesn't throw an error for me and works.

The text in the JComboBox displays a string but the selection is actually set to null

I have a JComboBox which I create with the following code:
employeeDeletetxt = new JComboBox(buildComboBoxmodel("SELECT employee_id, employee_first_name FROM employees"));
employeeDeletetxt.setSelectedItem(null);
Now, when I run the program the selection is set to null so nothing is displayed in the combo box. I have an ActionListener for a delete button. The ActionListener would delete certain records and when this happens I need the data in the JComboBox to reflect the recent changes. I use the following code:
employeeDeletetxt.removeItem(employeeDeletetxt.getSelectedItem());
employeeDeletetxt.setSelectedItem(null);
The problem is that the text displayed in the JComboBox is not empty after these lines are called. However, the item which the JComboBox points to is actually null because I get the following error message when I call the ActionListener directly after I have called it the previous time:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
How can I set the text to be empty?
I found the solution to the problem and would like to share it with everyone in case someone else has the same problem. As I stated above, the AutoCompleteDecorator was what was causing the problem in the first place. If I removed it then the program would work as expected. However I wanted to provide the user with the ability to search. The solution is to use AutoCompletion instead which is found in the following link: http://www.orbital-computer.de/JComboBox/source/AutoCompletion.java. now, in the program, instead of using:
AutoCompleteDecorator.decorate(employeeDeletetxt);
I use:
AutoCompletion.enable(employeeDeletetxt);
This way I allow the user to use the autocomplete option while also being able to set the current selection of the combo box to null.
I tried to implement what you described and got to this:
import java.awt.GridLayout;
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.JPanel;
import javax.swing.SwingUtilities;
public class TestGui extends JFrame{
JPanel contentPane = new JPanel();
JButton button = new JButton("Press me!");
JComboBox comboBox = new JComboBox(new String[] {"None", "Help"});
public TestGui() {
initalise();
}
private void initalise() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.comboBox.setSelectedItem(null);
this.contentPane.setLayout(new GridLayout(2,1));
this.contentPane.add(comboBox);
this.contentPane.add(button);
this.button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
comboBox.removeItem(comboBox.getSelectedItem());
comboBox.setSelectedItem(null);
}
});
this.setContentPane(this.contentPane);
this.pack();
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestGui();
}
});
}
}
My program runs exactly the way you described. Maybe you can find your problem.
The problem is that you are setting the current item to null which is different than setting it to an empty string. You can do something like:
employeeDeletetxt.setSelectedItem("").
What I would probably do is create a method that has a loop that creates an array of strings for your combobox and always have the first element be the empty string. That way, once the array is built, you add the rest of your elements retrieved from your query. If your query returns no results, you will just have the text box with the one blank element.

Get selected `JCheckBox` associated `id` on swing

Before I asked this question, I went through many examples, some of them are related, but did not answer my needs:
How to get the selected index of JCheckbox?
Java- Reading whether a checkbox is checked or not
I have a list as keyMessageList which includes id as Long and associated keyWord as String.
I displayed keyWord's name on my jpanel using following code:
for (KeyMessage obj : keyMessageList) {
checkBox = new JCheckBox(obj.getSmsKey());
displayKeywordPanel.checkBooxPanel.add(checkBox);
}
I got the following output:
Now, My requirement is: If I select keywords, I need to get the id associated with the selected keyword. I have done similar things many times in web applications like this, but now I need to do the same thing on swing. I used the following code on web application to fulfill the requirements.
Code for web:
<h:selectOneMenu id="branch" value="#{createUser.branchId}" required="true" requiredMessage="Please choose branch">
<f:selectItems value="#{allBranch}"/>
</h:selectOneMenu>
Can any swing expert please help me.
Note I may select multiple checkBox and keyMessageList returns from JPA query.
I have a list as keyWordsList which includes id and associated keyWord.
Don't use a List. Instead use a Map with the "keyword" as the key and the "id" as the value. Then when you select a check box you get the ID from the Map.
Another option would be to create you JCheckBox as follows:
JCheckBox checkBox = new JCheckBox(keyword);
checkbox.setActionCommand( id );
Then later you access the id of the selected checkbox by using the getActionCommand() method.
You can get displayKeywordPanel.checkBooxPanel.getComponents() array. Iterate through the array and store indexes. Then use the indexes to get elements from the keyMessageList
I think you can extend your own JCheckBox (let say JCheckBoxWithID) which allow you keep the id. Then use a List to store/remove ids everytime a checkbox is selected/unselected using an ItemListener
This way you'll be avoiding iterate over your checkboxPanel asking who is selected and keeping separated responsibilities:
JCheckBox just shows a keyword and holds an id
List just stores selected ids
ItemListener handles the event when a JCheckBox becomes selected/unselected and adds/removes its id to/from List
Hope this example be helpful:
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Tests {
private void initGUI(){
/* This list will store selected ids */
final List<Integer> selectedIds = new ArrayList<>();
ItemListener itemListener = new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getSource() instanceof JCheckBoxWithID){
JCheckBoxWithID checkBoxWithID = (JCheckBoxWithID) e.getSource();
if(checkBoxWithID.isSelected()){
selectedIds.add(checkBoxWithID.getId());
} else {
selectedIds.remove(checkBoxWithID.getId());
}
}
}
};
String[] keyWords = new String[]{"Help 1", "Help 2", "Help 3", "Help 4", "Help 5", "Help 6"};
Integer id = 0;
JPanel checkBoxesPanel = new JPanel(new GridLayout(3,3));
/* Add many checkbox as you keywords you have */
for(String keyWord : keyWords){
JCheckBoxWithID checkBoxWithID = new JCheckBoxWithID(keyWord, id);
checkBoxWithID.addItemListener(itemListener);
checkBoxesPanel.add(checkBoxWithID);
id++;
}
JButton submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, Arrays.toString(selectedIds.toArray()), "Selected IDs", JOptionPane.INFORMATION_MESSAGE);
}
});
JPanel content = new JPanel(new FlowLayout(FlowLayout.LEADING));
content.add(checkBoxesPanel);
content.add(submit);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Tests().initGUI();
}
});
}
class JCheckBoxWithID extends JCheckBox {
/* I use Integer but the id could be whatever you want, the concept is the same */
private Integer _id;
public JCheckBoxWithID(String text, Integer id) {
super(text);
_id = id;
}
public void setId(Integer id){
_id = id;
}
public Integer getId(){
return _id;
}
}
}
Here's a print screen:

JTextField hangs on GUI update via X11 forwarding

I have a Swing GUI that allows a user to add JTextFields to the GUI as needed. When I run this locally on the console (on ubuntu), everything works fine.. When I run the GUI from Cygwin on a Windows box using X11 forwarding, everything starts out fine, but when I click the "add" button to put a new JTextField on the GUI, the text field shows up as expected, but I can't click in it or modify it, etc., for a long time. In fact, I can't click in the original text fields either.. After a little more than 30 seconds, the text fields come back to life and work normally until I click "add" again.
I've included a SSCCE below that demonstrates the problem. Again, this only seems to happen when running with X11-forwarding, and if I run on the Ubuntu console directly, it works as expected, so I'm not sure if this will be reproduce-able for everyone else.
One last piece of information - in my real program, clicking the add button causes a JComboBox and two JTextFields to be added. The combo box is responsive right away, but all text fields on the GUI (new ones and old ones too) are not.
HmmFrame.java:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class HmmFrame extends JFrame
{
ArrayList< JTextField > fields;
JPanel mainPan;
JButton addButton;
HmmFrame()
{
super("Hmmm");
JTextField curField;
fields = new ArrayList< JTextField >();
setLayout(new FlowLayout());
mainPan = new JPanel(new FlowLayout());
this.add(mainPan);
addButton = new JButton("Add");
addButton.addActionListener(new HmmListener());
this.add(addButton);
curField = new JTextField("Try");
fields.add(curField);
updateGUI();
setVisible(true);
}
public void updateGUI()
{
mainPan.removeAll();
for (JTextField curField : fields)
{
mainPan.add(curField);
}
pack();
}
public class HmmListener implements ActionListener
{
public void actionPerformed(ActionEvent actEv)
{
JTextField curField;
curField = new JTextField("New One" + fields.size());
fields.add(curField);
updateGUI();
}
}
}
Hmm.java (driver)
public class Hmm
{
public static void main(String [] args)
{
HmmFrame hmmFrame;
hmmFrame = new HmmFrame();
}
}

Java first GUI, two classes

I'm trying to program my first GUI-class in Java, using the Window Builder. Ok, the GUI is ready but has no functions yet (it contains 10 checkboxes (yes, they are all neccessary) and 2 buttons and a JTextField, so nothing special). So I just drag'n'dropped the checkboxes and button into the window, I haven't coded anything yet.
I have two classes:
GUI.java -> only for the layout
Main.java -> should get 'inputs' from GUI.java
Now the user should check or uncheck the checkboxes and then finally press a button.
But how do I 'read out' if a checkbox is checked or not - I have two classes?
I have to add that I'm a beginner to Java and especially to GUI-programming, but I just want to learn it. I would be happy to receive some help but NOT the complete code.
Basically you instantiate an object of your GUI from the Main.java. Then you have access to this GUI (assumed you have setter/getter-methods or the Components in the GUI are public). In the GUI constructor you call all builder methods, so when you then call new GUI() from Main.java, you got a) the GUI running and b) access to it from Main.java
For your specific question about the checkboxes, you can call
nameOfCheckbox.isSelected()
which returns a boolean wheter the checkbox is checked or not.
Viceversa: since your Main.java has (or should have) static methods (like the main-method), you can then simply call Main.anyMethodName() from GUI.java (assuming this anyMethod is static) and pass data from the "visual area" to the "logic area" (it is recommended to seperate this two componentes as good as possible).
I know you said you didn't want the full, code but this isn't really it, just a very basic working demo of what you want to do
Gui.java
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Gui {
JFrame frame;
JButton button;
JCheckBox checkBox;
JLabel label;
public Gui() {
frame = new JFrame("demo");
button = new JButton("is it checked?");
checkBox = new JCheckBox();
label = new JLabel("no");
JPanel panel = new JPanel();
panel.add(checkBox);
panel.add(button);
panel.add(label);
frame.add(panel);
frame.pack();
//frame.setSize(200, 60);
frame.setResizable(false);
frame.setLocation(400, 400);
frame.setVisible(true);
}
// method to add an action listener to the gui's
// private button
public void setButtonActionListener(ActionListener al) {
button.addActionListener(al);
}
// gui method to check if box is checked
public boolean isBoxChecked() {
return checkBox.isSelected();
}
// method to set lable
public void setText(String text) {
label.setText(text);
}
}
Main.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
public static void main(String[] args) {
// create an instance of your gui class
final Gui gui = new Gui();
// add the action listener to the button
// notice how we reference the gui here by running the methods in the
// gui class
// this action listener could be created in the gui
// class but in general you don't want to do that because actions will
// involve multiple classes
gui.setButtonActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
gui.setText((gui.isBoxChecked() ? "yes" : "no"));
}
});
}
}
Attach an ItemListener.
You can determine if the box is rising (unchecked to checked) or falling (checked to unchecked) with the following line in itemStateChanged(ItemEvent e)
boolean selected = e.getStateChange() == ItemEvent.SELECTED;
To determine whether it is checked when it is not changing, just use isSelected()
Either like that:
checkbox.isSelected();
Or this would be a way by an Itemlistener which will be called if there is a change:
checkbox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) {
foo = false;
} else {
foo = true;
}
}
});
You could expose all of your gui objects as fields in your gui class
public JTextField getNameTextField() {
return nameTextField;
}
public JCheckBox getCheckBox1() {
return checkBox1;
}
and then in main:
if (gui.getCheckBox1().isSelected())
// do stuff
Assuming your checkbox is an object named "myCheckBox", you can check if it's selected or not by using:
myCheckBox.isSelected()
Returns true if the checkbox is selected.
I reccomend you to check Java's tutorials on how to use the various GUI components, e.g:
http://docs.oracle.com/javase/tutorial/uiswing/components/button.html

Categories

Resources