jtable selectionlistener doesn't work - java

I have write a little program with a table in it, i've tried and read so many documentation and anwers but i really don't understand what am i doing wrong, because the 4th column is still editable and no event is triggered when i select the rows...
Main
public class Main extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
private JLabel banner;
private String[] tecnici;
private String[] columnNames;
private Object[][] data;
private JTable table;
Map<String,List<Cliente>> clientiList;
private Container pane = getContentPane();
GroupLayout gl = new GroupLayout(pane);
Main(){
init();
}
private void init(){
ImageIcon webIcon = new ImageIcon(Constants.WORK_GUI_LOGO);
setIconImage(webIcon.getImage());
setTitle(Constants.WORK_GUI_TITLE);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
banner=new JLabel("", webIcon, JLabel.CENTER);
MenuBar menu=new MenuBar();
setJMenuBar(menu.getMenuBar());
System.out.println("Leggo i tecnici dal db");
tecnici=new String[] {"Tarzan","Cita","Jane"};
clientiList=new HashMap();
for(String tec:tecnici){
List<Cliente> l=new ArrayList<>();
Cliente c=new Cliente();
c.setConsultivoIncassi(1000);
c.setNome("Clnl ross");
c.setPreventivoIncassi(1000);
l.add(c);
c=new Cliente();
c.setConsultivoIncassi(2000);
c.setNome("Clnl ross");
c.setPreventivoIncassi(2000);
l.add(c);
clientiList.put(tec, l);
}
data=createTableFromMap(clientiList);
columnNames=new String[]{"Tecs","Customer","count","credit"};
table=new JTable(data, columnNames){
public boolean isCellEditable(int row, int col) {
//where i want to make editable only the 4th col
return col==4;
}
};
table.getSelectionModel().addListSelectionListener(new TableSelectionListener());
createWindowLayout(
banner,
new JLabel("Tecnici"),
new JCheckBox(tecnici[0]),
new JCheckBox(tecnici[1]),
new JCheckBox(tecnici[2]),
new JTable(data, columnNames));
}
public void createWindowLayout(JComponent... arg) {
pane = getContentPane();
gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addGroup(gl.createSequentialGroup()
.addComponent(arg[1])
.addGroup(gl.createParallelGroup(Alignment.LEADING)
.addComponent(arg[2])
.addComponent(arg[3])
.addComponent(arg[4])
)
)
.addComponent(arg[5])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGroup(gl.createParallelGroup()
.addComponent(arg[1])
.addComponent(arg[2]))
.addComponent(arg[3])
.addComponent(arg[4])
.addComponent(arg[5])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Main ex = new Main();
ex.setVisible(true);
});
}
private Object[][] createTableFromMap(Map<String,List<Cliente>> clienti ){
Iterator it= clienti.entrySet().iterator();
Object[][] tabella=new Object[clienti.size()][4];
int counter=0;
while(it.hasNext()){
Map.Entry entry=(Map.Entry) it.next();
for(Cliente c:(List<Cliente>)entry.getValue()){
tabella[counter]=new Object[]{entry.getKey(),
c.getNome(),
c.getPreventivoIncassi(),
c.getConsultivoIncassi()};
}
counter++;
}
return tabella;
}
class TableSelectionListener implements ListSelectionListener{
#Override
public void valueChanged(ListSelectionEvent arg0) {
String selectedData = null;
int[] selectedRow = table.getSelectedRows();
int[] selectedColumns = table.getSelectedColumns();
for (int i = 0; i < selectedRow.length; i++) {
for (int j = 0; j < selectedColumns.length; j++) {
selectedData = (String) table.getValueAt(selectedRow[i], selectedColumns[j]);
}
}
System.out.println("Selected: " + selectedData);
}
}
}

return col==4;
Did you ever do any basic debugging to see that the value of the "col" variable is? The first thing you should do when you have a problem is used System.out.println(...) to display the value so you can determine if your if condition is correct.
If you did, you would have noticed two things:
You don't get any output because the code is never executed.
Even is it did execute it would not work because your table only has 4 columns and Java uses 0 based offsets should you should be using "3" for the 4th column.
The reason the code is never executed is because you have two table. The first one you create with the overridden isCellEditable() method. But you never add that table to the GUI so that is dead code. Then you create a second table that you add to the GUI:
new JCheckBox(tecnici[2]),
new JTable(data, columnNames));
So get rid of the above statement and just use:
new JCheckBox(tecnici[2]),
//new JTable(data, columnNames));
table);
Since the table variable is the table with the custom method.

