JTable update after row selection - java

Here is an SSCCE of a JTextField that auto-completes a JTable.
It works fine until I wanted to do something when a row is selected. The problem is that whenever a row in the JTable is selected, changing the JTextField text throws an exception:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.Vector.elementAt(Vector.java:430)
at javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:632)
at javax.swing.JTable.getValueAt(JTable.java:2681)
at fr.ensicaen.si.client.AnimalAutoComplete$1.valueChanged(AnimalAutoComplete.java:73)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:167)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:147)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:194)
at javax.swing.DefaultListSelectionModel.changeSelection(DefaultListSelectionModel.java:388)
at javax.swing.DefaultListSelectionModel.changeSelection(DefaultListSelectionModel.java:398)
at javax.swing.DefaultListSelectionModel.removeSelectionIntervalImpl(DefaultListSelectionModel.java:559)
at javax.swing.DefaultListSelectionModel.clearSelection(DefaultListSelectionModel.java:403)
at javax.swing.JTable.clearSelection(JTable.java:2075)
at fr.ensicaen.si.client.AnimalAutoComplete$AutoCompleteListener.fill(AnimalAutoComplete.java:97)
at fr.ensicaen.si.client.AnimalAutoComplete$AutoCompleteListener.insertUpdate(AnimalAutoComplete.java:93)
In fact, selecting a row and do something works. But when the JTextField is modified, the ListSelectionListener is fired again (but shouldn't?) and I can't figure out why!
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import java.awt.GridLayout;
public class AnimalAutoComplete extends JFrame {
private JPanel contentPane;
private JScrollPane animalPane;
private JTable animalTable;
private JPanel panel;
private JTextField animalField;
/** Create the frame. */
public AnimalAutoComplete() {
/* Frame structure */
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 710, 471);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
animalPane = new JScrollPane();
contentPane.add(animalPane, BorderLayout.CENTER);
panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(new GridLayout(1, 0, 0, 0));
/* JTable model */
DefaultTableModel animalModel = new DefaultTableModel();
animalTable = new JTable(animalModel);
animalPane.setViewportView(animalTable);
animalModel.addColumn("Animal");
/* Initially fills the JTable */
List<String> animals = new ArrayList<String>();
animals.add("Dog");
animals.add("Cat");
animals.add("Fish");
for (String a : animals) {
animalModel.addRow( new Object[] {a} );
}
/* Text fields */
animalField = new JTextField();
panel.add(animalField);
animalField.setColumns(10);
/* This listener updates the JTable depending on the JTextField */
animalField.getDocument().addDocumentListener(new AutoCompleteListener(animalTable, animals, animalField));
/* This listener will do something useful when an animal is selected*/
animalTable.getSelectionModel().addListSelectionListener(
new ListSelectionListener(){
public void valueChanged(ListSelectionEvent event) {
System.out.println(animalTable.getValueAt(animalTable.getSelectedRow(), 0));
}
}
);
}
private final class AutoCompleteListener implements DocumentListener {
private final JTable animalTable;
private final List<String> animals;
private JTextField searchedAnimal;
private AutoCompleteListener(JTable animalTable,
List<String> animals, JTextField textAnimal) {
this.animalTable= animalTable;
this.animals = animals;
this.searchedAnimal = textAnimal;
}
public void changedUpdate(DocumentEvent arg0) {fill();}
public void insertUpdate(DocumentEvent arg0) {fill();}
public void removeUpdate(DocumentEvent arg0) {fill();}
public void fill() {
animalTable.clearSelection();
DefaultTableModel model = (DefaultTableModel) animalTable.getModel();
model.setRowCount(0);
for (String a : animals) {
if (a.startsWith(this.searchedAnimal.getText())) {
model.addRow(new Object[] {a});
}
}
}
}
public static void main(String[] args) {
AnimalAutoComplete frame = new AnimalAutoComplete();
frame.setVisible(true);
}
}

The problem is that the selection event is fired twice when a table row(or col/cell) gets selected. First time with index -1 and the second time with correct index. So check with a condition if animalTable.getSelectedRow() is returning -1:
public void valueChanged(ListSelectionEvent event) {
int selRow = animalTable.getSelectedRow()
if(selRow >= 0)
{
System.out.println(animalTable.getValueAt(selRow, 0));
// or do other things
}
}
As #camickr has suggested below, you can also make use of event.getValueIsAdjusting() method: which returns true if the selection is still changing. Many list selection listeners are interested only in the final state of the selection and can ignore list selection events when this method returns true. In fact using this function is preferable against the one mentioned above as it makes the action code more specific.

