I'm working on a program for a little store. When I click the button "Report", it must show a Table, like this one:
Column names "A", "B"..."N", must be the names of the employees. But I can't figure out how.
Here is my code:
public void Inform()
{
String[] employee;
String[] product[];
this.setLayout(null);
Inform=new JTable(nulo, employee.length);
model = new DefaultTableModel() {
private static final long serialVersionUID = 1L;
#Override
public int getColumnCount() {
return 1;
}
#Override
public boolean isCellEditable(int row, int col) {
return false;
}
#Override
public int getRowCount() {
return Inform.getRowCount();
}
};
headerTable = new JTable(model);
for (int i = 0; i < Inform.getRowCount(); i++)
headerTable.setValueAt(product[i], i, 0);
headerTable.setShowGrid(false);
headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
headerTable.setPreferredScrollableViewportSize(new Dimension(50, 0));
headerTable.getColumnModel().getColumn(0).setPreferredWidth(50);
scrollPane = new JScrollPane(Inform);
scrollPane.setRowHeaderView(headerTable);
scrollPane.setBounds(5,5,500,500);
scrollPane.setEnabled(false);
this.add(scrollPane);
}
Employee and product variates depending how many are entered. nulo is how many products are ready to sell.
You should add getColumnName() in your TableModel:
String[] employee = {"Employee 1", "Employee 2"};
#Override
public String getColumnName(int index) {
return employee[index];
}
In your case this could be:
model = new DefaultTableModel() {
private static final long serialVersionUID = 1L;
String[] employee = {"Employee 1", "Employee 2"};
#Override
public int getColumnCount() {
return employee.length;
}
#Override
public boolean isCellEditable(int row, int col) {
return false;
}
#Override
public int getRowCount() {
return Inform.getRowCount();
}
#Override
public String getColumnName(int index) {
return employee[index];
}
};
And here is a fully working example:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class TableNamesTest extends JFrame {
public TableNamesTest() {
DefaultTableModel model = new DefaultTableModel() {
String[] employee = {"emp 1", "emp 2"};
#Override
public int getColumnCount() {
return employee.length;
}
#Override
public String getColumnName(int index) {
return employee[index];
}
};
JTable table = new JTable(model);
add(new JScrollPane(table));
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new TableNamesTest();
}
}
Here is the example from the oracle website, you can load the names you want for your columns into an array, then pass the array to the JTable
String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
//Then the Table is constructed using these data and columnNames:
JTable table = new JTable(data, columnNames);
The resulting table looks like this:
Link to tutorial on JTables: http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#data
Try this:
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
public class Class1 extends JFrame{
static JTable table;
static String[] Employees = {"Employee1","Employee2","Employee3","Employee4"};
static int NumberOfRows=4;
static int NumberOfColumns=4;
public static void main(String[] args){
table = new JTable(NumberOfRows,NumberOfColumns);
for(int i=0;i<Employees.length;i++){
TableColumn tc = table.getColumnModel().getColumn(i);
tc.setHeaderValue(Employees[i]);
DefaultTableCellRenderer dtcr = new DefaultTableCellRenderer();
dtcr.setHorizontalAlignment(SwingConstants.CENTER); //For Aligning the Elements of all columns to CENTER
tc.setCellRenderer(dtcr);
}
JFrame frame = new JFrame();
frame.add(new JScrollPane(table));
frame.setSize(300,300);
frame.setVisible(true);
}
}`
This is more of a manual approach but it works for me.
JTabel TABLE = new JTable();
JTableHeader HEADER = TABLE.getTableHeader();
TableColumnModel TMC = HEADER.getColumnModel();
TableColumn TC = TMC.getColumn(0);
TC.setHeaderValue("Person 1");
TableColumn TC1 = TMC.getColumn(1);
TC1.setHeaderValue("Person 2");
HEADER.repaint();
TABLE.getTableHeader().repaint();
Related
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();
}
});
}
}
I created JTable that contains information about employees. In this JTable I added the column called "Qualifications". This column is represented by JComboBox (different content at each row). For instance:
Row 1 | JComboBox(){"Programmer","Web"}
Row 2 | JComboBox(){"Writer","Editor"}
The JComboBox content is taken from the List<String> employees[row].getQualification().
The problem is that the selected item in Row 1 and Row 2 is "Programmer", however "Programmer" should not appear in Row 2. Only when I click on JComboBox, the correct list appears, i.e. Row 2 - {"Writer","Editor"}.
TableColumn column = table.getColumnModel().getColumn(5);
column.setCellRenderer(getRenderer());
private TableCellRenderer getRenderer() {
return new TableCellRenderer() {
private JComboBox<String> box = new JComboBox<String>();
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
for (String q : employees[row].getQualification())
box.addItem(q);
box.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
box.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return box;
}
};
}
Override the getCellEditor() method of the JTable. Something like:
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableComboBoxByRow extends JPanel
{
List<TableCellEditor> editors = new ArrayList<TableCellEditor>(3);
public TableComboBoxByRow()
{
setLayout( new BorderLayout() );
// Create the editors to be used for each row
String[] items1 = { "Red", "Blue", "Green" };
JComboBox<String> comboBox1 = new JComboBox<String>( items1 );
DefaultCellEditor dce1 = new DefaultCellEditor( comboBox1 );
editors.add( dce1 );
String[] items2 = { "Circle", "Square", "Triangle" };
JComboBox<String> comboBox2 = new JComboBox<String>( items2 );
DefaultCellEditor dce2 = new DefaultCellEditor( comboBox2 );
editors.add( dce2 );
String[] items3 = { "Apple", "Orange", "Banana" };
JComboBox<String> comboBox3 = new JComboBox<String>( items3 );
DefaultCellEditor dce3 = new DefaultCellEditor( comboBox3 );
editors.add( dce3 );
// 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)
return editors.get(row);
else
return super.getCellEditor(row, column);
}
};
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
}
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();
}
});
}
}
JComboBox-es appear only on a click
because you use them as CellEditor, which apper only when you edit cells. If you want to display your column cells as JComboBox everytime, you need to use TableCellRenderer, read about that. Here is simple example of JComboBox as renderer :
import java.awt.Component;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class TestFrame extends JFrame{
public TestFrame(){
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
private void init() {
JTable t = new JTable(3,3);
TableColumn column = t.getColumnModel().getColumn(2);
column.setCellRenderer(getRenderer());
add(new JScrollPane(t));
}
private TableCellRenderer getRenderer() {
return new TableCellRenderer() {
private JComboBox<String> box = new JComboBox<String>(new String[]{"1","2"});
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
box.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
box.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return box;
}
};
}
public static void main(String... s){
new TestFrame();
}
}
Thanks to #alex2410, I cleaned up the code and wrapped it into a ComboTable class which should do the job for you. instantiate ComboTable class with a hashmap of each row values (the demo assumes 2 columns, but you can add more). Note MyMap.of is just a wrapper for java 9 Map.of since I was using Java 8 at that time. same for MyList.of
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.EventObject;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import rs.code.utils.MyList;
import rs.code.utils.MyMap;
public class Test extends JFrame
{
private static final long serialVersionUID = 1L;
public ComboTable table = new ComboTable(MyMap.of("Gender", MyList.of("male", "female"), "City", MyList.of("london", "bedord"), "orientation", MyList.of("left", "right")));
public Test()
{
super("EachRow Editor Example");
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll, BorderLayout.CENTER);
setPreferredSize(new Dimension(400, 120));
setLocation(150, 100);
pack();
setVisible(true);
}
public static void main(String[] args)
{
Test frame = new Test();
frame.addWindowListener(new WindowAdapter()
{
#Override
public void windowClosing(WindowEvent e)
{
System.out.println(frame.table.getSelectedValues().toString());
System.exit(0);
}
});
}
}
class ComboTable extends JTable
{
private static final long serialVersionUID = 1L;
protected Map<Integer, ComboCellEditor> editors = new LinkedHashMap<>();
public ComboTable(Map<String, List<String>> rows)
{
setModel(new DefaultTableModel(new String[] {"Attribute", "Value"}, rows.size()));
setRowHeight(20);
EachRowEditor rowEditor = new EachRowEditor(this);
int i = 0;
for(String key : rows.keySet())
{
getModel().setValueAt(key, i, 0);
editors.put(i++, new ComboCellEditor(createComboBox(rows.get(key))));
}
getColumn("Value").setCellEditor(rowEditor);
getColumn("Value").setCellRenderer(getRenderer());
}
public Map<Integer, ComboCellEditor> getEditors()
{
return editors;
}
public Map<String, String> getSelectedValues()
{
Map<String, String> values = new LinkedHashMap<>();
for(int i=0;i<getModel().getRowCount();i++)
{
values.put(getModel().getValueAt(i, 0).toString(), editors.get(i).getComboBox().getSelectedItem().toString());
}
return values;
}
private JComboBox<String> createComboBox(List<String> elements)
{
JComboBox<String> comboBox = new JComboBox<>();
for (String element : elements)
{
comboBox.addItem(element);
}
comboBox.setSelectedIndex(0);
comboBox.addComponentListener(new ComponentAdapter()
{
#Override
public void componentShown(ComponentEvent e)
{
final JComponent c = (JComponent) e.getSource();
SwingUtilities.invokeLater(new Runnable()
{
#SuppressWarnings("rawtypes")
#Override
public void run()
{
c.requestFocus();
System.out.println(c);
if (c instanceof JComboBox)
{
System.out.println(((JComboBox) c).getSelectedItem());
}
}
});
}
});
return comboBox;
}
private TableCellRenderer getRenderer()
{
return new TableCellRenderer()
{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
editors.get(row).getComboBox().setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
editors.get(row).getComboBox().setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return editors.get(row).getComboBox();
}
};
}
}
class ComboCellEditor extends DefaultCellEditor
{
private static final long serialVersionUID = 1L;
private final JComboBox<String> comboBox;
public ComboCellEditor(JComboBox<String> comboBox)
{
super(comboBox);
this.comboBox = comboBox;
}
public JComboBox<String> getComboBox()
{
return comboBox;
}
}
class EachRowEditor implements TableCellEditor
{
private TableCellEditor editor;
private final TableCellEditor defaultEditor;
private final ComboTable table;
public EachRowEditor(ComboTable table)
{
this.table = table;
defaultEditor = new DefaultCellEditor(new JTextField());
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
return editor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
public Object getCellEditorValue()
{
return editor.getCellEditorValue();
}
public boolean stopCellEditing()
{
return editor.stopCellEditing();
}
public void cancelCellEditing()
{
editor.cancelCellEditing();
}
public boolean isCellEditable(EventObject anEvent)
{
selectEditor((MouseEvent) anEvent);
return editor.isCellEditable(anEvent);
}
public void addCellEditorListener(CellEditorListener l)
{
editor.addCellEditorListener(l);
}
public void removeCellEditorListener(CellEditorListener l)
{
editor.removeCellEditorListener(l);
}
public boolean shouldSelectCell(EventObject anEvent)
{
selectEditor((MouseEvent) anEvent);
return editor.shouldSelectCell(anEvent);
}
protected void selectEditor(MouseEvent e)
{
int row;
if (e == null)
{
row = table.getSelectionModel().getAnchorSelectionIndex();
}
else
{
row = table.rowAtPoint(e.getPoint());
}
editor = table.getEditors().get(row);
if (editor == null)
{
editor = defaultEditor;
}
}
}
What I'm trying to do:
I want to have two JTables side by side, and when you make a selection on the left JTable you see more detailed information about that row in the JTable to the right.
What's my problem?:
I have no idea how to implement this. I have tried using the addListSelectionListener, but I'm unsure on how I can use a listener from one table to interact with a completely different table. Such as, having the listener replace table2 with a new table that has completely new data.
I've included an SSCCE which shows the gist of what I did. I would appreciate any help, as I've been scouring the internet trying to piece this problem together.
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
public class TableInteraction extends JPanel
{
private JTable table1;
private JTable table2;
public TableInteraction()
{
super();
String[][] tableOneData = {{"Kathy", "Smith"}};
String[][] tableTwoData = {{"Kathy", "Smith"}};
String[][] tableThreeData = {{"Matt", "Bird"}};
setLayout(new BorderLayout());
FirstTableModel model1 = new FirstTableModel(tableOneData);
table1 = new JTable(model1);
table1.setPreferredScrollableViewportSize(new Dimension(500,200));
table1.setFillsViewportHeight(true);
table1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table1.setRowSelectionInterval(0,0);
JScrollPane scrollPane1 = new JScrollPane(table1);
SecondTableModel model2 = new SecondTableModel(tableTwoData);
table2 = new JTable(model2);
table2.setPreferredScrollableViewportSize(new Dimension(500,200));
table2.setFillsViewportHeight(true);
table2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane scrollPane2 = new JScrollPane(table2);
table1.getSelectionModel().addListSelectionListener(
new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent event)
{
int index = table1.getSelectedRow();
}
});
add(scrollPane1, BorderLayout.WEST);
add(scrollPane2, BorderLayout.EAST);
}
public class FirstTableModel extends AbstractTableModel
{
private String[] columnNames = {"First Name", "Last Name"};
private String[][] data;
public FirstTableModel(String[][] data)
{
this.data = data;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
}
public class SecondTableModel extends AbstractTableModel
{
private String[] columnNames = {"First Name", "Last Name"};
private String[][] data;
public SecondTableModel(String[][] data)
{
this.data = data;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableFilterDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableInteraction newContentPane = new TableInteraction();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Consider this (extension of my comment)
private String[] columnNames1 = {"First Name", "Last Name"};
private String[][] data1 = {{"Kathy", "Smith"},{"John","Doe"}};
private String[] columnNames2 = {"First Name", "Last Name"};
private String[][] data2 = {{"Kathy", "Smith"},{"John","Doe"}};
DefaultTableModel tableModel1 = new DefaultTableModel(data1, columnNames1);
DefaultTableModel tableModel2 = new DefaultTableModel(data2, columnNames2);
JTable jTable1 = new JTable(tableModel1);
JTable jTable2 = new JTable(tableModel1);
jTable1.getSelectionModel().addListSelectionListener(
new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent event)
{
int index = jTable1.getSelectedRow();
jTable2.removeRow(index);
}
});
When a row from table1 is selected, The same row from table2 is deleted. This is a bizarre example that would not work without some null checks, but it shows how two tables can interact using the table model
Edit: with OP added comment
If you want to set the second table based on the first table, you can do something like this
jTable2.setModel(jTable1.getModel());
Also, you should place you listener AFTER creating tables and models, so that you can can use the model. If they haven't been declared yet, you cant use them in the listener, unless they are declared as global
I'm new to GUI design and I'm trying to plan this out before I go too far the wrong way, any help would be nice. I'm trying to display a JTable with rows of Employee, which itself has datatypes of String and ArrayList<Cert>. Cert contains a String.
I'd like to have the table present the data for editing, but for a few of the columns I'd like to implement a JComboBox for selection of a String from a set of valid strings, as well as color each option differently (different background colors in the JComboBox).
Also, the ArrayList<Cert> currently displays in a cell as [xxx, xxx, ...] where XXX is the return from the toString() function for each item in the ArrayList. I think I'd like to display that ArrayList<Cert> as a read-only JComboBox, but I'm not as concerned with this item.
I'm questioning how many classes I need to create to make this happen. I already have a custom model for the JTable extending AbstractTableModel. Do I need to write an extension of JComboBox or do I just need to extend the appropriate renderer for a JComboBox as a cell and do the magic there, then assign that custom renderer to the cell renderer for the String cell?
Here's what I have so far, lightly abridged:
public class EmployeeTableModel extends AbstractTableModel {
...
private ArrayList<Employee> myDataObjects = new ArrayList<Employee>();
...
#Override
public Object getValueAt(int row, int column) {
Employee emp = myDataObjects.get(row);
switch (column) {
case 0:
return emp.getName();
case 1:
return emp.getShift();
case 2:
return emp.getCertifications();
default:
return "";
}
}
}
Employees:
public class Employee {
private String name;
private String shift;
private ArrayList<Cert> certs;
...
public String getName() {
return name;
}
public String getShift() {
return shift;
}
public ArrayList<Cert> getCerts() {
return certs;
}
...
}
And the initializations:
EmployeeTableModel etm = new EmployeeTableModel();
JTable employeeTable = new JTable();
employeeTable.setModel( etm );
you can to start with, simplest code as is possible, maybe depends if you want to see JComboBox as Renderer too by #aterai
import java.awt.BorderLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
public class TableRenderDemo extends JPanel {
private static final long serialVersionUID = 1L;
public TableRenderDemo() {
super(new BorderLayout(5, 5));
final JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.setFillsViewportHeight(true);
table.setRowHeight(20);
JScrollPane scrollPane = new JScrollPane(table);
initColumnSizes(table);
setUpSportColumn(table, table.getColumnModel().getColumn(2));
add(scrollPane, BorderLayout.CENTER);
JButton resetButton = new JButton("Reset to default");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < table.getRowCount(); i++) {
table.getModel().setValueAt("None of the above", i, 2);
}
}
});
add(resetButton, BorderLayout.SOUTH);
}
private void initColumnSizes(JTable table) {
MyTableModel model = (MyTableModel) table.getModel();
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).getTableCellRendererComponent(table, longValues[i], false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
}
private void setUpSportColumn(JTable table, TableColumn sportColumn) {
ArrayList<String> listSomeString = new ArrayList<String>();
listSomeString.add("Snowboarding");
listSomeString.add("Rowing");
listSomeString.add("Knitting");
listSomeString.add("Speed reading");
listSomeString.add("Pool");
listSomeString.add("None of the above");
JComboBox comboBox = new JComboBox();
comboBox.addItem(new Item(1, "-"));
comboBox.addItem(new Item(2, "Snowboarding"));
comboBox.addItem(new Item(3, "Rowing"));
comboBox.addItem(new Item(4, "Knitting"));
comboBox.addItem(new Item(5, "Speed reading"));
comboBox.addItem(new Item(6, "Pool"));
comboBox.addItem(new Item(7, "None of the above"));
comboBox.setMaximumRowCount(3);
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox comboBox = (JComboBox) e.getSource();
Item item = (Item) comboBox.getSelectedItem();
System.out.println(item.getId() + " : " + item.getDescription());
}
});
comboBox.setRenderer(new ItemRenderer());
sportColumn.setCellEditor(new DefaultCellEditor(comboBox));
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
}
class ItemRenderer extends BasicComboBoxRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
Item item = (Item) value;
setText(item.getDescription().toUpperCase());
}
if (index == -1) {
Item item = (Item) value;
setText("" + item.getId());
}
return this;
}
}
class Item {
private int id;
private String description;
public Item(int id, String description) {
this.id = id;
this.description = description;
}
public int getId() {
return id;
}
public String getDescription() {
return description;
}
#Override
public String toString() {
return description;
}
}
class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"};
private Object[][] data = {{"Kathy", "Smith", "Snowboarding", new Integer(5), false},
{"John", "Doe", "Rowing", new Integer(3), true}, {"Sue", "Black", "Knitting", new Integer(2), false},
{"Jane", "White", "Speed reading", new Integer(20), true}, {"Joe", "Brown", "Pool", new Integer(10), false}};
public final Object[] longValues = {"Jane", "Kathy", "None of the above", new Integer(20), Boolean.TRUE};
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return data.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
#Override
public Object getValueAt(int row, int col) {
return data[row][col];
}
#Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
System.out.println("New value of data: " + getValueAt(row, col));
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableRenderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableRenderDemo newContentPane = new TableRenderDemo();
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
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);
}
}