Look carefully at your code and comment here:
public boolean isCellEditable(int row, int col) {
//where i want to make editable only the 4th row
return col==4;
}
The comments don't match the code do they? Your method is checking col when it should be checking row, no? e.g.:
public boolean isCellEditable(int row, int col) {
//where i want to make editable only the 4th row
return row == 4; // ****** note change ******
}
MCVE'ized code:
import java.awt.Container;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
import javax.swing.event.*;
public class Main extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JLabel banner;
private String[] tecnici;
private String[] columnNames;
private Object[][] data;
private JTable table;
Map<String,List<Cliente>> clientiList;
private Container pane = getContentPane();
GroupLayout gl = new GroupLayout(pane);
Main(){
init();
}
private void init(){
ImageIcon webIcon = new ImageIcon(Constants.WORK_GUI_LOGO);
setIconImage(webIcon.getImage());
setTitle(Constants.WORK_GUI_TITLE);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
banner=new JLabel("", webIcon, JLabel.CENTER);
MenuBar menu=new MenuBar();
setJMenuBar(menu.getMenuBar());
System.out.println("Leggo i tecnici dal db");
tecnici=new String[] {"Tarzan","Cita","Jane"};
clientiList=new HashMap<>();
for(String tec:tecnici){
List<Cliente> l=new ArrayList<>();
Cliente c=new Cliente();
c.setConsultivoIncassi(1000);
c.setNome("Clnl ross");
c.setPreventivoIncassi(1000);
l.add(c);
c=new Cliente();
c.setConsultivoIncassi(2000);
c.setNome("Clnl ross");
c.setPreventivoIncassi(2000);
l.add(c);
clientiList.put(tec, l);
}
data=createTableFromMap(clientiList);
columnNames=new String[]{"Tecs","Customer","count","credit"};
table=new JTable(data, columnNames){
public boolean isCellEditable(int row, int col) {
//where i want to make editable only the 4th row
return col==4;
}
};
table.getSelectionModel().addListSelectionListener(new TableSelectionListener());
createWindowLayout(
banner,
new JLabel("Tecnici"),
new JCheckBox(tecnici[0]),
new JCheckBox(tecnici[1]),
new JCheckBox(tecnici[2]),
new JTable(data, columnNames));
}
public void createWindowLayout(JComponent... arg) {
pane = getContentPane();
gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addGroup(gl.createSequentialGroup()
.addComponent(arg[1])
.addGroup(gl.createParallelGroup(Alignment.LEADING)
.addComponent(arg[2])
.addComponent(arg[3])
.addComponent(arg[4])
)
)
.addComponent(arg[5])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGroup(gl.createParallelGroup()
.addComponent(arg[1])
.addComponent(arg[2]))
.addComponent(arg[3])
.addComponent(arg[4])
.addComponent(arg[5])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Main ex = new Main();
ex.setVisible(true);
});
}
private Object[][] createTableFromMap(Map<String,List<Cliente>> clienti ){
Iterator it= clienti.entrySet().iterator();
Object[][] tabella=new Object[clienti.size()][4];
int counter=0;
while(it.hasNext()){
Map.Entry entry=(Map.Entry) it.next();
for(Cliente c:(List<Cliente>)entry.getValue()){
tabella[counter]=new Object[]{entry.getKey(),
c.getNome(),
c.getPreventivoIncassi(),
c.getConsultivoIncassi()};
}
counter++;
}
return tabella;
}
class TableSelectionListener implements ListSelectionListener{
#Override
public void valueChanged(ListSelectionEvent arg0) {
String selectedData = null;
int[] selectedRow = table.getSelectedRows();
int[] selectedColumns = table.getSelectedColumns();
for (int i = 0; i < selectedRow.length; i++) {
for (int j = 0; j < selectedColumns.length; j++) {
selectedData = (String) table.getValueAt(selectedRow[i], selectedColumns[j]);
}
}
System.out.println("Selected: " + selectedData);
}
}
private static class Cliente {
private String nome;
private int preventivoIncassi;
private int consultivoIncassi;
public String getNome() {
return nome;
}
public void setPreventivoIncassi(int preventivoIncassi) {
this.preventivoIncassi = preventivoIncassi;
}
public void setNome(String nome) {
this.nome = nome;
}
public void setConsultivoIncassi(int consultivoIncassi) {
this.consultivoIncassi = consultivoIncassi;
}
public int getConsultivoIncassi() {
return consultivoIncassi;
}
public int getPreventivoIncassi() {
return preventivoIncassi;
}
}
private static class Constants {
public static final String WORK_GUI_LOGO = null;
public static final String WORK_GUI_TITLE = null;
}
private static class MenuBar {
public JMenuBar getMenuBar() {
// TODO Auto-generated method stub
return null;
}
}
}

Related

Java ArrayList returning 0 value