Related

How do I update JList and store into an array using a function?

I am under the impression that most of my code work, however, I think I am confident that I am only missing one line under the function updatedJList() Please help, thank you.
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JList;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Ex1 extends JFrame {
private JTextField txtName;
private JList nameList;
private String[] nameArr;
private int arrCounter = 0;
private JLabel lblDisplayName;
public Ex1(){
this.setTitle("Exercise01");
this.setSize(300, 266);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(null);
this.nameArr = new String[10];
JLabel lblName = new JLabel("Name:");
lblName.setBounds(10, 11, 264, 14);
getContentPane().add(lblName);
this.txtName = new JTextField();
this.txtName.setBounds(10, 25, 264, 20);
getContentPane().add(this.txtName);
this.txtName.setColumns(10);
JButton btnAddName = new JButton("Add Name to List");
btnAddName.setBounds(10, 49, 264, 23);
getContentPane().add(btnAddName);
btnAddName.addActionListener(new AddNameListener());
//Create ScrollPane
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 75, 264, 126);
getContentPane().add(scrollPane);
//Create and Add JList
this.nameList = new JList();
nameList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.updateJList();
this.nameList.addListSelectionListener(new DisplayListener());
this.lblDisplayName = new JLabel("(Name will be shown here)");
this.lblDisplayName.setHorizontalAlignment(SwingConstants.CENTER);
this.lblDisplayName.setBounds(10, 203, 264, 14);
getContentPane().add(this.lblDisplayName);
this.setVisible(true);
}
private class AddNameListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
updateJList();
}
}
private void updateJList(){
//I think I am missing something on this line.. HELP
String name = this.txtName.getText();
this.txtName.setText(name);
this.arrCounter++;
this.txtName.setText("");
DefaultListModel model = new DefaultListModel();
for(int i =0;i<this.nameArr.length;i++)
{
model.addElement(name);
}
this.nameList.setModel(model);
}
private class DisplayListener implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent arg0) {
displayName();
}
}
private void displayName()
{
int index = this.nameList.getSelectedIndex();
String name = this.nameArr[index];
this.lblDisplayName.setText(name);
}
public static void main(String[] args) {
Ex1 gui = new Ex1();
}
}
I am very very very lost at this point, I cant seem to figure out what's wrong, I've been learning Java for about 8 weeks now, and I've also been working on this question for 4 hours. I really think I am missing a line, but if you think otherwise, please feel free to comment. Thank you, wonderful people!
Edit:
After some discussion the issue that the OP is stating is the following:
Whenever I run the code, it will work, however, when I key in the name in the text box to store it in the array and display it, it will not show up in the text box, therefore I cannot display the name.
Compare the below code with that in your question. The changes are described after the code.
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JList;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Ex1 extends JFrame {
private JTextField txtName;
private JList<Object> nameList;
private String[] nameArr;
private int arrCounter = 0;
private JLabel lblDisplayName;
public Ex1() {
this.setTitle("Exercise01");
this.setSize(300, 266);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(null);
this.nameArr = new String[10];
JLabel lblName = new JLabel("Name:");
lblName.setBounds(10, 11, 264, 14);
getContentPane().add(lblName);
this.txtName = new JTextField();
this.txtName.setBounds(10, 25, 264, 20);
getContentPane().add(this.txtName);
this.txtName.setColumns(10);
JButton btnAddName = new JButton("Add Name to List");
btnAddName.setBounds(10, 49, 264, 23);
getContentPane().add(btnAddName);
btnAddName.addActionListener(new AddNameListener());
// Create and Add JList
DefaultListModel<Object> model = new DefaultListModel<>();
this.nameList = new JList<>(model);
nameList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Create ScrollPane
JScrollPane scrollPane = new JScrollPane(nameList);
scrollPane.setBounds(10, 75, 264, 126);
getContentPane().add(scrollPane);
this.nameList.addListSelectionListener(new DisplayListener());
this.lblDisplayName = new JLabel("(Name will be shown here)");
this.lblDisplayName.setHorizontalAlignment(SwingConstants.CENTER);
this.lblDisplayName.setBounds(10, 203, 264, 14);
getContentPane().add(this.lblDisplayName);
this.setVisible(true);
}
private class AddNameListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
updateJList();
}
}
private void updateJList() {
// I think I am missing something on this line.. HELP
String name = this.txtName.getText();
this.txtName.setText(name);
this.arrCounter++;
this.txtName.setText("");
DefaultListModel<Object> model = (DefaultListModel<Object>) nameList.getModel();
model.addElement(name);
}
private class DisplayListener implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent arg0) {
displayName();
}
}
private void displayName() {
int index = this.nameList.getSelectedIndex();
if (index >= 0) {
ListModel<Object> model = nameList.getModel();
Object obj = model.getElementAt(index);
String name = obj == null ? "" : obj.toString();
this.lblDisplayName.setText(name);
}
}
public static void main(String[] args) {
Ex1 gui = new Ex1();
}
}
Create a model for the JList first and pass it to the JList constructor.
DefaultListModel<Object> model = new DefaultListModel<>();
this.nameList = new JList<>(model);
You are adding an empty JScrollPane. You need to pass the JList to the JScrollPane constructor.
JScrollPane scrollPane = new JScrollPane(nameList);
In method updateJList(), you don't need a new model, you just need to update the existing model by adding an element to it.
DefaultListModel<Object> model = (DefaultListModel<Object>) nameList.getModel();
model.addElement(name);
EDIT
Excuse me, I didn't pay attention to that part of your code that displays the selected value from nameList.
I changed method displayName() in the above code to the following:
private void displayName() {
int index = this.nameList.getSelectedIndex();
if (index >= 0) {
ListModel<Object> model = nameList.getModel();
Object obj = model.getElementAt(index);
String name = obj == null ? "" : obj.toString();
this.lblDisplayName.setText(name);
}
}
You don't need nameArr and you don't need arrCounter.
There is no need for an Array.
When you use Swing components, the data is store in a "model", in this case the DefaultListModel. So the data is added to the model and if you every want to access the data in the JList you get the data from the model.
DefaultListModel model = new DefaultListModel();
That code is wrong. You don't want to keep creating a new model every time you click on the button. You want to add items to the existing model so all the items can be displayed.
Read the section from the Swing tutorial on How to Use Lists. The ListDemo code will show you how to better structure your class so you can dynamically add and remove items in the model. So download the code and modify it for your requirements.

