updating JTable date - java

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.

Related

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 clear a selected cell in JTable?

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();
}
});
}
}

java swing change background to a selected cell (no columns or rows) at time

This code changes the color of all the column, I need to change the single cell color at time. This code creates a table and installs a TableCellRenderer that modify the column color. It has two buttons that perform this action. The code speaks alone.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;
public class Board extends JPanel {
private static final long serialVersionUID = 1L;
int boardHeight = 20;
int boardWidth = 10;
JTable table;
Random random = new Random();
public Board() {
setLayout(new BorderLayout()); // !!
DefaultTableModel model = new
DefaultTableModel(boardHeight, boardWidth) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
};
// !! table = new JTable(this.boardHeight, this.boardWidth);
table = new JTable(model);
for (int row = 0; row < model.getRowCount(); row++) {
for (int col = 0; col < model.getColumnCount(); col++) {
String s = random.nextBoolean() ? "red" : "yellow";
model.setValueAt(s, row, col);
}
}
//table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
BoardTableCellRenderer mcr = new BoardTableCellRenderer();
table.setFocusable(true);
table.setShowGrid(false);
table.setRowMargin(0);
table.setIntercellSpacing(new Dimension(0, 0));
table.setRowSelectionAllowed(false);
table.setFillsViewportHeight(true);
table.setVisible(true);
//this.add(table);
this.setPreferredSize(new Dimension(table.getPreferredSize().width,
(table.getPreferredSize().height + 85)));
javax.swing.JButton b = new javax.swing.JButton("bottone");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
table.getColumnModel().getColumn(table.getSelectedColumn()).setCellRenderer(mcr);
table.revalidate(); table.repaint();
}
});
javax.swing.JButton b1 = new javax.swing.JButton("bottone default");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
table.setDefaultRenderer(String.class, new DefaultTableCellRenderer());
table.revalidate(); table.repaint();
}
});
/*for (int columnIndex = 0; columnIndex < table.getColumnCount(); columnIndex ++) {
table.getColumnModel().getColumn(columnIndex).setCellRenderer(mcr);
}*/
//JScrollPane p1 = new JScrollPane();
//p1.add(table);
add(b, BorderLayout.SOUTH); // e.g. for the button
add(b1, BorderLayout.NORTH); // e.g. for the button
add(table, BorderLayout.CENTER); // e.g. for the button
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Board");
frame.getContentPane().add(new Board());
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();
}
});
}
}
class BoardTableCellRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, col);
TableModel t = table.getModel();
Object valueAt = table.getModel().getValueAt(row, col);
String s = "";
if (valueAt != null) {
s = valueAt.toString();
}
//if (isSelected) {
// System.out.println("row: "+row+" "+"col: "+col);
if (col == 0 && row == 0) {
c.setForeground(Color.YELLOW);
c.setBackground(Color.gray);
}
//}
/* if (s.equalsIgnoreCase("yellow")) {
c.setForeground(Color.YELLOW);
c.setBackground(Color.gray);
} else {
c.setForeground(Color.black);
c.setBackground(Color.WHITE);
}
*/
return c;
}
}
This code changes the color of all the column,
The same renderer is used by all cells in the column.
So you need code something like:
if (!isSelected)
{
if (your special condition)
{
c.setBackground(...);
}
else // reset background to the default
{
c.setBackground(table.getBackground();
}
}

How to put different JComboBox in each row of JTable dinamically

I would like to create a JTable in my application.
The table will contain two coumns, the first is the name of a software module.
The second column needs to contain a JComboBox with the revision numbers of the software module in the first column.
Is it even possible or I need to find another way to do this? (For example: put a button to the cell and choose the revision from a popup window)
Thank you in advance!
Here is one possible implementation to use a DefaultComboBoxModel<Integer> as the table column's data type:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class EditableComboCellEditorTest {
private JComponent makeUI() {
String[] columnNames = {"version", "revision"};
Object[][] data = {
{"1.7.0", makeModel(76, 79, 80)},
{"1.8.0", makeModel(91, 92, 101, 102)},
};
TableModel model = new DefaultTableModel(data, columnNames) {
#Override public Class<?> getColumnClass(int column) {
return column == 1 ? DefaultComboBoxModel.class : String.class;
}
};
JTable table = new JTable(model);
table.setRowHeight(32);
table.setAutoCreateRowSorter(true);
TableColumn col = table.getColumnModel().getColumn(1);
col.setCellRenderer(new ComboCellRenderer());
col.setCellEditor(new ComboCellEditor());
return new JScrollPane(table);
}
private static DefaultComboBoxModel<Integer> makeModel(Integer... items) {
return new DefaultComboBoxModel<Integer>(items) {
#Override public String toString() {
return Objects.toString(getSelectedItem(), "");
}
};
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new EditableComboCellEditorTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class ComboCellRenderer implements TableCellRenderer {
private final JPanel p = new JPanel(new GridBagLayout());
private final JComboBox<Integer> cb = new JComboBox<>();
#Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
p.removeAll();
p.setOpaque(false);
p.add(cb);
cb.setEditable(true);
cb.removeAllItems();
if (value instanceof DefaultComboBoxModel) {
DefaultComboBoxModel m = (DefaultComboBoxModel) value;
Object o = m.getSelectedItem();
if (o instanceof Integer) {
cb.addItem((Integer) o);
}
}
return p;
}
}
//https://java-swing-tips.blogspot.jp/2016/08/use-editable-jcombobox-as.html
class ComboCellEditor extends AbstractCellEditor implements TableCellEditor {
private final JPanel p = new JPanel(new GridBagLayout());
private final JComboBox<Integer> cb = new JComboBox<>();
protected ComboCellEditor() {
super();
cb.setEditable(true);
cb.addActionListener(e -> fireEditingStopped());
p.add(cb);
p.setOpaque(false);
}
#Override public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
if (value instanceof ComboBoxModel) {
#SuppressWarnings("unchecked")
ComboBoxModel<Integer> m = (ComboBoxModel<Integer>) value;
cb.setModel(m);
}
return p;
}
#Override public Object getCellEditorValue() {
#SuppressWarnings("unchecked")
DefaultComboBoxModel<Integer> m = (DefaultComboBoxModel<Integer>) cb.getModel();
if (cb.isEditable()) {
Object o = cb.getEditor().getItem();
if (o instanceof Integer && m.getIndexOf((Integer) o) < 0) {
Integer value = (Integer) o;
int n = m.getSize();
Vector<Integer> list = new Vector<>(n + 1);
for (int i = 0; i < n; i++) {
list.add(m.getElementAt(i));
}
list.add(value);
Collections.sort(list);
m = new DefaultComboBoxModel<Integer>(list);
cb.setModel(m);
cb.setSelectedIndex(m.getIndexOf(value));
}
}
return m;
}
}
Override the getCellEditor(...) method to return the combo box:
import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableComboBoxByRow extends JPanel
{
List<String[]> editorData = new ArrayList<String[]>(3);
public TableComboBoxByRow()
{
setLayout( new BorderLayout() );
// Create the editorData to be used for each row
editorData.add( new String[]{ "Red", "Blue", "Green" } );
editorData.add( new String[]{ "Circle", "Square", "Triangle" } );
editorData.add( new String[]{ "Apple", "Orange", "Banana" } );
// Create the table with default data
Object[][] data =
{
{"Color", "Red"},
{"Shape", "Square"},
{"Fruit", "Banana"},
{"Plain", "Text"}
};
String[] columnNames = {"Type","Value"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable(model)
{
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 1 && row < 3)
{
JComboBox<String> comboBox1 = new JComboBox<String>( editorData.get(row));
return new DefaultCellEditor( comboBox1 );
}
else
return super.getCellEditor(row, column);
}
};
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
// table.getColumnModel().getColumn(1).setCellRenderer(new ComboBoxRenderer2() );
}
/*
class ComboBoxRenderer2 extends DefaultTableCellRenderer
{
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
label.setIcon(UIManager.getIcon("Table.descendingSortIcon"));
return label;
}
}
*/
private static void createAndShowUI()
{
JFrame frame = new JFrame("Table Combo Box by Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TableComboBoxByRow() );
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

How to create table with JComboBox in columns [duplicate]

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);
}
}

Categories