Get value from a cell in JTable - java

I've looked everywhere but can't seem to figure this out. I just want to pull out a cell's value from my JTable when a user clicks on it.
However at the moment I am getting -1 so I suppose double clicking results in no row being detected. Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLException;
import javax.swing.*;
import javax.swing.table.TableColumn;
public class CardLayoutExample {
private static JScrollPane scrollPane;
public static void main(String[] arguments) throws SQLException {
// main window
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame window = new JFrame("CardLayout Example");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1500,800);
window.getContentPane().setLayout(new BorderLayout());
final CardLayout cardLayout = new CardLayout();
final JPanel cardPanel = new JPanel(cardLayout);
JPanel card3 = new JPanel();
cardPanel.add(card3,"All Patients");
String AllPatients="select * from tblPtDetails";
JTable tablePatientDt = new JTable(Bquery.buildTableModel(Bquery.resultQuery(AllPatients)));
tablePatientDt.setEnabled(false);
tablePatientDt.setPreferredScrollableViewportSize(new Dimension(1200, 400));
tablePatientDt.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
tablePatientDt.setRowHeight(30);
tablePatientDt.setAutoCreateRowSorter(true);
card3.add(tablePatientDt);
card3.add(new JScrollPane(tablePatientDt), BorderLayout.CENTER);
for (int i = 0; i < (tablePatientDt.getColumnCount()); i++) {
TableColumn columnPatients = null;
columnPatients = tablePatientDt.getColumnModel().getColumn(i);
columnPatients.setPreferredWidth(70); //sport column is bigger
}
tablePatientDt.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int row = tablePatientDt.getSelectedRow();
int column = tablePatientDt.getSelectedColumn();
//Object val= tablePatientDt.getModel().getValueAt(row, column);
//tablePatientDt.getModel().getValueAt(row, column);
//return tablePatientDt.getModel().getValueAt(row, column);
System.out.println(row);
JFrame newFrame = new JFrame();
newFrame.setTitle("Detail Screen");
newFrame.setVisible(true);
}
}
});

Your main problem is here:
tablePatientDt.setEnabled(false);
Because the table is not enabled, no cell or row can ever be selected, and so the selected row will always be -1. Solution: get rid of that line. Instead, if you don't want a cell to be editable on double click, override the JTable or its model and override the isCellEditable method:
e.g.,
// create your JTable model here:
DefaultTableModel model = ......
JTable tablePatientDt = new JTable(model){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
Other issues: don't add the JTable to more than one component as you're doing. That spells great risk for trouble since Swing components can be added to only one component at a time.
A side recommendation: in your future questions post only small compilable and runnable programs. Your code above cannot run since it has database dependencies that we don't have access to, and is also incomplete. In order to find your problem, I had to take your code and create a small runnable program with it, an mcve (please read the link):
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLException;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class CardLayoutExample {
private static JScrollPane scrollPane;
public static void main(String[] arguments) throws SQLException {
// main window
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame window = new JFrame("CardLayout Example");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// !! window.setSize(1500, 800);
window.getContentPane().setLayout(new BorderLayout());
final CardLayout cardLayout = new CardLayout();
final JPanel cardPanel = new JPanel(cardLayout);
JPanel card3 = new JPanel();
cardPanel.add(card3, "All Patients");
String AllPatients = "select * from tblPtDetails";
//!!
String[][] data = {{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}};
String[] columnNames = {"One", "Two", "Three"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
// !! JTable tablePatientDt = new JTable(Bquery.buildTableModel(Bquery.resultQuery(AllPatients)));
JTable tablePatientDt = new JTable(model){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
// !! tablePatientDt.setEnabled(false);
tablePatientDt.setPreferredScrollableViewportSize(new Dimension(1200, 400));
tablePatientDt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tablePatientDt.setRowHeight(30);
tablePatientDt.setAutoCreateRowSorter(true);
// !! card3.add(tablePatientDt);
card3.add(new JScrollPane(tablePatientDt), BorderLayout.CENTER);
for (int i = 0; i < (tablePatientDt.getColumnCount()); i++) {
TableColumn columnPatients = null;
columnPatients = tablePatientDt.getColumnModel().getColumn(i);
columnPatients.setPreferredWidth(70); // sport column is bigger
}
tablePatientDt.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int row = tablePatientDt.getSelectedRow();
int column = tablePatientDt.getSelectedColumn();
// Object val= tablePatientDt.getModel().getValueAt(row,
// column);
// tablePatientDt.getModel().getValueAt(row, column);
// return tablePatientDt.getModel().getValueAt(row, column);
System.out.println(row);
JFrame newFrame = new JFrame();
newFrame.setTitle("Detail Screen");
newFrame.setVisible(true);
}
}
});
//!!
window.add(cardPanel);
window.pack();
window.setVisible(true);
}
}
But really this effort should be yours not mine, since we're all volunteers, and you're the one asking for volunteer help in solving a problem. So in the future we ask that you create your own mcve to go with your questions.
Also that detail window shouldn't be a JFrame but rather a JDialog.