JTable changing column order and then editing cell raising bug

I have a strange problem with JTable.
What I have
A two-column JTable. And the second column uses JComboBox as a cell editor.
Problem
When I edit that JComboBox cell with the origin column order it works fine. But When I change the column first, such as switching that 2 column(JComboBox column becomes fist), then I edited the JComboBox cell raising Bug. I must click that cell twice to fire the editing event, otherwise, JComboBox isn't activated.
What I tried
I tried to use TableCellListener, but it raises the exception, such as column index is -1;
My SSCCE:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.AbstractAction;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.GridLayout;
import javax.swing.JTable;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
public class MainTable extends JDialog {
private static final long serialVersionUID = 156332386872772726L;
private final JPanel contentPanel = new JPanel();
private DefaultTableModel tableModel;
private JTable table;
public static void main(String[] args) {
try {
MainTable dialog = new MainTable();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public MainTable() {
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(new GridLayout(1, 0, 0, 0));
{
JScrollPane scrollPane = new JScrollPane();
contentPanel.add(scrollPane);
{
table = new JTable();
table.setAutoCreateRowSorter(true);
tableModel = new DefaultTableModel(new String[]{"first","second"},0);
table.setModel(tableModel);
{
//set comboBox to table
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.addItem("Input");
comboBox.addItem("Output");
table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(comboBox));
table.getColumnModel().addColumnModelListener(new TableColumnModelListener(){
#Override
public void columnAdded(TableColumnModelEvent arg0) {
}
#Override
public void columnMarginChanged(ChangeEvent arg0) {
}
#Override
public void columnMoved(TableColumnModelEvent arg0) {
table.requestFocusInWindow();
comboBox.setFocusable(true);
comboBox.requestFocus();
comboBox.grabFocus();
comboBox.requestFocusInWindow();//try to get focus, not worked.
}
#Override
public void columnRemoved(TableColumnModelEvent arg0) {
}
#Override
public void columnSelectionChanged(ListSelectionEvent arg0) {
}
});
}
// TableCellListener tcl = new TableCellListener(table, new AbstractAction(){
// #Override
// public void actionPerformed(ActionEvent e) {
// }
// });
tableModel.addRow(new Object[]{"1","Input"});
tableModel.addRow(new Object[]{"2","Output"});//init. add 2 rows
scrollPane.setViewportView(table);
}
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("Add");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int row = tableModel.getRowCount();
tableModel.addRow(new Object[]{row,"Input"});//click button to add a row
}
});
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
}
}
}
I must click that cell twice to fire the editing event, otherwise, JComboBox isn't activated.
This only happens the first time you try to edit the column after changing column order. It will also happens if you switch the column back to its original position.
It is like the table doesn't have focus so the first mouse click is giving the table focus.
So you could try to add a TableColumnModelListener to the TableColumModel. Then in the columnMoved event you can try using table.requestFocusInWindow()