I'm trying to build an application on java with swing that the user need to enter some product and store them in an arraylist and show the list of products on table (JTable) in another Jframe , the problem i face that when i'm adding the product and click on button of liste the table does not contain the products even the Arraylist size return 0
Class Product
package Inventory;
public class Produit {
private int code;
private int StockInitial;
private int StockEntree;
private int StockSortie;
private int StockReel;
public Produit(int code, int StockInitial, int StockEntree, int StockSortie) {
this.code = code;
this.StockInitial = StockInitial;
this.StockEntree = StockEntree;
this.StockSortie = StockSortie;
this.StockReel = (this.StockInitial+this.StockEntree)-this.StockSortie;
}
public void AjouterProduit(int code, int StockInitial, int StockEntree, int StockSortie) {
this.code = code;
this.StockInitial = StockInitial;
this.StockEntree = StockEntree;
this.StockSortie = StockSortie;
this.StockReel = (this.StockInitial+this.StockEntree)-this.StockSortie;
}
public Produit() {
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public int getStockInitial() {
return StockInitial;
}
public void setStockInitial(int StockInitial) {
this.StockInitial = StockInitial;
}
public int getStockEntree() {
return StockEntree;
}
public void setStockEntree(int StockEntree) {
this.StockEntree = StockEntree;
}
public int getStockSortie() {
return StockSortie;
}
public void setStockSortie(int StockSortie) {
this.StockSortie = StockSortie;
}
public int getStockReel() {
return this.StockReel;
}
public void setStockReel(int StockReel) {
this.StockReel = StockReel;
}
}
Class Inventory the jframe that user able to enter details of product
package Inventory;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.*;
public class Inventory extends JFrame implements ActionListener {
public ArrayList<Produit> listProduit = new ArrayList<Produit>();
JLabel l1 = new JLabel("Code : ");
JLabel l2 = new JLabel("Stock initial : ");
JLabel l3 = new JLabel("Stock entree : ");
JLabel l4 = new JLabel("Stock sortie : ");
JTextField t1 = new JTextField(20);
JTextField t2 = new JTextField(20);
JTextField t3 = new JTextField(20);
JTextField t4 = new JTextField(20);
JButton b1 = new JButton("Suivant");
JButton b2 = new JButton("liste");
JFrame frame = new JFrame("Inventory");
public Inventory(){
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.getContentPane().add(l1);
frame.getContentPane().add(t1);
frame.getContentPane().add(l2);
frame.getContentPane().add(t2);
frame.getContentPane().add(l3);
frame.getContentPane().add(t3);
frame.getContentPane().add(l4);
frame.getContentPane().add(t4);
frame.getContentPane().add(b1);
frame.getContentPane().add(b2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b1.addActionListener(this);
b2.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==b1){
int code = Integer.parseInt(t1.getText());
int StockInitial = Integer.parseInt(t2.getText());
int StockEntree = Integer.parseInt(t3.getText());
int StockSortie = Integer.parseInt(t4.getText());
Produit p = new Produit(code,StockInitial,StockEntree,StockSortie);
listProduit.add(p);
}
if(e.getSource()==b2) {
new Liste().frame.setVisible(true);
}
}
public ArrayList<Produit> getList() {
return listProduit;
}
public static void main(String[] args) {
new Inventory().frame.setVisible(true);
}
}
Class Inventory the jframe that show to the user the details of product
package Inventory;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
public class Liste extends JFrame {
JFrame frame = new JFrame("Inventory");
String head[] = {"Code","Stock Intial","Stock Entree","Stock Sortie","Sotck Reel"};
String[][] Rows = {};
DefaultTableModel model = new DefaultTableModel(Rows,head);
Inventory n;
JTable table = new JTable(model);
JScrollPane sp = new JScrollPane(table);
Container con = null;
public Object[] objProduit;
public void addRowToJTable()
{
}
public Liste(){
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setRowCount(0);
for(int i=0;i<n.listProduit.size();i++){
Object[] obj = {n.listProduit.get(i).getCode(),n.listProduit.get(i).getStockInitial(),n.listProduit.get(i).getStockEntree(),n.listProduit.get(i).getStockSortie(),n.listProduit.get(i).getStockReel()};
model.addRow(obj);
}
//return 0
System.out.println(n.listProduit.size());
frame.getContentPane().add(table);
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.add(sp);
}
}
If you want your Liste class to access the listProduit of the Inventory class you have several possibilities.
In my preferred order:
1. pass the listProduit to the Liste constructor
In the actionPerformed() method, create the Liste instance as follows:
new Liste(listProduit).frame.setVisible(true);
To do this you need to change the Liste constructor as follows:
private List<Produit> listProduit;
public Liste(List<Produit> listProduit) {
this.listProduit = listProduit;
model.setRowCount(0);
for (int i = 0; i < listProduit.size(); i++) {
Produit p = listProduit.get(i);
Object[] obj = { p.getCode(), p.getStockInitial(), p.getStockEntree(), p.getStockSortie(), p.getStockReel() };
model.addRow(obj);
}
System.out.println(n.listProduit.size());
frame.getContentPane().add(table);
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.add(sp);
}
The field Inventory n in the Liste class is not needed.
2. pass the Inventory instance to the Liste constructor
In the actionPerformed() method, create the Liste instance as follows:
new Liste(this).frame.setVisible(true);
To do this you need to change the Liste constructor as follows:
public Liste(Inventory inventory) {
this.n = inventory;
model.setRowCount(0);
for (int i = 0; i < n.listProduit.size(); i++) {
Produit p = n.listProduit.get(i);
Object[] obj = { p.getCode(), p.getStockInitial(), p.getStockEntree(), p.getStockSortie(), p.getStockReel() };
model.addRow(obj);
}
System.out.println(n.listProduit.size());
frame.getContentPane().add(table);
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.add(sp);
}
3. make the listProduit a static field
This is only for completeness. You should create as few static fields as possible - static fields are a lazy "solution" that can create big problems if your program grows, and to change from this approach to something better (preferably the first approach) grows harder the more code you have that relies on static fields.
In the class Inventory change the declaration of the field listProduit as follows:
public static List<Produit> listProduit = new ArrayList<Produit>();
You can then change the constructor of Liste as follows:
public Liste(Inventory inventory) {
model.setRowCount(0);
for (int i = 0; i < Inventory.listProduit.size(); i++) {
Produit p = Inventory.listProduit.get(i);
Object[] obj = { p.getCode(), p.getStockInitial(), p.getStockEntree(), p.getStockSortie(), p.getStockReel() };
model.addRow(obj);
}
System.out.println(n.listProduit.size());
frame.getContentPane().add(table);
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.add(sp);
}
You can further improve the constructor by using either an enhanced for loop or by using the forEach() method of the List interface.
With an enhanced for loop:
private List<Produit> listProduit;
public Liste(List<Produit> listProduit) {
this.listProduit = listProduit;
model.setRowCount(0);
for (Produit p: listProduit) {
Object[] obj = { p.getCode(), p.getStockInitial(), p.getStockEntree(), p.getStockSortie(), p.getStockReel() };
model.addRow(obj);
}
System.out.println(n.listProduit.size());
frame.getContentPane().add(table);
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.add(sp);
}
With forEach():
private List<Produit> listProduit;
public Liste(List<Produit> listProduit) {
this.listProduit = listProduit;
model.setRowCount(0);
listProduit.forEach(p -> {
Object[] obj = { p.getCode(), p.getStockInitial(), p.getStockEntree(), p.getStockSortie(), p.getStockReel() };
model.addRow(obj);
});
System.out.println(n.listProduit.size());
frame.getContentPane().add(table);
frame.setLayout(new FlowLayout());
frame.setSize(400,300);
frame.add(sp);
}

How do I add an ActionListener to a JCheckBox?

Problem
So my program takes in a .csv file and loads the data and displays it. When data is loaded in, it creates a new JCheckBox for every column header there is in the data. How do I add an ActionListener such that when the user ticks/unticks any of the boxes, it should do a certain function?
When data is loaded in, it updates the JPanel by the code:
public void updateChecklistPanel(){
checklistPanel.removeAll();
checklistPanel.setLayout(new GridLayout(currentData.getColumnNames().length, 1, 10, 0));
for (String columnName : currentData.getColumnNames()){
JCheckBox checkBox = new JCheckBox();
checkBox.setText(columnName);
checklistPanel.add(checkBox);
}
checklistPanel.revalidate();
checklistPanel.repaint();
}
I also have the following at the bottom:
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == newDataFrameItem){
newFile();
System.out.println("New DataFrame Loaded in");
}
if (e.getSource() == loadDataFrameItem){
loadFile();
System.out.println(".csv Data loaded into DataFrame.");
}
if (e.getSource() == saveDataFrameItem){
System.out.println("Saved the data to a .csv file");
}
}
What I'm trying to do is that when a checkbox is unticked, it should hide a column in the JTable and when ticked, it should redisplay the column.
Current Solution
The solution that I have come up with is to make a variable allColumnHeaders that is an ArrayList of Strings. I then also have a variable shownColumnHeaders that is an ArrayList of Booleans. When the user wants to show/hide a column, the showColumn(String columnName) and hideColumn(String columnName) function finds the index of the column Name in allColumnHeaders and sets the Boolean value of the index in shownColumnHeaders to either true/false.
It the proceeds to create a new table model where the columns are only added if the Boolean value for that column is true. It will then set the model for the table to the new table model.
The code for the following is show below:
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class MRE extends JPanel {
private static JTable table;
private static ArrayList<String> allColumnHeaders = new ArrayList<>();
private static ArrayList<Boolean> shownColumnHeaders = new ArrayList<>();
private static void createAndShowGUI()
{
table = new JTable(5, 7);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
JPanel buttons = new JPanel( new GridLayout(0, 1) );
for (int i = 0; i < table.getColumnCount(); i++) {
String column = table.getColumnName(i);
allColumnHeaders.add(column);
JCheckBox checkBox = new JCheckBox(column);
checkBox.addActionListener(event -> {
JCheckBox cb = (JCheckBox) event.getSource();
if (cb.isSelected()) {
System.out.println(checkBox.getText() + " is now being displayed");
showColumn(checkBox.getText());
} else {
System.out.println(checkBox.getText() + " is now being hidden");
hideColumn(checkBox.getText());
}
table.setModel(createTableModel());
});
checkBox.setSelected( true );
buttons.add( checkBox );
shownColumnHeaders.add(true);
}
JPanel wrapper = new JPanel();
wrapper.add( buttons );
JFrame frame = new JFrame("MRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(wrapper, BorderLayout.LINE_END);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static DefaultTableModel createTableModel(){
DefaultTableModel tableModel = new DefaultTableModel(0, 0);
String[] columnValues = new String[1];
for (int i = 0; i < shownColumnHeaders.size(); i++){
if (shownColumnHeaders.get(i)){
tableModel.addColumn(allColumnHeaders.get(i), columnValues);
}
}
return tableModel;
}
public static void showColumn(String columnName){
for (int i = 0; i < allColumnHeaders.size(); i++) {
if (allColumnHeaders.get(i).equals(columnName)){
shownColumnHeaders.set(i, true);
}
}
}
public static void hideColumn(String columnName){
for (int i = 0; i < allColumnHeaders.size(); i++) {
if (allColumnHeaders.get(i).equals(columnName)){
shownColumnHeaders.set(i, false);
}
}
}
public static void main(String[] args) throws Exception
{
SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
}
Introduction
It took me a while, but I came up with the following JTable GUI. Here's the starting display.
Here's the GUI after I remove the item description.
Here's the GUI after I remove the item price.
Here's the GUI after I add the columns back.
Explanation
I created an Item class to hold one item.
I created an Inventory class to hold a List of Item instances and a String array of the column headers.
I created the JFrame and two JPanels. One JPanel holds the JTable and the other holds the JCheckBoxes. I used Swing layout managers to create the JPanels.
So far, so basic. Creating the JTable took a bit of effort. I wanted to display the item price as currency, but that wasn't important for this example GUI.
I created an ActionListener to add and remove columns from the JTable. I had to experiment a bit. The TableColumnModel addColumn method appends the column to the table.
I had to create a DisplayTableColumn class to hold a TableColumn and a boolean that tells me whether or not to display the TableColumn. I wound up removing all the columns from the JTable and adding all the columns back to the JTable so that I could maintain the column sequence. I probably ran 100 tests before I could get this code to work.
Code
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class JCheckBoxTableGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JCheckBoxTableGUI());
}
private final Inventory inventory;
private final InventoryTableModel tableModel;
private JFrame frame;
private JTable table;
public JCheckBoxTableGUI() {
this.tableModel = new InventoryTableModel();
this.inventory = new Inventory();
String[] columns = inventory.getTableHeader();
for (String column : columns) {
tableModel.addColumn(column);
}
List<Item> items = inventory.getInventory();
for (Item item : items) {
Object[] object = new Object[5];
object[0] = item.getItemNumber();
object[1] = item.getItemName();
object[2] = item.getItemDescription();
object[3] = item.getItemQuantity();
object[4] = item.getItemPrice();
tableModel.addRow(object);
}
}
#Override
public void run() {
frame = new JFrame("JCheckBox Table GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTablePanel(), BorderLayout.CENTER);
frame.add(createSelectionPanel(), BorderLayout.AFTER_LINE_ENDS);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createTablePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
table = new JTable(tableModel);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getColumnModel().getColumn(0).setPreferredWidth(100);
table.getColumnModel().getColumn(1).setPreferredWidth(150);
table.getColumnModel().getColumn(2).setPreferredWidth(150);
table.getColumnModel().getColumn(3).setPreferredWidth(100);
table.getColumnModel().getColumn(4).setPreferredWidth(100);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(620, 300));
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createSelectionPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel innerPanel = new JPanel(new GridLayout(0, 1, 5, 5));
ColumnListener listener = new ColumnListener(this);
String[] columns = inventory.getTableHeader();
for (String column : columns) {
JCheckBox checkBox = new JCheckBox("Display " + column);
checkBox.addActionListener(listener);
checkBox.setActionCommand(column);
checkBox.setSelected(true);
innerPanel.add(checkBox);
}
panel.add(innerPanel);
return panel;
}
public JTable getTable() {
return table;
}
public JFrame getFrame() {
return frame;
}
public class ColumnListener implements ActionListener {
private final JCheckBoxTableGUI frame;
private final List<DisplayTableColumn> displayColumns;
public ColumnListener(JCheckBoxTableGUI frame) {
this.frame = frame;
this.displayColumns = new ArrayList<>();
TableColumnModel tcm = frame.getTable().getColumnModel();
for (int index = 0; index < tcm.getColumnCount(); index++) {
TableColumn tc = tcm.getColumn(index);
displayColumns.add(new DisplayTableColumn(tc, true));
}
}
#Override
public void actionPerformed(ActionEvent event) {
JCheckBox checkBox = (JCheckBox) event.getSource();
String column = event.getActionCommand();
TableColumnModel tcm = frame.getTable().getColumnModel();
for (int index = 0; index < displayColumns.size(); index++) {
DisplayTableColumn dtc = displayColumns.get(index);
if (dtc.isShowTableColumn()) {
tcm.removeColumn(dtc.getTableColumn());
}
}
int columnIndex = getColumnIndex(column);
displayColumns.get(columnIndex).setShowTableColumn(
checkBox.isSelected());
for (int index = 0; index < displayColumns.size(); index++) {
DisplayTableColumn dtc = displayColumns.get(index);
if (dtc.isShowTableColumn()) {
tcm.addColumn(dtc.getTableColumn());
}
}
frame.getFrame().pack();
}
private int getColumnIndex(String column) {
for (int index = 0; index < displayColumns.size(); index++) {
DisplayTableColumn dtc = displayColumns.get(index);
if (column.equals(dtc.getTableColumn().getHeaderValue())) {
return index;
}
}
return -1;
}
}
public class DisplayTableColumn {
private boolean showTableColumn;
private final TableColumn tableColumn;
public DisplayTableColumn(TableColumn tableColumn, boolean showTableColumn) {
this.tableColumn = tableColumn;
this.showTableColumn = showTableColumn;
}
public boolean isShowTableColumn() {
return showTableColumn;
}
public void setShowTableColumn(boolean showTableColumn) {
this.showTableColumn = showTableColumn;
}
public TableColumn getTableColumn() {
return tableColumn;
}
}
public class InventoryTableModel extends DefaultTableModel {
private static final long serialVersionUID = 1L;
#Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex <= 2) {
return String.class;
} else if (columnIndex == 3) {
return Integer.class;
} else {
return Integer.class;
}
}
}
public class Inventory {
private final List<Item> inventory;
private final String[] tableHeader;
public Inventory() {
this.tableHeader = new String[] { "Item Number", "Item Name",
"Item Description", "Item Quantity",
"Item Price" };
this.inventory = new ArrayList<>();
inventory.add(new Item("X101111", "Samsung Camera", " ", 20, 69.99));
inventory.add(new Item("X101112", "Samsung Monitor", " ", 10, 279.99));
inventory.add(new Item("X101113", "Samsung Smartphone", " ", 110, 599.99));
inventory.add(new Item("X101114", "Apple Watch", " ", 20, 1259.99));
inventory.add(new Item("X101115", "Sony Playstation 5", " ", 0, 399.99));
}
public String[] getTableHeader() {
return tableHeader;
}
public List<Item> getInventory() {
return inventory;
}
}
public class Item {
private int itemPrice;
private int itemQuantity;
private final String itemNumber;
private final String itemName;
private final String itemDescription;
public Item(String itemNumber, String itemName,
String itemDescription, int itemQuantity, double itemPrice) {
this.itemNumber = itemNumber;
this.itemName = itemName;
this.itemDescription = itemDescription;
this.itemQuantity = itemQuantity;
setItemPrice(itemPrice);
}
public int getItemPrice() {
return itemPrice;
}
public void setItemPrice(double itemPrice) {
this.itemPrice = (int) Math.round(itemPrice * 100.0);
}
public int getItemQuantity() {
return itemQuantity;
}
public void setItemQuantity(int itemQuantity) {
this.itemQuantity = itemQuantity;
}
public String getItemNumber() {
return itemNumber;
}
public String getItemName() {
return itemName;
}
public String getItemDescription() {
return itemDescription;
}
}
}
This only demonstrates how to create a basic MRE:
the csv file is irrelevant.
data in the model is irrelevant.
your loadFile, newFile and saveFile buttons are irrelevant.
the TableModel is irrelevant
Your question is about adding an ActionListener to dynamically created checkboxes based on the columns of the table.
So all you need is a table with some columns and the resulting checkboxes.
import java.awt.*;
import javax.swing.*;
public class MRE extends JPanel
{
private static void createAndShowGUI()
{
JTable table = new JTable(5, 7);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
JPanel buttons = new JPanel( new GridLayout(0, 1) );
for (int i = 0; i < table.getColumnCount(); i++)
{
String column = table.getColumnName(i);
JCheckBox checkBox = new JCheckBox("Display " + column);
checkBox.setSelected( true );
buttons.add( checkBox );
}
JPanel wrapper = new JPanel();
wrapper.add( buttons );
JFrame frame = new JFrame("MRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(wrapper, BorderLayout.LINE_END);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
}
If you can modify this to demonstrate how to use your "reusable class" to manage column visibility, then I will update the above code to use my reusable class with 4 additional lines of code.
Edit:
Suggested improvements to your code:
Make the code reusable and self contained
Don't use static methods
Don't change the data.
Your original question was:
How do I add an ActionListener to a JCheckBox?
So to do that you need a class that:
implements an ActionListener
is self contained to implement the functionality you require.
So the basic structure could be like the following:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SomeFunction implements ActionListener
{
private JTable table;
public SomeFunction(JTable table)
{
this.table = table;
}
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() instanceof AbstractButton)
{
String command = e.getActionCommand();
AbstractButton button = (AbstractButton)e.getSource();
if (button.isSelected())
doSelected( command );
else
doUnselected( command );
}
}
private void doSelected(String command)
{
System.out.println(command + " selected");
}
private void doUnselected(String command)
{
System.out.println(command + " unselected");
}
private static void createAndShowGUI()
{
JTable table = new JTable(5, 7);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
JPanel buttons = new JPanel( new GridLayout(0, 1) );
SomeFunction listener = new SomeFunction( table ); // added
// TableColumnManager listener = new TableColumnManager(table, false);
// ColumnListener listener = new ColumnListener();
for (int i = 0; i < table.getColumnCount(); i++)
{
String column = table.getColumnName(i);
JCheckBox checkBox = new JCheckBox("Display " + column);
checkBox.setSelected( true );
checkBox.setActionCommand( column ); // added
checkBox.addActionListener( listener ); // added
buttons.add( checkBox );
}
JPanel wrapper = new JPanel();
wrapper.add( buttons );
JFrame frame = new JFrame("MRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(wrapper, BorderLayout.LINE_END);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
}
Whatever your function does it only needs to know about the table it should act upon.
So try to restructure your code into a reusable class.
If you want to use Gilberts code, then you need to restructure the ColumnListener class into a separate reusable self contained class.
Finally you can also try my reusable class. Check out Table Column Manager for the class to download.
Whatever reusable class you decide to use, you will only need to change a single line of code from the above example (once your functionality is contained in a reusable class).
Note the static methods would not be part of the final class. They are only there so simplify testing and posting of an MRE in a single class file.
Hope this helps with future design considerations.

How to count data in jtable and show on the bottom of my gui

I have such an api. It shows JTable with 3 columns. I want that when I insert price and quantity to the jtable result will be seen on the bottom of my jframe. For example I insert data like on the picture and then get the result (2*5)+(2*5)=20. My result will be 20. And this result will be seen on the bottom of the gui window.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class Demo extends JFrame implements ActionListener{
private static void createAndShowUI() {
JFrame frame = new JFrame("Customer Main");
frame.getContentPane().add(new FuGui(), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
class FuGui extends JPanel {
FuDisplayPanel displayPanel = new FuDisplayPanel();
FuButtonPanel buttonPanel = new FuButtonPanel();
FuInformationPanel informationPanel = new FuInformationPanel();
public FuGui() {
//JTextField textField;
//textField = new JTextField(20);
//textField.addActionListener(this);
JPanel bottomPanel = new JPanel();
bottomPanel.add(buttonPanel);
bottomPanel.add(Box.createHorizontalStrut(10));
bottomPanel.add(informationPanel);
setLayout(new BorderLayout());
add(displayPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.SOUTH);
buttonPanel.addInfoBtnAddActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name = informationPanel.getName();
String price = informationPanel.getPrice();
String quantity = informationPanel.getQuantity();
displayPanel.addRow(name, price, quantity);
}
});
}
}
class FuDisplayPanel extends JPanel {
private String[] COLUMNS = {"Name", "Price", "Quantity"};
private DefaultTableModel model = new DefaultTableModel(COLUMNS, 1);
private JTable table = new JTable(model);
public FuDisplayPanel() {
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
public void addRow(String name, String price, String quantity) {
Object[] row = new Object[3];
row[0] = name;
row[1] = price;
row[2] = quantity;
model.addRow(row);
}
}
class FuButtonPanel extends JPanel {
private JButton addInfoButton = new JButton("Add Information");
public FuButtonPanel() {
add(addInfoButton);
}
public void addInfoBtnAddActionListener(ActionListener listener) {
addInfoButton.addActionListener(listener);
}
}
class FuInformationPanel extends JPanel {
private JTextField nameField = new JTextField(10);
private JTextField priceField = new JTextField(10);
private JTextField quantityField = new JTextField(10);
public FuInformationPanel() {
add(new JLabel("Kwota:"));
add(nameField);
add(Box.createHorizontalStrut(10));
// add(new JLabel("Price:"));
// add(priceField);
//add(new JLabel("Quantity:"));
// add(quantityField);
}
public String getName() {
return nameField.getText();
}
public String getPrice() {
return priceField.getText();
}
public String getQuantity() {
return quantityField.getText();
}
}
update your addRow method in class FuDisplayPanel to return the total like this and
public int addRow(String name, String price, String quantity) {
Object[] row = new Object[3];
row[0] = name;
row[1] = price;
row[2] = quantity;
model.addRow(row);
int total = 0;
for (int count = 0; count < model.getRowCount(); count++){
price = model.getValueAt(count, 1).toString();
quantity = model.getValueAt(count, 2).toString();
if(price != null && !price.trim().equals("") && quantity != null && !quantity.trim().equals("")) {
total += Integer.parseInt(price) * Integer.parseInt(quantity);
}
}
return total;
}
public class FuButtonPanel extends JPanel {
private JButton addInfoButton = new JButton("Add Information");
public JLabel total = new JLabel("Total : ");
public FuButtonPanel() {
add(addInfoButton);
add(total);
}
public void addInfoBtnAddActionListener(ActionListener listener) {
addInfoButton.addActionListener(listener);
}
public void setTotal(int total) {
this.total.setText("Total : " + total);
}
}
and do this at FuGui.class
int total = displayPanel.addRow(name, price, quantity);
buttonPanel.setTotal(total);
Access the underlying data in the table via the model (Swing fundamental):
TableModel model = table.getModel();
Add a listener to the table model to do the automatic updates:
TableModelListener listener = new TableModelListener(tableChanged(TableModelEvent e) {
// update code here
}};
table.getModel().addTableModelListener(listener);

updating JTable date

For initialization:
Vector<Vector> rowdata = new Vector<Vector>();
Vector columnname = new Vector();
JTabel result = new JTable(rowdata, columnname);
JScrollPane sqlresult = new JScrollPane(result);
In the later part, I assign values in rowdata and columnname vector. How to show new values in JTable on GUI?
In addition..
result.repaint();
..and..
((DefaultTableModel)result.getModel()).fireTabelDataChanged()
..seem to do nothing.
1) use DefaultTableModel for JTable
2) define Column Class
3) add row(s) DefaultTableModel.addRow(myVector);
for example
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class DefaultTableModelDemo {
public static final String[] COLUMN_NAMES = {
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
};
private DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
private JTable table = new JTable(model);
private JPanel mainPanel = new JPanel(new BorderLayout());
private Random random = new Random();
public DefaultTableModelDemo() {
JButton addDataButton = new JButton("Add Data");
JPanel buttonPanel = new JPanel();
buttonPanel.add(addDataButton);
addDataButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
addDataActionPerformed();
}
});
model = new DefaultTableModel(COLUMN_NAMES, 0) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (isRowSelected(row) && isColumnSelected(column)) {
((JComponent) c).setBorder(new LineBorder(Color.red));
}
return c;
}
};
mainPanel.add(new JScrollPane(table), BorderLayout.CENTER);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
}
private void addDataActionPerformed() {
for (int i = 0; i < 5; i++) {
Object[] row = new Object[COLUMN_NAMES.length];
for (int j = 0; j < row.length; j++) {
row[j] = random.nextInt(5);
}
model.addRow(row);
}
}
public JComponent getComponent() {
return mainPanel;
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("DefaultTableModelDemo");
frame.getContentPane().add(new DefaultTableModelDemo().getComponent());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
rowdata and columnname are used for the initialization of JTable, after the component JTable exists you need to use JTable.getColumnModel() and JTable.getModel() to add columns or rows.
Or JTable.addColumn(TableColumn aColumn) if you only wants to add a column.
Look here if you want to know how to add a row following an example.

Custom data flavour for DnD rows in JTable

How can I register a custom data flavour, such that when I call
TransferHandler.TransferSupport.isDataFlavorSupported()
it returns true?
The flavour is initialised like so
private final DataFlavor localObjectFlavor = new ActivationDataFlavor(DataManagerTreeNode.class, DataFlavor.javaJVMLocalObjectMimeType, "DataManagerTreeNode flavour");
Many thanks
I saw only once times correct code for JTable and DnD, offical code by Oracle (former Sun)
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
public class FillViewportHeightDemo extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private DefaultListModel model = new DefaultListModel();
private int count = 0;
private JTable table;
private JCheckBoxMenuItem fillBox;
private DefaultTableModel tableModel;
private static String getNextString(int count) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < 5; i++) {
buf.append(String.valueOf(count));
buf.append(",");
}
buf.deleteCharAt(buf.length() - 1); // remove last newline
return buf.toString();
}
private static DefaultTableModel getDefaultTableModel() {
String[] cols = {"Foo", "Toto", "Kala", "Pippo", "Boing"};
return new DefaultTableModel(null, cols);
}
public FillViewportHeightDemo() {
super("Empty Table DnD Demo");
tableModel = getDefaultTableModel();
table = new JTable(tableModel);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setDropMode(DropMode.INSERT_ROWS);
table.setTransferHandler(new TransferHandler() {
private static final long serialVersionUID = 1L;
#Override
public boolean canImport(TransferSupport support) {
if (!support.isDrop()) { // for the demo, we'll only support drops (not clipboard paste)
return false;
}
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) { // we only import Strings
return false;
}
return true;
}
#Override
public boolean importData(TransferSupport support) { // if we can't handle the import, say so
if (!canImport(support)) {
return false;
}
JTable.DropLocation dl = (JTable.DropLocation) support.getDropLocation();// fetch the drop location
int row = dl.getRow();
String data; // fetch the data and bail if this fails
try {
data = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException e) {
return false;
} catch (IOException e) {
return false;
}
String[] rowData = data.split(",");
tableModel.insertRow(row, rowData);
Rectangle rect = table.getCellRect(row, 0, false);
if (rect != null) {
table.scrollRectToVisible(rect);
}
model.removeAllElements(); // demo stuff - remove for blog
model.insertElementAt(getNextString(count++), 0); // end demo stuff
return true;
}
});
JList dragFrom = new JList(model);
dragFrom.setFocusable(false);
dragFrom.setPrototypeCellValue(getNextString(100));
model.insertElementAt(getNextString(count++), 0);
dragFrom.setDragEnabled(true);
dragFrom.setBorder(BorderFactory.createLoweredBevelBorder());
dragFrom.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
if (SwingUtilities.isLeftMouseButton(me) && me.getClickCount() % 2 == 0) {
String text = (String) model.getElementAt(0);
String[] rowData = text.split(",");
tableModel.insertRow(table.getRowCount(), rowData);
model.removeAllElements();
model.insertElementAt(getNextString(count++), 0);
}
}
});
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
JPanel wrap = new JPanel();
wrap.add(new JLabel("Drag from here:"));
wrap.add(dragFrom);
p.add(Box.createHorizontalStrut(4));
p.add(Box.createGlue());
p.add(wrap);
p.add(Box.createGlue());
p.add(Box.createHorizontalStrut(4));
getContentPane().add(p, BorderLayout.NORTH);
JScrollPane sp = new JScrollPane(table);
getContentPane().add(sp, BorderLayout.CENTER);
fillBox = new JCheckBoxMenuItem("Fill Viewport Height");
fillBox.addActionListener(this);
JMenuBar mb = new JMenuBar();
JMenu options = new JMenu("Options");
mb.add(options);
setJMenuBar(mb);
JMenuItem clear = new JMenuItem("Reset");
clear.addActionListener(this);
options.add(clear);
options.add(fillBox);
getContentPane().setPreferredSize(new Dimension(260, 180));
}
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == fillBox) {
table.setFillsViewportHeight(fillBox.isSelected());
} else {
tableModel.setRowCount(0);
count = 0;
model.removeAllElements();
model.insertElementAt(getNextString(count++), 0);
}
}
private static void createAndShowGUI() {//Create and set up the window.
FillViewportHeightDemo test = new FillViewportHeightDemo();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.pack(); //Display the window.
test.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}

Categories