Related

Remove the rows of jTable that have been selected and were saved in a list at same time after press a button

I need to remove the rows that are selected after a button is pressed.
That's is my code: I have a column that is a checkbox, then a check if it is checked and add the corresponding line to the list.
DefaultTableModel model = (DefaultTableModel) jTableLayouts.getModel();
// gets the number of rows that were selected
Public ArrayList<Integer> selectedLines = new ArrayList<Integer>();
for (int j = 0; j <= jTableLayouts.getModel().getRowCount(); j++) {
if ((Boolean) jTableLayouts.getModel().getValueAt(j,2)){ //checkbox
selectedLines.add(jTableLayouts.getSelectedRow());
}
model.removeRow(selectedLines.get(j));
}
With this code I can remove one by one. Any ideas how I can remove all the lines after a press the button?
EDIT: I only need to remove the rows that are marked as true in the checkbox. Example: the rows 0,1,4,5 are marked as true, after that I will add these lines in a list, and then just remove the lines that are on the list at same time after the button is pressed.
As #MadProgrammer already commented, you can do this from a button by having the ActionListener perform the deletes and add the deleted rows to the list you want.
In this snippet when pressing the button, the checked rows on the left are deleted and added to the table on the right. Check the createDeleteButton method for how this is done.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
#SuppressWarnings("serial")
public class TestTableDeleteRows extends JPanel {
private JTable tblLeft;
private JTable tblRight;
public TestTableDeleteRows() {
initialize();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600,400);
}
private void initialize() {
setLayout(new BorderLayout());
add(createHeaderPane(),BorderLayout.NORTH);
add(createTablePane(),BorderLayout.CENTER);
add(createDeleteButton(),BorderLayout.SOUTH);
}
private JPanel createHeaderPane() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS));
p.add(new JScrollPane(new JLabel("Source",SwingConstants.CENTER)));
p.add(new JScrollPane(new JLabel("Deleted",SwingConstants.CENTER)));
return p;
}
private JPanel createTablePane() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
tblLeft = createTable(stdRows);
tblRight = createTable(new Vector<Vector<Object>>());
p.add(new JScrollPane(tblLeft));
p.add(new JScrollPane(tblRight));
return p;
}
private static final int COL_CHECK=0;
private static final int COL_TEXT=1;
private static final Vector<Vector<Object>> stdRows;
private static final Vector<Object> cols;
static {
stdRows = new Vector<Vector<Object>>();
for(int i=0;i!=100;++i)
stdRows.add(new Vector<Object>(Arrays.asList(new Object[]{Boolean.FALSE,"This is text line number "+(i+1)})));
cols = new Vector<>(Arrays.asList(new Object[]{"Check me","Silly text"}));
}
private static JTable createTable(Vector<Vector<Object>> rows) {
JTable t = new JTable(rows,cols) {
#Override
public Class<?> getColumnClass(int column) {
if(getRowCount()>0)
return getValueAt(0, column).getClass();
return super.getColumnClass(column);
}
};
t.getColumnModel().getColumn(COL_CHECK).setPreferredWidth(50);
t.getColumnModel().getColumn(COL_TEXT).setPreferredWidth(200);
return t;
}
private JButton createDeleteButton() {
JButton b = new JButton("Delete checked rows");
b.addActionListener(new ActionListener() {
#SuppressWarnings("unchecked")
#Override
public void actionPerformed(ActionEvent e) {
Vector<Vector<Object>> removedRows = new Vector<>();
DefaultTableModel modelLeft = (DefaultTableModel) tblLeft.getModel();
for(int r=0;r!=modelLeft.getRowCount();++r)
if((Boolean) modelLeft.getValueAt(r,COL_CHECK)) {
removedRows.add((Vector<Object>) modelLeft.getDataVector().get(r));
modelLeft.removeRow(r--);
}
DefaultTableModel modelRight = (DefaultTableModel) tblRight.getModel();
for(Vector<Object> row : removedRows)
modelRight.addRow(row);
}
});
return b;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Delete checked rows in JTable from button");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new TestTableDeleteRows());
f.pack();
f.setVisible(true);
}
});
}
}
Result:

Error when deleting a row in a row sorted JTable

I get an error when I remove a row a sorted row in a JTable.
The error appears only when the table is sorted, and I know where the error source is:
the method updateRowHeights() in the tableChanged causes an Exception java.lang.ArrayIndexOutOfBoundsException.
I guess that the line int rowHeight = table.getRowHeight(); causes the problem,
but I don't know why.
Here is my code:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class TableExample {
String [] title = new String [] {"Title A", "Title B"};
Object [][] data = new String [][] {{"aaaaaaaaaaaa aaaaaa aaaaaaa", "bbbbbbbb bbbb bbbbbb bbbbbb"},
{"cccccccccc cccccccc ccccccc", "ddddddd ddd dddddddd dddddd"},
{"eeeeeeeeee eeeeeeee eeeeeee", "fffffff ffff ffffff fffffff"}};
private JTable table;
private JFrame frame;
private DefaultTableModel model;
private JScrollPane pane1;
TableExample() {} //constructor
public JPanel createTable() {
JPanel panel = new JPanel();
//creating tables and table models
model = new DefaultTableModel(data, title);
table = new JTable(model);
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
updateRowHeights();
}
});
//enable table sorting
table.setAutoCreateRowSorter(true);
pane1 = new JScrollPane(table);
pane1.setPreferredSize(new Dimension(300,300));
updateRowHeights();
panel.add(pane1);
//delete a row after del keystroke
keyBindings();
return panel;
}
void showTable() {
//create and show frame
JPanel testPanel = createTable();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testPanel);
frame.pack();
frame.setVisible(true);
}//showTable
void updateRowHeights() {
for (int row = 0; row < table.getRowCount(); row++) {
int rowHeight = table.getRowHeight();
Component comp = table.prepareRenderer(table.getCellRenderer(row, 1), row, 1);
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
table.setRowHeight(row, rowHeight);
}
}
void keyBindings() {
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
actionMap.put("delete", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
model.removeRow(row);
}
});
}
public static void main(String[] args) {
TableExample example = new TableExample();
example.showTable();
}//main
}//TableExample
How can I solve this problem?
As noted here, "When using a sorter, always remember to translate cell coordinates." In your delete action, for example,
row = table.convertRowIndexToModel(row);
A similar problem afflicts updateRowHeights(), although I did not pursue this.
Also consider overriding getPreferredScrollableViewportSize(), instead of calling setPreferredSize(); more details here.
As tested:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class TableExample {
String[] title = new String[]{"Title A", "Title B"};
Object[][] data = new String[][]{
{"aaaaaaaaaaaa aaaaaa aaaaaaa", "bbbbbbbb bbbb bbbbbb bbbbbb"},
{"cccccccccc cccccccc ccccccc", "ddddddd ddd dddddddd dddddd"},
{"eeeeeeeeee eeeeeeee eeeeeee", "fffffff ffff ffffff fffffff"}};
private JTable table;
private JFrame frame;
private DefaultTableModel model;
private JScrollPane pane1;
public JPanel createTable() {
JPanel panel = new JPanel();
//creating tables and table models
model = new DefaultTableModel(data, title);
table = new JTable(model);
//enable table sorting
table.setAutoCreateRowSorter(true);
pane1 = new JScrollPane(table);
panel.add(pane1);
//delete a row after del keystroke
keyBindings();
return panel;
}
void showTable() {
//create and show frame
JPanel testPanel = createTable();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testPanel);
frame.pack();
frame.setVisible(true);
}//showTable
void keyBindings() {
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
actionMap.put("delete", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
row = table.convertRowIndexToModel(row);
model.removeRow(row);
}
});
}
public static void main(String[] args) {
TableExample example = new TableExample();
example.showTable();
}//main
}//TableExample