Change color of selection (after selection) in a JComboBox

I'm writing a GUI using Swing. I have a custom written JComboBox using a ListCellRenderer and a BasicComboBoxEditor.
In my getListCellRendererComponent() method I change the color of the the list based on whether the item is "selected" (mouse is hovering above), which is nice and all, but I don't want the selection to change background color once a choice is made, which it currently does.
The first picture shows how the interface looks before a selection is made, and the second one shows how it looks after.
QUESTION
How do I change the background of the "selection" to the "stockColor"?
MCVE
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.Vector;
import javax.swing.DefaultComboBoxModel;
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.plaf.basic.BasicComboBoxEditor;
public class TFComboBox extends JComboBox{
public static void main(String[] args){
createAndShowGUI();
}
public static void createAndShowGUI(){
JFrame frame = new JFrame("MCVE");
JPanel pane = new JPanel(new BorderLayout());
TFComboBox cb = new TFComboBox();
boolean[] tf = {true, false};
cb.addItems(tf);
JButton b = new JButton("Click me!");
pane.add(cb, BorderLayout.CENTER);
pane.add(b, BorderLayout.LINE_END);
frame.add(pane);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private DefaultComboBoxModel model;
private Vector<Boolean> comboBoxItems;
private JComboBox comboBox;
public TFComboBox(){
comboBoxItems = new Vector<Boolean>();
comboBoxItems.add(Boolean.TRUE);
comboBoxItems.add(Boolean.FALSE);
comboBox = new JComboBox(comboBoxItems);
model = new DefaultComboBoxModel();
setModel(model);
setRenderer(new TrueFalseComboRenderer());
setEditor(new TrueFalseComboEditor());
}
public void addItems(boolean[] items){
for(boolean anItem : items){
model.addElement(anItem);
}
}
}
class TrueFalseComboRenderer extends JPanel implements ListCellRenderer {
private JLabel labelItem = new JLabel();
private Color stockColor = labelItem.getBackground();
public TrueFalseComboRenderer(){
setLayout(new BorderLayout());
labelItem.setOpaque(true);
labelItem.setHorizontalAlignment(JLabel.CENTER);
add(labelItem);
setBackground(Color.LIGHT_GRAY);
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
boolean tempValue = (boolean) value;
labelItem.setText(Boolean.toString(tempValue));
if(isSelected){
labelItem.setBackground(stockColor.darker());
labelItem.setForeground(Color.WHITE);
} else {
labelItem.setBackground(stockColor);
labelItem.setForeground(Color.BLACK);
}
return this;
}
}
class TrueFalseComboEditor extends BasicComboBoxEditor {
private JLabel labelItem = new JLabel();
private JPanel panel = new JPanel();
private Object selectedItem;
public TrueFalseComboEditor() {
labelItem.setOpaque(false);
labelItem.setHorizontalAlignment(JLabel.CENTER);
labelItem.setForeground(Color.WHITE);
panel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
panel.setBackground(Color.BLUE);
panel.add(labelItem);
}
public Component getEditorComponent(){
return this.panel;
}
public Object getItem(){
return this.selectedItem;
}
public void setItem(Object item){
if(item == null){
return;
}
this.selectedItem = item;
labelItem.setText(item.toString());
}
}
EDIT
I've added a MCVE and as you can see it is the "problem" that the JComboBox is focused that has to do with my issue. I've placed a button next to the ComboBox to help with removing the focus from the ComboBox.
Simply doing a setFocusable(false) would fix it, but also take away some of the functionality of the rest of the program, so this is not desired.
for better help sooner post an SSCCE / MCVE, short, runnable, compilable, with hardcoded value for JComboBox / XxxComboBoxModel in local variable
JList has Boolean array implemented as default in API (no idea whats hidden in
String trueFalseItem = Boolean.toString(tempValue); and with value stored JComboBox model)
this is just code minimum to test isSelected and to change JList.setSelectionXxx inside DefaultListCellRenderer
for example (code in SSCCE / MCVE form)
.
.
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.SwingUtilities;
public class ComboBoxBooleanModel {
private javax.swing.Timer timer = null;
private Vector<Boolean> comboBoxItems;
private JComboBox box;
public ComboBoxBooleanModel() {
comboBoxItems = new Vector<Boolean>();
comboBoxItems.add(Boolean.TRUE);
comboBoxItems.add(Boolean.FALSE);
box = new JComboBox(comboBoxItems);
box.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
if (Boolean.TRUE.equals(value)) {
l.setBackground(Color.RED);
if (isSelected) {
list.setSelectionForeground(Color.RED);
list.setSelectionBackground(Color.BLUE);
}
} else if (Boolean.FALSE.equals(value)) {
l.setBackground(Color.BLUE);
if (isSelected) {
list.setSelectionForeground(Color.BLUE);
list.setSelectionBackground(Color.RED);
}
}
return l;
}
return c;
}
});
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(box);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
box.setSelectedIndex(1);
}
});
start();
}
private void start() {
timer = new javax.swing.Timer(2250, updateCol());
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
if (box.getSelectedItem() == (Boolean) false) {
box.setSelectedItem((Boolean) true);
} else {
box.setSelectedItem((Boolean) false);
}
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ComboBoxBooleanModel comboBoxModel = new ComboBoxBooleanModel();
}
});
}
}
Here is a short demo of 2 JCombos, one of which will not change its background color when selected :
public static void main(String[] args){
JFrame frame = new JFrame("Combos BG Color test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.getContentPane().setPreferredSize(new Dimension(400, 40));
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(1,2));
frame.add(mainPanel);
JComboBox<String> aCombo = new JComboBox<>(new String[]{"A","B","C"});
mainPanel.add(aCombo);
JComboBox<String> bCombo = new JComboBox<>(new String[]{"1","2","3"});
Color bgColor = bCombo.getBackground();
bCombo.setRenderer(new DefaultListCellRenderer() {
#Override
public void paint(Graphics g) {
setBackground(bgColor);
super.paint(g);
}
});
mainPanel.add(bCombo);
frame.pack();
frame.setVisible(true);
}
(Most of the credit goes to this answer)

