JList NullPointerException in valueChanged operation - java

here is my first JList:
JPanel classe = new JPanel();
class_list = new JList();
class_list.addListSelectionListener(this);
JScrollPane classeScrollPane = new JScrollPane(class_list);
classeScrollPane.setPreferredSize(new Dimension(175,405));
classe.setBorder(new TitledBorder("Classes"));
classe.add(classeScrollPane);
here is the second:
JPanel relation = new JPanel();
relation_list = new JList();
relation_list.addListSelectionListener(this);
JScrollPane relationScrollPane = new JScrollPane(relation_list);
relationScrollPane.setPreferredSize(new Dimension(220,130));
relation.setBorder(new TitledBorder("Relations"));
relation.add(relationScrollPane);
here is my valueChanged operation:
public void valueChanged(ListSelectionEvent e){
JList source = (JList) e.getSource();
String value = (String)source.getSelectedValue();
if (value.length() > 0){
if (source == class_list){
//if(!relation_list.isSelectionEmpty()) relation_list.clearSelection();
Class_object co = declaration.getClass(value);
attribut_list.setListData(co.getAttributes().toArray());
operation_list.setListData(co.getOperations().toArray());
if(declaration.getGeneralization(value) !=null){
subClass_list.setListData(declaration.getGeneralization(value).getSubClasses().toArray());
}
//clear JList if there is no correspondent subclass
else subClass_list.setListData(new String[2]);
//add relation content to relation panel
DefaultListModel model = new DefaultListModel();
related_association = declaration.getAssociation(value);
for(Association asso : related_association){
model.addElement("(R)"+asso.getName());
}
related_aggregation = declaration.getAggregation(value);
for(Aggregation agg : related_aggregation){
model.addElement("(A)"+agg.getName());
}
relation_list.setModel(model);
}
if (source == relation_list){
int focused_list = source.getSelectedIndex();
if(focused_list < related_association.size()){
details.setText(related_association.get(focused_list).toString());
}
else {
details.setText(related_aggregation.get(focused_list-related_association.size()).toString());
}
}
}
}
Basically, when we click on item in the first JList, it displays in the second JList something (for example a variable name of this item). Then we click on item in the second JList, it displays more information about this item in a JTextArea. So you have to click first jlist to display second jlist then click second jlist to display detail information.
Here is the problem, after I have clicked first jlist and second jlist, I click another item in first JList, a NullPointerException occurs in line "
if (value.length() > 0){
I understand that the error occurs because the variable value is null, but I don't know why value is null.
Could anyone tell me whats wrong with my code. Thanks alot.

During a change in selection, the currently selected item is "deselected", this means that, momentarily, nothing is selected, the ListSelectionListeners are notified of this change, this is where your null value is coming from.
Then the selection is changed to the newly selected item and the ListSelecitonListeners are notified again.
You can test for this through the use of ListSelectionEvent#getValueIsAdjusting
The reason this occurs the second time you select a value is because the deselection event notification does not occur, only the selection event...

Related

How to add MouseListener to a table model

I have a JTable. When a user clicks on a cell another JTable is created that shows the data for the whole row of that cell, in a column format (ie the row is converted to a column).
This happens when the user clicks but its a bit irritating to happen every time so I want to make it only on a double click.
The problem is that the getSelection method of the table only takes a addListSelectionListener method and not a MouseListener. How can I do what I want?
Here is the code:
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
int selectedRow = table.getSelectedRow();
DefaultTableModel newModel = new DefaultTableModel();
String rowName = "Row: " + selectedRow;
newModel.setColumnIdentifiers(new Object[]{rowName});
for (int i = 0; i < table.getModel().getColumnCount(); i++) {
newModel.addRow(new Object[]{table.getModel().getValueAt(selectedRow, i)});
}
JTable newTable = new JTable(newModel) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(140, 240);
}
};
// Apply any custom renderers and editors
JOptionPane.showMessageDialog(frame, new JScrollPane(newTable),
rowName, JOptionPane.PLAIN_MESSAGE);
}
}
});
This happens when the user clicks but its a bit irritating to happen every time so I want to make it only on a double click
You use a MouseListener, not a ListSelectionListener. You would check the Mouse event for a click count of 2.
Read the section from the Swing tutorial on How to Write a MouseLister for more information and working examples.
Also, a double click will start the editor by default so you want to make sure the cell is not editable. So you may need to override the isCellEditable(...) method of the table.

How do I dynamically update the JFrame with new data instead of a button

So I have a Jframe with 5 buttons. One of the buttons allow the user to add products to the inventory. The other buttons won't work until the user has added something to the inventory. Once the user has added something to the inventory, the user has to update the Jcombobox by the pressing the buy button and running some code that adds the data from an arrayList to the Jcombobox. My question is, I how do skip all of that and have it update right after the user adds an item to the inventory(This what I mean by dynamically).
relevant Code
code from Machine Frame that gets the information from an arraylist to a string array and adds it to the combobox.
case "buy":
if(product.checkInventory())
{
JOptionPane.showMessageDialog(mainMenu, "No Products in the vending machine.");
}
else
{
productList.removeItem("Product");
String tempArray[] = product.sendingInformationToVendor();
for (String tempArray1 : tempArray)
{
productList.addItem(tempArray1);
}
}
code from the addProductFrame that adds to the arrayList in the class productInventory
case "enter":
if (productDescription.getText().equals("") || costField.getText().equals("")) {
JOptionPane.showMessageDialog(addProductFrame, "Filling in all the necessary fields.");
} else {
String prodName = productDescription.getText();
String tempProdCost = costField.getText();
double prodCost = Double.parseDouble(tempProdCost);
int q = (int) quantity.getValue();
Product p = new Product(prodName, prodCost, q);
proInv.addProduct(p);
JOptionPane.showMessageDialog(addProductFrame, "This product has been successfully added to the vending machine");
productDescription.setText("");
costField.setText("");
quantity.setValue(1);
}
Each of these snippets of code are in a class called processAction that implements actionlistener and each of the string next to the keyword case is the action command for each button

