I can select and set focus to cells in a JTable by clicking it, now I want to change the value on the focused cell. In order to change the value of it, I have to double click! Is there any way to clear/change the value of that focused cell (by single-clicking)?
I have tried jTable1.setValueAt("", row, column);, this clears the value in the background(It's not updated in the GUI/Same old value appears in the cell).
Table structure:
jTable1.addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(final MouseEvent e) {
if (e.getClickCount()==1){
final JTable jTable=(JTable)e.getSource();
final int row = jTable.getSelectedRow();
final int column = jTable.getSelectedColumn();
jTable1.editCellAt(row,column);
jTable1.getEditorComponent().requestFocus();
final Double valueInCell = (Double)jTable.getValueAt(row, column);
System.out.println(valueInCell);
}
}
});
If all you desire is to clear or change a JTable cell that holds Strings, why not simply call JTable's setValueAt(Object o, int row, int column) method? To clear, pass in "", to set to something different, then pass in a different String.
For example, my minimal reproducible example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import java.util.Arrays;
import java.util.Vector;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
#SuppressWarnings("serial")
public class TableFoo extends JPanel {
private static final Vector<String> COLUMN_NAME_VECTOR = new Vector<String>(
Arrays.asList(new String[] { "A", "B", "C" }));
private static final int COLUMN_COUNT = COLUMN_NAME_VECTOR.size();
private JTable table = new JTable();
public TableFoo() {
table.setFillsViewportHeight(true);
fillTableData();
MyMouse myMouse = new MyMouse();
table.addMouseListener(myMouse);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
class MyMouse extends MouseAdapter {
#Override
public void mousePressed(final MouseEvent e) {
final int row = table.getSelectedRow();
final int column = table.getSelectedColumn();
table.setValueAt("", row, column);
}
}
public void fillTableData() {
Vector<Vector<String>> matrix = new Vector<Vector<String>>();
int rowCount = 8;
for (int i = 0; i < rowCount ; i++) {
Vector<String> row = new Vector<String>();
for (int j = 0; j < COLUMN_COUNT; j++) {
String rowText = String.format("row %d col %d", i, j);
row.add(rowText );
}
matrix.add(row);
}
DefaultTableModel model = new DefaultTableModel(matrix,
COLUMN_NAME_VECTOR);
table.setModel(model);
}
private static void createAndShowGui() {
TableFoo mainPanel = new TableFoo();
JFrame frame = new JFrame("TableFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
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.
I have following code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import javax.swing.table.DefaultTableModel;
public class NewClass1 extends JFrame {
private JTable table;
private JScrollPane scrollPane;
private DefaultTableModel defaultTableModel;
public NewClass1() {
setLocationByPlatform(true);
setLayout(new BorderLayout());
setPreferredSize(new Dimension(600, 400));
setTitle("Table Issues");
setDefaultCloseOperation(EXIT_ON_CLOSE);
createTableModel();
table = new JTable(defaultTableModel);
scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
}
private void createTableModel() {
Vector cols = new Vector();
cols.add("A");
Vector rows = new Vector();
for (int i = 0; i < 50; i++) {
Vector row = new Vector();
row.add((i + 1) + "");
rows.add(row);
}
defaultTableModel = new DefaultTableModel(rows, cols) {
Class[] types = new Class[]{
String.class
};
#Override
public Class getColumnClass(int columnIndex) {
return types[columnIndex];
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(new NimbusLookAndFeel());
} catch (Exception e) {
}
final NewClass1 nc = new NewClass1();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
nc.setVisible(true);
}
});
while (true) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int row = (int) (Math.random() * 50);
int move = (int) (Math.random() * 50);
nc.defaultTableModel.moveRow(row, row, move);
}
});
try{
Thread.sleep(1000);
}catch(Exception e){
}
}
}
}
Please run the above code and select row.
My problem is with row movement, row selection is not moving. It is staying at fixed position. Suppose I selected row with column value 25, selected row must be of column value 25 after row movements.
Please help me on this.
My real problem is, user will select row and clicks menu to perform action, meanwhile other threads may have moved rows, and performed action will be on other row than actual one.
The easiest way is to remember the selected row somewhere outside of the ListSelectionModel and adjust the selection whenever the TableModel changes. For example you could do this:
public class NewClass1 extends JFrame {
private JTable table;
private DefaultTableModel defaultTableModel;
private JScrollPane scrollPane;
private class SelectionHelper implements ListSelectionListener, TableModelListener {
private Object selectedRow;
#Override
public void valueChanged(ListSelectionEvent event) {
if (!event.getValueIsAdjusting()) return;
int selectedIndex = table.getSelectedRow();
if (selectedIndex >= 0) {
selectedRow = defaultTableModel.getDataVector().get(selectedIndex);
} else {
selectedRow = null;
}
}
#Override
public void tableChanged(TableModelEvent event) {
if (selectedRow == null) return;
int selectedIndex = defaultTableModel.getDataVector().indexOf(selectedRow);
table.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex);
}
}
public NewClass1() {
// ...
createTableModel();
table = new JTable(defaultTableModel);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
SelectionHelper helper = new SelectionHelper();
table.getModel().addTableModelListener(helper);
table.getSelectionModel().addListSelectionListener(helper);
// ...
}
// ...
}
Note however, that you should adjust this code for production use, for example in regards to thread safety or portability (using the table and defaultTableModel attributes in the inner class is bad style).
I'm working on jTable and I intend on deleting specific rows as part of the data manipulation to be conducted on the table. Essentially I've been able to successfully delete a row which the user would specify but I what I really want to do is to delete several rows based on boolean states or check boxes that are selected as part one of the four columns of the table.
I've attached a screenshot as to the current result of running the code and would like to be able to delete the rows based on the selected boolean states or check boxes.
Below is my code including my table model code which extends the AbstractTableModel:
package com.TableRowSelectProgramatically;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
#SuppressWarnings("serial")
public class JTableRowSelectProgramatically extends JPanel {
public MyTableModel MyTableModel;
public String Cell1 = "ABCD";
public JTableRowSelectProgramatically() {
initializePanel();
}
private void initializePanel() {
setLayout(null);
setPreferredSize(new Dimension(1250, 700));
// Table model
MyTableModel = new MyTableModel();
// Table
final JTable table = new JTable(MyTableModel);
table.setFillsViewportHeight(true);
// Row data
Object[] values = {Cell1, "EFGH", "IJKL", new Boolean(false)};
Object[] values2 = {"UVWX","QRST","MNOP", new Boolean(false)};
Object[] values3 = {"ABCD","YZAB","CDEF", new Boolean(false)};
final Object[] values4 = {"QWERTY","YTREWQ","QWERTY", new Boolean(false)};
// Insert row data
MyTableModel CustomTableModel = (MyTableModel) table.getModel();
CustomTableModel.insertData(values);
CustomTableModel.insertData(values2);
CustomTableModel.insertData(values3);
CustomTableModel.insertData(values);
CustomTableModel.insertData(values2);
CustomTableModel.insertData(values3);
CustomTableModel.insertData(values);
CustomTableModel.insertData(values2);
CustomTableModel.insertData(values3);
// Create edit menu label
JLabel labelEditMenu = new JLabel("EDIT MENU:\n");
// Create add row btn
JButton addRow = new JButton("Add Row");
// Attach listener for add row btn
addRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
MyTableModel.insertData(values4);
}
});
// Create delete row btn
JButton deleteRow = new JButton("Delete Row");
// Attach listener for delete btn
deleteRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
MyTableModel.removeRow(1);
}
});
// Create scroll pane
JScrollPane pane = new JScrollPane(table);
pane.setBounds(30, 30, 500, 500);
//
JTextField AgentIDTextField = new JTextField();
// Populate the JPanel
JPanel dataEntryPanel = new JPanel(new FlowLayout());
//dataEntryPanel.setBackground(Color.orange);
dataEntryPanel.setBounds(540, 30, 500, 50);
//dataEntryPanel.add(AgentIDTextField);
dataEntryPanel.add(labelEditMenu);
dataEntryPanel.add(addRow);
dataEntryPanel.add(deleteRow);
// Join up GUI
add(pane);
add(dataEntryPanel);
}
// Enable visibity of frame
public static void showFrame() {
JPanel panel = new JTableRowSelectProgramatically();
JFrame frame = new JFrame("Test table");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
// Launch prog
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableRowSelectProgramatically.showFrame();
}
});
}
// Create custom table model for data entry
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"COLUMN 0", "COLUMN 1", "COLUMN 2", "COLUMN 3"};
private Vector data = new Vector();
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#SuppressWarnings("rawtypes")
#Override
public Object getValueAt(int row, int col) {
return ((Vector) data.get(row)).get(col);
}
public String getColumnName(int col){
return columnNames[col];
}
public Class getColumnClass(int c){
return getValueAt(0,c).getClass();
}
public void setValueAt(Object value, int row, int col){
((Vector) data.get(row)).setElementAt(value, col);
fireTableCellUpdated(row,col);
}
public boolean isCellEditable(int row, int col){
if (3 == col){
return true;
}
else {
return false;
}
}
public void insertData(Object[] values){
data.add(new Vector());
for(int i =0; i<values.length; i++){
System.out.println("data.size is: " + data.size());
((Vector) data.get(data.size()-1)).add(values[i]);
}
fireTableDataChanged();
}
public void removeRow(int row){
data.removeElementAt(row);
fireTableDataChanged();
}
}
}
New attempt at deleting rows of a JTable:
public void deleteRow() {
for (int i = 0; i < getRowCount(); i++) {
Object columnState = getValueAt(i, 3);
System.out.println("STEP 6 - In row " + i + " boolean value is: " + columnState);
boolean columnStateAsBoolean = (Boolean) columnState;
System.out.println("STEP 6 - In row " + i + " Column State As Boolean is: " + columnStateAsBoolean);
if(columnStateAsBoolean == true) {
removeRow(i);
}
System.out.println("-------------------------------------");
}
}
I really want to do is to delete several rows based on boolean states or check boxes
create a loop that starts on the last row and counts down to 0.
Then for every row you use the table.getValueAt(...) method to get the Boolean value of the column.
If the value is true then delete the row.
//Try something like this
int rowCount=table.getSelectedRowCount();//get selected row's count
int row;
if(rowCount>0)
{
while((row=table.getSelectedRow())!=-1)
(DefaultTableModel)table.getModel().removeRow(table.convertRowIndexToModel(row));
}
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.
I have a JTable with a column containing a JComboBox.
I have an ItemListener attached to the JComboBox which acts upon any changes.
However, ItemListener does not have a method for obtaining the Row that the changed ComboBox is within.
I need to Row number in order to act upon another column in the same row when the ComboBox has a change.
Any help would be appreciated.
This is my Short and Concise code. What I am trying to accomplish, is obtaining the Table Row of the ComboBox when a the itemlistener picks up a change.
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class Example extends JFrame {
private static final long serialVersionUID = 1L;
public static int maxX, maxY;
public static final String[] columnHeads = {"Col 1", "Col 2", "Col 3"};
public static void main(String args[]) throws IOException {
Example example = new Example();
}
public Example() {
//Create Table Model
DefaultTableModel model = new DefaultTableModel();
for (int index = 0; index < columnHeads.length; index++) {
model.addColumn(columnHeads[index]);
}
//Create Table
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
//List for ComboBox
String[] list = {"Item1", "Item2", "Item3"};
//Create ComboBox
JComboBox itemTypes = attachComboBoxRenderer(table, 2, list);
//Attach Item Listener
itemTypes.addItemListener(new ComboBoxListener());
((DefaultTableModel) table.getModel()).insertRow(
table.getRowCount(), new Object[]{"C1", "C2", ""});
this.setTitle("Example");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = getContentPane();
//MAIN Panel
final JPanel main = new JPanel();
main.setLayout(new GridBagLayout());
main.add(scrollPane);
container.add(main);
this.pack();
this.setVisible(true);
}
public static JComboBox attachComboBoxRenderer(
JTable table, int column, Object[] values) {
JComboBox combo = new JComboBox(values);
TableColumn col = table.getColumnModel().getColumn(column);
col.setCellRenderer(new ComboBoxRenderer(values));
col.setCellEditor(new DefaultCellEditor(combo));
return combo;
}
}
class ComboBoxListener implements ItemListener {
private static final int SELECTED = 1;
#Override
public void itemStateChanged(ItemEvent e) {
// Get the affected item
Object item = e.getItem();
if (item.toString() != null
&& !"".equals(item.toString())
&& e.getStateChange() == SELECTED) {
System.out.println(item.toString() + " selected");
//How do I get Row in the Table of the ComboBox that was changed?
}
}
}
class ComboBoxRenderer extends JComboBox implements TableCellRenderer {
private static final long serialVersionUID = 1L;
public ComboBoxRenderer(Object[] items) {
super(items);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
// Select the current value
setSelectedItem(value);
return this;
}
}
It sounds like you are Using a Combo Box as an Editor. If so, the TableCellEditor method, getTableCellEditorComponent(), includes the row as a parameter. There's a related example here.
Addendum: To change a value in the same row you've edited, just have the model return the correct value for the "other column" based on the related values in that row. Alternatively, update the related value in your model's setValueAt() method before firing the update, as shown in the example.
Addendum: Based on your example, the code below overrides the model's getValueAt() method to keep the dependent column synchronized with the item column.
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
/** #see http://stackoverflow.com/questions/7350445 */
public class DependentColumn extends JFrame {
private static final int DEPENDENT_COL = 1;
private static final int ITEM_COL = 2;
private static final String[] columnNames = {"Col 1", "Col 2", "Col 3"};
public static void main(String args[]) throws IOException {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DependentColumn dc = new DependentColumn();
}
});
}
public DependentColumn() {
this.setTitle("Example");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create Model & Table
DefaultTableModel model = new DefaultTableModel(columnNames, 0) {
#Override
public Object getValueAt(int row, int col) {
if (col == DEPENDENT_COL) {
return "C2:" + this.getValueAt(row, ITEM_COL);
} else {
return super.getValueAt(row, col);
}
}
};
for (int i = 0; i < 16; i++) {
model.addRow(new Object[]{"C1", "C2", "Item1"});
}
JTable table = new JTable(model);
table.setPreferredScrollableViewportSize(new Dimension(320, 120));
//Create ComboBox
String[] items = {"Item1", "Item2", "Item3"};
JComboBox combo = new JComboBox(items);
TableColumn col = table.getColumnModel().getColumn(ITEM_COL);
col.setCellEditor(new DefaultCellEditor(combo));
combo.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println(e.getItem() + " selected");
}
}
});
this.add(new JScrollPane(table));
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}