Update JTable from DefaultTableModel

so what i want to do is update a JTable when a button is pressed. Im using a DefaultTableModel as a source.
Table class:
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import java.awt.Dimension;
public class TableDemo extends JPanel {
String[] columnNames = {"Tipo","Cantidad"};
DefaultTableModel dtm = new DefaultTableModel(null,columnNames);
final JTable table = new JTable(dtm);
public TableDemo() {
table.setPreferredScrollableViewportSize(new Dimension(500, 700));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public void addRow(Object [] row)
{
dtm.addRow(row);
}
}
the form class:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
public class MyForm extends JFrame {
JPanel panel;
JLabel label;
JTextField txtName;
JTextField txtSurname;
JButton btnAccept;
TableDemo tb = new TableDemo();
public MyForm(){
initControls();
}
private void initControls() {
setTitle("Form Example");
setSize(600, 400);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
panel = new JPanel();
panel.setLayout(null);
label = new JLabel("Welcome to Swing");
label.setBounds(50, 10, 200, 30);
txtName = new JTextField();
txtName.setBounds(50, 50, 200, 30);
txtSurname = new JTextField();
txtSurname.setBounds(270, 50, 200, 30);
btnAccept = new JButton("Add");
btnAccept.setBounds(120, 100, 150, 30);
onAcceptClick();
TableDemo tablePanel = new TableDemo();
panel.add(label);
panel.add(txtName);
panel.add(txtSurname);
panel.add(btnAccept);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
tablePanel,panel );
splitPane.setDividerLocation(205);
splitPane.setEnabled(false);
getContentPane().add(splitPane);
}
private void onAcceptClick() {
btnAccept.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tb.addRow(new Object[]{"taza",txtName.getText()});
}
});
public static void main(String[] args) {
//Initilizer init = new Initilizer();
Runnable init = new Runnable() {
#Override
public void run() {
MyForm form = new MyForm();
form.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
As you can see i call the addRow function but in never updates in the JTable, what am i missing? Thnx
You're creating two TableDemo objects -- one you add to the GUI, tablePanel, the other you add a row to, tb;
// ...
TableDemo tb = new TableDemo(); // TableDemo #1. Never displayed
private void initControls() {
// ...
TableDemo tablePanel = new TableDemo(); // TableDemo #2
// ...
// TableDemo #2 is here added to the GUI
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, tablePanel,panel );
// ...
}
btnAccept.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// here you add a row to the non-displayed TableDemo #1
tb.addRow(new Object[]{"taza",txtName.getText()});
}
});
Solution: Don't do this (obviously)! Use only one TableDemo instance, display it and make changes to it. So get rid of the tablePanel variable and only use the tb variable.
Other problems:
You're using null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.