How to link JcheckBoxes to JtextFields when they are being dynamically generated?

i want my app to create jcheckboxes from an input that always changes.
I want to create a jtextfield near every checkbox, that will be set enabled, only when his checkbox is pressed.
I managed to create this code:
//Create checkboxes with textfileds
for (int i = 0; i < activeProjects.length; i++) {
projectPanels[i] = new JCheckBox(activeProjects[i]);
projectPanels[i].setSelected(false);
projectPanels[i].setComponentOrientation (ComponentOrientation.RIGHT_TO_LEFT);
projectPanels[i].setAlignmentX(RIGHT_ALIGNMENT);
projectPanels[i].addItemListener(this);
projectStorageNum[i] = new JTextField("");
// projectStorageNum[i].setEnabled(false);
projectStorageNum[i].setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
projectStorageNum[i].setMaximumSize(new Dimension(200,30));
projectStorageNum[i].setMinimumSize(new Dimension(200,30));
projectStorageNum[i].setPreferredSize(new Dimension(200,30));
projectStorageNum[i].setAlignmentX(RIGHT_ALIGNMENT);
tmppnl = new JPanel();
tmppnl.add(projectStorageNum[i]);
tmppnl.add(projectPanels[i]);
checkBoxPanel.add(tmppnl);
}
and this is my state change listener:
public void itemStateChanged(ItemEvent e) {
Object source = e.getItemSelectable();
JCheckBox myBox= (JCheckBox)source;
String bName = myBox.getText();
if (e.getStateChange() == ItemEvent.SELECTED)
{
// enable matching text field.
// add bName to projects list.
}
else
{
//disable matching textfield
// remove bName from list
}
when I access the checkboxes in a dynamic way I don't have access to the second array of textfields.
is there any way to link them , or any other idea ?
thanks
Dave.
One thing you could do is use the setName and getName methods of Component to save the index of the JCheckBox.
projectPanels[i].setName(Integer.toString(i));
Then, in your state change listener.
int i = Integer.valueOf(e.getName());
This gives you the index of the JTextField.
You could use a Map (Hashmap) the checkbox would be the key and the textField the value returned when you do the key loopup.

Java JList remove() method throws an ArrayOutOfBoundsException

I'm using a JList which displays correctly. However, I'm having trouble removing elements from the list.
JList nameList = new JList(db.getAllNames());
nameList.setVisibleRowCount(6);
nameList.setFixedCellWidth(400);
JButton removeNameButton = new JButton("Remove Name");
removeNameButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String id = nameList.getSelectedValue().toString(); //valid value when button pressed
int index = nameList.getSelectedIndex(); //valid value when value pressed
namesList.remove(index); //ERROR
}
The JList contains 4 names, which displays perfectly and seem to have the correct indexes. (If I check the value System.out.println(copiersList.getModel().getSize()); it always displays 4
Here is the error message:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 3
Oddly, if I remove Adam, I do not get an error (but visibly the list does not change and calling .getSize() method displays 4):
id selected: Adam
index selected: 0
However, any other:
id selected: BobException in thread "AWT-EventQueue-0"
index selected: 1
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 1
at java.awt.Container.remove(Unknown Source)
Don't remove from the JList itself since the remove(...) method does not do what you think that it does. It in fact is trying to remove a component that is held in the JList as if it were a JPanel that held other components, even if no such component exists. Instead remove from the JList's model, usually a DefaultListModel. The DefaultListModel class has a removeElement(Object element) and a removeElementAt(int index) method that can help you.
i.e.,.
public void actionPerformed(ActionEvent e) {
String id = nameList.getSelectedValue().toString(); //valid value when button pressed
int index = nameList.getSelectedIndex(); //valid value when value pressed
DefaultListModel listModel = (DefaultListModel) namesList.getModel();
listModel.removeElementAt(index);
}

How can I setSelected for a ButtonGroup where all its JRadioButtons were created in a loop?

I've got the following for loop creating JRadioButtons for the ButtonGroup btgrpDiff for each of the values in my Difficulty enum:
private enum Difficulty {
EASY("Easy"),
MEDIUM("Medium"),
HARD("Hard"),
EXTRA_HARD("Extra Hard");
public final String name;
private Difficulty(String name) {
this.name = name;
}
}
for (Difficulty diff : Difficulty.values()) {
JRadioButton radDiff = new JRadioButton(diff.name);
radDiff.setActionCommand(diff.name);
btgrpDiff.add(radDiff);
panDiff.add(radDiff, "align 50%, shrink 2, wrap");
}
How can I setSelected for the ButtonGroup btgrpDiff outside of the for loop? I'd like to either set it straight after they're all selected or have a boolean parameter for each difficulty level in my enum to determine whether or not they get set as selected in the for loop, but I'm not sure which would be best, or how exactly to get the ButtonModel for the JRadioButtons.
Upon creation put your buttons in an ArrayList.
as class variable you should have
ArrayList<JRadioButton> mylist = new ArrayList<JRadioButton>()
So inside the loop do:
mylist.add(new JRadioButton(diff.name));
then you can access them anytime you want using mylist.get(i)
Or put them in a Map, then you can get them directly:
Map<Difficulty,JRadioButton> rButtons = new HashMap<Difficulty,JRadioButton>();
for (Difficulty diff : Difficulty.values()) {
JRadioButton radDiff = new JRadioButton(diff.name);
rButtons.put(diff,radDiff);
btgrpDiff.add(radDiff);
...
}

Categories