JTable inside a JScrollPane not showing up properly

I am working on a the GUI of a piece of code that I have been patching together. I am stuck at this part of the program where I would like a datafile the user chooses to be displayed in a JTable in a preview manner (i.e. the user should not be able to edit the data on the table).
With a button click from Experiment Parameters tab (see screenshot below), I create and run a "PreviewAction" which creates a new tab, and fills it up with the necessary components. Below is the code for DataPreviewAction. EDIT: I also posted a self-contained, minimal version of this that mimics the conditions in the real project, and exhibits the same behaviour.
import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class MyFrame extends JFrame {
private JPanel panel1;
private JTabbedPane tabs;
private JButton runButton;
public MyFrame() {
tabs = new JTabbedPane();
panel1 = new JPanel();
runButton = new JButton("go!");
runButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
runButtonActionPerformed(evt);
}
});
panel1.add(runButton);
tabs.addTab("first tab", panel1);
this.add(tabs);
pack();
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager
.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
java.util.logging.Level.SEVERE, null, ex);
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
MyFrame frame = new MyFrame();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
/*
* Normally there is more stuff happening here but this much will do for
* the sake of example
*/
List<String[]> data = new LinkedList<String[]>();
for (int i = 1; i < 1000; i++)
data.add(new String[] { "entry1", "value1", "value2", "value3" });
SwingUtilities.invokeLater(new DataPreviewAction(data, tabs));
}
public class DataPreviewAction implements Runnable {
private JTabbedPane contentHolder;
private List<String[]> data;
public DataPreviewAction(List<String[]> data, JTabbedPane comp) {
this.contentHolder = comp;
this.data = data;
}
#Override
public void run() {
DefaultTableModel previewModel = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
for (String[] datarow : data) {
previewModel.addRow(Arrays.copyOf(datarow, datarow.length,
Object[].class));
}
JTable table = new JTable(previewModel);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton("A button"));
buttonPanel.add(new JLabel(
"Some description for the awesome table below "));
buttonPanel.add(new JButton("another button"));
JScrollPane tablePanel = new JScrollPane(table);
JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.add(buttonPanel, BorderLayout.NORTH);
container.add(tablePanel, BorderLayout.CENTER);
contentHolder.addTab("Preview", container);
contentHolder.validate();
contentHolder.repaint();
}
}
}
There are at least two problems here:
The JTable (or the JScrollPane) does not render at all
The JScrollPane is not as wide as the frame itself, I have no idea why
I am not all that good in Swing so I might be missing something fundamental. I have checked that the datafile is read properly, and the data model contains the right amount of rows (1000+). SO the table should not be empty.
Suggestions?
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton("A button"));
buttonPanel.add(new JLabel("Some description for the awesome table below "));
buttonPanel.add(new JButton("another button"));
JScrollPane tablePanel = new JScrollPane(table);
JPanel container = new JPanel();
container.add(buttonPanel,BorderLayout.NORTH);
container.add(tablePanel,BorderLayout.SOUTH);
contentHolder.addTab("Preview", container);
//contentHolder.validate(); <- NO good
//contentHolder.repaint(); <- --"---
}
JPanel uses FlowLayout (implemented in API, acceptiong only PreferredSize, by default isn't resizable), correct output as is demonstrated in attn image, you have to change default LayoutManager for JPanel to BorderLayout, then code lines
.
container.add(buttonPanel,BorderLayout.NORTH);
container.add(tablePanel,BorderLayout.SOUTH);
will expands JComponents and can be works as you expecting, but I think tablePanel should be placed in CENTER area
EDIT:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class MyFrame extends JFrame {
private JPanel panel1;
private JTabbedPane tabs;
private JButton runButton;
private JFrame frame = new JFrame();
private String[] columnNames = {"Nama", "Nim", "IP", "Hapus Baris ke"};
private Object[][] data = {
{"igor", "B01_125-358", "1.124.01.125", true},
{"lenka", "B21_002-242", "21.124.01.002", true},
{"peter", "B99_001-358", "99.124.01.001", false},
{"zuza", "B12_100-242", "12.124.01.100", true},
{"jozo", "BUS_011-358", "99.124.01.011", false},
{"nora", "B09_154-358", "9.124.01.154", false},
{"xantipa", "B01_001-358", "1.124.01.001", false},};
private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
switch (column) {
case 3:
return true;
default:
return false;
}
}
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
public MyFrame() {
tabs = new JTabbedPane();
panel1 = new JPanel();
runButton = new JButton("go!");
runButton.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
//
}
});
panel1.add(runButton);
tabs.addTab("first tab", panel1);
JTable table = new JTable(model);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton("A button"));
buttonPanel.add(new JLabel("Some description for the awesome table below "));
buttonPanel.add(new JButton("another button"));
JScrollPane tablePanel = new JScrollPane(table);
JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.add(buttonPanel, BorderLayout.NORTH);
container.add(tablePanel, BorderLayout.CENTER);
tabs.addTab("Preview", container);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tabs);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame();
}
});
}
}
EDIT 2nd. e.g.
from code (included your idea about to fill data to model)
import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class MyFrame extends JFrame {
private JPanel panel1;
private JTabbedPane tabs;
private JButton runButton;
private JFrame frame = new JFrame();
private String[] columnNames = {"Nama", "Nim", "IP", "Hapus Baris ke"};
private Object[][] data = {
{"igor", "B01_125-358", "1.124.01.125", "true"},
{"lenka", "B21_002-242", "21.124.01.002", "true"},
{"peter", "B99_001-358", "99.124.01.001", "false"},
{"zuza", "B12_100-242", "12.124.01.100", "true"},
{"jozo", "BUS_011-358", "99.124.01.011", "false"},
{"nora", "B09_154-358", "9.124.01.154", "false"},
{"xantipa", "B01_001-358", "1.124.01.001", "false"},};
private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
switch (column) {
case 3:
return true;
default:
return false;
}
}
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
public MyFrame() {
tabs = new JTabbedPane();
panel1 = new JPanel();
runButton = new JButton("go!");
runButton.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
List<String[]> data = new LinkedList<String[]>();
for (int i = 1; i < 10; i++) {
data.add(new String[]{"entry1", "value1", "value2", "value3"});
}
for (String[] datarow : data) {
model.addRow(Arrays.copyOf(datarow, datarow.length, Object[].class));
}
}
});
panel1.add(runButton);
tabs.addTab("first tab", panel1);
JTable table = new JTable(model);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton("A button"));
buttonPanel.add(new JLabel("Some description for the awesome table below "));
buttonPanel.add(new JButton("another button"));
JScrollPane tablePanel = new JScrollPane(table);
JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.add(buttonPanel, BorderLayout.NORTH);
container.add(tablePanel, BorderLayout.CENTER);
tabs.addTab("Preview", container);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tabs);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame();
}
});
}
}
Following the footsteps of mKorbel I ended up doing some debugging. I am providing it here in case others run into the same problem.
It felt quite odd that the table looked OK when the underlying DataModel was supplied a data matrix upon initialisation
private DefaultTableModel model = new DefaultTableModel(data, columnNames)
but it would not show up properly when created with the empty constructor
private DefaultTableModel model = new DefaultTableModel()
and adding rows later with model.addRow(Object[] row);
I started look through the source code, and it turns out with the empty constructor the number of rows and columns for the model (private fields) is initiated to 0 and not updated properly afterwards. I noticed this while debugging since my tables had the dimension of 1370 x 0, which of course does not display properly.
Since I do not want to hardcode the number of rows/cols in advance the best course of action was to convert my "rows" to a matrix and provide the data to the model via constructor (much like mKorbel did). Here comes the fun part, if you want to supply the data then you need to supply the column names as well. THe fact that you have to have column names is counter-intuitive (IMHO), what happens if you dont have/need headers? The data is already in a table form, so I dont understand why column names is so important.
At any rate the following code renders the table at least:
String[] colNames = new String[data[1].length];
for(int i=0; i<colNames.length; i++)
colNames[i] = "C" + i;
DefaultTableModel model = new DefaultTableModel(data,colNames){
#Override
public boolean isCellEditable(int row, int column){
return false;
}};
I am accepting this because it points to the origin of the problem, but I would not be able to pinpoint the problem without mKorbel's answer, so give the upvote to his/her answer :)