How to get JButtons to print integers in a JTextField by using Action Listener and Action Event?

I am trying to create and hypothetical ATM GUI interface to enter in a couple of numbers through a keypad. I am having trouble having the program display the numbers after the user clicks any of the buttons. I have only created one button for time sake:
public JButton jbtOne = new JButton(STANDARD_BTN_TEXTS[0][0]);
So if the user clicks 'jbtOne' say 4 times. The JTextField should display 1111. My problem is that the button is unresponsive to the line of code:
addActionListener(listener)
How do you get JButtons to print integers in a JTextField? I have gotten this to work before, but have since failed to get it to work again after adding in a more user friendly look with this line of code:
private static final String[][] STANDARD_BTN_TEXTS =
{
{"1", "2", "3"},
{"4", "5", "6"},
{"7", "8", "9"},
{ "0" }
Can someone point me in the right direction? Any help would be much appreciated!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractButton;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JPasswordField;
public class TerminalATM extends JFrame
{
private JPanel panel;
public final JPasswordField passwordField = new JPasswordField(2);
private static final String[][] STANDARD_BTN_TEXTS =
{
{"1", "2", "3"},
{"4", "5", "6"},
{"7", "8", "9"},
{ "0" }
};
private static final int GAP = 5;
private static final Font BTN_FONT = new Font(Font.DIALOG, Font.BOLD, 20);
public JButton jbtOne = new JButton(STANDARD_BTN_TEXTS[0][0]);
private JTextField jtfNumber1 = new JTextField(8);//Define Number Field
public TerminalATM()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
JPanel standardPanel = createBtnPanel(STANDARD_BTN_TEXTS, "KeyPad");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(0, 1));
buttonPanel.add(jtfNumber1, BorderLayout.NORTH);
buttonPanel.add(standardPanel, BorderLayout.SOUTH);
BtnListener listener = new BtnListener();
jbtOne.addActionListener(listener);
TextFieldHandler handler = new TextFieldHandler();
passwordField.addActionListener(handler);
add(buttonPanel, BorderLayout.LINE_START);
setSize(450, 500);
setVisible(true);
}
//Create Unique Rows of Buttons
private JPanel createBtnPanel(String[][] texts, String title) {
JPanel btnPanel = new JPanel();
int rows = texts.length;
int cols = texts[0].length;
btnPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
for (int row = 0; row < texts.length; row++) {
for (int col = 0; col < texts[row].length; col++) {
JButton btn = new JButton(texts[row][col]);
btn.setFont(BTN_FONT);
btnPanel.add(btn);
}
}
btnPanel.setBorder(BorderFactory.createTitledBorder(title));
return btnPanel;
}
private class TextFieldHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
String string = "";
if(event.getSource()==passwordField)
string = String.format("textField1: %s", event.getActionCommand());
}
}
/**** Create Button Listener and Action Listener ****/
class BtnListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
/* This is where we would set each button to the action event */
/* Only Button one for brevity */
int int1=0;
if(e.getSource().equals(jbtOne))
{
int1 = 1;
passwordField.setText(String.valueOf(int1));
}
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new TerminalATM();
}
});
}
}//EndTerminalATM
It looks to me that you are not adding jbtOne to the visible panel. Your createBtnPanel method creates its own buttons and adds them to the panel without any action listeners.
Try changing the following lines of the inner loop of createBtnPanel:
for (int row = 0; row < texts.length; row++) {
for (int col = 0; col < texts[row].length; col++) {
final String text = texts[row][col];
final JButton btn = new JButton(text);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
passwordField.setText(text);
}
});
btn.setFont(BTN_FONT);
btnPanel.add(btn);
}
}
Let me know if you don't understand what this does or have any problems with it.
This code can also be significantly simplified if you are using Java 8 but I'll assume you aren't to keep my answer straightforward.
In the following code I got the button listener to respond and output the text of the clicked button to show in the text field.
All changes are documented starting with /****, to explain what I did.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package logging;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TerminalATM extends JFrame
{
private JPanel panel;
public final JPasswordField passwordField = new JPasswordField(2);
private static final String[][] STANDARD_BTN_TEXTS =
{
{"1", "2", "3"},
{"4", "5", "6"},
{"7", "8", "9"},
{ "0" }
};
private static final int GAP = 5;
private static final Font BTN_FONT = new Font(Font.DIALOG, Font.BOLD, 20);
/**** what is the purpose of this JButton ? */
public JButton jbtOne = new JButton(STANDARD_BTN_TEXTS[0][0]);
private JTextField jtfNumber1 = new JTextField(8);//Define Number Field
public TerminalATM()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
JPanel standardPanel = createBtnPanel(STANDARD_BTN_TEXTS, "KeyPad");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(0, 1));
buttonPanel.add(jtfNumber1, BorderLayout.NORTH);
buttonPanel.add(standardPanel, BorderLayout.SOUTH);
/**** The action listener should go on the button which is pressed
see createBtnPanel */
// BtnListener listener = new BtnListener();
// jbtOne.addActionListener(listener);
/**** what is the purpose of this JPasswordField ?
it is not being added to any JPanel */
TextFieldHandler handler = new TextFieldHandler();
passwordField.addActionListener(handler);
add(buttonPanel, BorderLayout.LINE_START);
setSize(450, 500);
setVisible(true);
}
//Create Unique Rows of Buttons
private JPanel createBtnPanel(String[][] texts, String title) {
JPanel btnPanel = new JPanel();
int rows = texts.length;
int cols = texts[0].length;
btnPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
/**** create the listener */
BtnListener listener = new BtnListener();
for (String[] text : texts) {
for (String element : text) {
JButton btn = new JButton(element);
btn.setFont(BTN_FONT);
/**** add the listener to each button*/
btn.addActionListener(listener);
btnPanel.add(btn);
}
}
btnPanel.setBorder(BorderFactory.createTitledBorder(title));
return btnPanel;
}
private class TextFieldHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
String string = "";
if(event.getSource()==passwordField) {
string = String.format("textField1: %s", event.getActionCommand());
}
}
}
/**** Create Button Listener and Action Listener ****/
class BtnListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
/* This is where we would set each button to the action event */
/* Only Button one for brevity */
/**** what is the purpose of it ? int int1=0; */
/**** the event is generated by the button created in
createBtnPanel so e.getSource() can not be equal to
jbtOne. It should be an instance of JButton */
if(e.getSource() instanceof JButton)
{
/**** get the JButton clicked */
JButton button = (JButton) e.getSource() ;
/**** display its text on the text field */
jtfNumber1.setText(button.getText());
}
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
/**** new MultiplePanels(); is un defined */
new TerminalATM();
}
});
}
}//EndTerminalATM
I need to better understand what is the functionality you want to achieve with the password field and action listener, so I can try to help you further, if needed. (0:
Your listeners are using passwordField however it seems you have added a text field to your panel, either use the passwordField or jtfNumber1.

Categories