JTable, JComboBox - problems in showing JComboBox in second column

I have written this simple program:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class JcomboboxJtableDemo extends JPanel
implements ActionListener {
private DefaultTableModel tableModel;
JTable table = new JTable (tableModel);
private JScrollPane scrollpaneTable = new JScrollPane( table );
private JPanel PaneBottoniTabella = new JPanel( );
public JcomboboxJtableDemo() {
super(new BorderLayout());
String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
JComboBox comboBox = new JComboBox(petStrings);
comboBox.setSelectedIndex(4);
tableModel = CreateTableModel();
tableModel.insertRow( 0, new Object[] {"Header col1", ""} );
tableModel.insertRow( 0, new Object[] {petStrings[0], ""} );
tableModel.insertRow( 0, new Object[] {petStrings[1], ""} );
tableModel.insertRow( 0, new Object[] {petStrings[2], ""} );
tableModel.insertRow( 0, new Object[] {petStrings[3], ""} );
tableModel.setValueAt("Header col2", 0, 1);
DefaultCellEditor editor = new DefaultCellEditor(comboBox);
table.getColumnModel().getColumn(0).setCellEditor(editor);
table.getColumnModel().getColumn(1).setCellEditor(editor);
//Lay out the demo.
add(comboBox, BorderLayout.PAGE_START);
add(table, BorderLayout.PAGE_END);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
}
private final DefaultTableModel CreateTableModel () {
DefaultTableModel modello = new DefaultTableModel( new Object[] { "Col1","Col2" }, 0 ) {
#Override
public boolean isCellEditable(int row, int column) {
return true;
}
};
table.setModel(modello);
return modello;
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("ComboBoxDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new JcomboboxJtableDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
I you try to run it you will see that there is a problem in showing correctly the JComboBox components in the second column, in the first column the are correctly shown and you can see each selected item as set in the code, instead in the second column there are some problems: none on the relative cell.
Could you tell me why? How can I solve the problem?
Thanks
You're using the same JComboBox component for both ColumnModel columns which in turn share the same ComboBoxModel. Any change in the selected item from one column will be reflected in the other column. Create a second combobox
JComboBox comboBox2 = new JComboBox(petStrings);
...
table.getColumnModel().getColumn(1).setCellEditor(editor2);
so that any changes can occur independently in either column.

Details JPanel with variable length fields

I'm trying to create a Panel which contains N rows and 2 columns, where the first column is a label with a variable length but within certain limits (it varies length according to Language), while the second column contains fields with possibly very long text.
I've tried with GridBagLayout using NetBeans however the results are messy when scaling the panel or adding very long fields..
below a screenshot of the JPanel to see what I mean:
I'd like the left column to be spaced from the left border, the first column to never resize to a smaller value than it's longest label (labels must always be readable), while the second column should visualize up to its available horizontal space and then show dots (and not crop the text).
What's also boring is that although I defined NorthWest for orientation the Panel shows vertically aligned in the center
EDIT: I have used TableColumnAdjuster to use table rows instead of labels for my values so that I can select the values with the mouse.
I still have the rows however fit the length of the text and not of the containing Panel:
public class TestPanel extends JPanel
{
private static ArrayList<String> columnNames = new ArrayList<>();
static JTable table;
MyTableModel myTableModel = new MyTableModel();
static class MyTableModel extends AbstractTableModel
{
private String[] columnNames =
{
"Name", "Value"
};
private Object[][] data =
{
{ "Subject", "very very very very very very very very very very very very very very very very long subject"},
{ "Date", "" },
{ "Location", "" },
{ "Status", "" },
{ "Notes", "" }
};
#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)
{ return false; }
#Override
public void setValueAt(Object value, int row, int col)
{ }
}
public TestPanel()
{
table = new JTable(myTableModel);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumnAdjuster tca = new TableColumnAdjuster(table);
tca.adjustColumns();
JPanel panel = new JPanel(new GridBagLayout());
panel.add(table);
GridBagConstraints constraints = new GridBagConstraints();
constraints.weighty = 1.0;
constraints.fill = GridBagConstraints.VERTICAL;
panel.add(Box.createGlue(), constraints);
add(panel);
}
public static void main(String args[])
{
JFrame frame = new JFrame();
frame.setContentPane(new TestPanel());
frame.setSize(300, 800);
frame.setVisible(true);
}
}
while TableColumnAdjuster is from TableColumnAdjuster.. what I get is still as below
You probably have an incorrect usage of the GridBagLayout.
To push all the content to the top, either wrap the GridBagLayout panel into another panel (like a BorderLayout panel in the NORTH position) or add a component at the bottom which takes all the extra space
For all components in the first column, set weightx to 0 while on the second one, set it to something bigger than 0.
To add some space between the left border and the labels, simply use insets
Here is an example illustrating this:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.Random;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Gridbag {
public void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
Random random = new Random();
for (int i = 0; i < 10; i++) {
String label = "Label " + (i + 1);
StringBuilder fieldValue = new StringBuilder();
int r = 1 + random.nextInt(4);
for (int j = 0; j < r; j++) {
fieldValue.append("Some long value that may be very long in some cases");
}
addField(panel, label, fieldValue.toString());
}
GridBagConstraints constraints = new GridBagConstraints();
constraints.weighty = 1.0;
constraints.fill = GridBagConstraints.VERTICAL;
panel.add(Box.createGlue(), constraints);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
private void addField(JPanel panel, String label, String fieldValue) {
GridBagConstraints labelGBC = new GridBagConstraints();
labelGBC.insets = new Insets(0, 5, 0, 5);
labelGBC.anchor = GridBagConstraints.EAST;
GridBagConstraints fieldGBC = new GridBagConstraints();
fieldGBC.gridwidth = GridBagConstraints.REMAINDER;
fieldGBC.weightx = 1.0;
fieldGBC.anchor = GridBagConstraints.WEST;
panel.add(new JLabel(label), labelGBC);
panel.add(new JLabel(fieldValue), fieldGBC);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Gridbag().initUI();
}
});
}
}
One way to achieve it is to use 3 panels in a 'nested layout'. The panels would be laid out as follows.
Uses BorderLayout for the outer panel, it contains panels 2 & 3.
Uses a single column GridLayout - put in BorderLayout.LINE_START
Uses a single column GridLayout - put in BorderLayout.CENTER
You could use a JTable with two columns and a TableColumnAdjuster or a TableCellRenderer in order to adjust the width of the columns to the longest content.

Categories

Resources