make Jtable non-editable [duplicate] - java

This question already has answers here:
How to make a JTable non-editable
(7 answers)
Closed 9 years ago.
I have a table which is clickable but when I double click, instead of doing what it is told, it goes editing mode. I have tried isCellEditable() method with no success. Maybe I am doing something wrong?
Here is the code:
public AllResultsFromDB(GUI x) {
final Vector columnNames = new Vector();
final Vector data = new Vector();
for (int i = 1; i <= columns; i++) {
columnNames.addElement(metad.getColumnName(i));
}
// This loop gets the data inside the rows
while (rset.next()) {
final Vector row = new Vector(columns);
for (int i = 1; i <= columns; i++) {
row.addElement(rset.getObject(i));
}
data.addElement(row);
//data.addElement(b);
}
rset.close();
stmt.close();
connection.close();
// Create table with results
final JTable table = new JTable(data, columnNames) {
public boolean isCellEditable() {
return false;
}
public Class getColumnClass(int column) {
for (int row = 0; row < getRowCount(); row++) {
Object obj = getValueAt(row, column);
if (obj != null) {
return obj.getClass();
}
}
return Object.class;
}
};
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.SOUTH);
table.addMouseListener(new MouseListener() {
public void mousePressed(MouseEvent e) {
//System.out.println(table.getSelectedRow());
}
public void mouseReleased(MouseEvent e) {
//System.out.println(table.getSelectedRow());
}
public void mouseEntered(MouseEvent e) {
//System.out.println(table.getSelectedRow());
}
public void mouseExited(MouseEvent e) {
//System.out.println(table.getSelectedRow());
}
public void mouseClicked(MouseEvent e) {
if(e.getClickCount()==2){
System.out.println(table.getSelectedRow());
}
}
});

The method isCellEditable that you tried to override has a different signature which is:
public boolean isCellEditable(int row, int column)
How could you specify which specific cell otherwise? Next time adding an #Override annotation should help spotting this.
In any case this is not the correct way to make a JTable non-editable. The correct way is to provide a custom AbstractTableModel which returns false with its isCellEditable method. The JTable shouldn't decide if a cell is editable, it's duty of the model to decide it: indeed the isCellEditable method of JTable just asks to its model if the cell is editable. The JTable shows the content, nothing more, it's the model that decides and contains the data.
Since you seem to use just basic features of a JTable you don't need to roll your own table model, a DefaultTableModel will work for you, and you can overrite its isCellEditable method.

You're not that far off.
The actual method isCellEditable takes two parameters, so your method isn't actually overriding anything.
See: http://docs.oracle.com/javase/7/docs/api/javax/swing/table/TableModel.html#isCellEditable%28int,%20int%29
for the correct method.

Related

JTable prevent Strings

How can I prevent strings in a JTable and allow and show only numbers?
like for example I press "a" on my keyboard I won't not even that "a" will be displayed in the JTable cell. literally nothing should happen unless a user types in a number. so how can I prevent even not showing "a" ?
I had a similar issue some time ago and solved by validating with an KeyListener. This is a dirty way of doing it, but it works. The only weakness is if you're trying to edit a lot of cells quickly if you're a fast writer. Anyhow, here's the code that worked for me. I've added some commentary, but in short; we're overriding the normal validation and check with a TextField KeyListener if the given key is the one we allow in the TextField. If we allow the key, we enable TextField editing, if not, we turn it off to prevent the character being printed in the TextField. I hope this helps you.
UPDATE 1:
adding a celleditor on the TestField to prevent premature data insertion.
public class TableValidation extends JFrame
{
public static void main(String args[])
{
TableValidation x = new TableValidation();
x.setVisible(true);
}
JPanel topPanel;
JTable table = new JTable();
JScrollPane scrollPane;
String[] columnNames;
String[][] dataValues;
public TableValidation()
{
this.setTitle("JTable Cell Validation");
this.setDefaultCloseOperation (EXIT_ON_CLOSE);
this.setSize(300,112);
// make our panel to tin the table to
topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
this.getContentPane().add(topPanel);
// set some initial data for the table
columnNames = new String[] {"Anything" ,"Numbers only"};
dataValues = new String[][] { {"h4x0r","1337"} };
table.setRowHeight(50);
table.setModel( new CustomTableModel(dataValues, columnNames) );
TableColumn tableColumn = table.getColumnModel().getColumn(1); // apply our validation to the 2nd column
JTextField textfield = new JTextField(); // the textbox to which we test our validation
// setup our validation system. were passing the textfield as out celleditor source
tableColumn.setCellEditor(new MyCellEditor(textfield));
table.setCellSelectionEnabled(true);
scrollPane = new JScrollPane(table);
topPanel.add(scrollPane,BorderLayout.CENTER);
textfield.addKeyListener(new KeyAdapter()
{
public void keyTyped(KeyEvent e)
{
// check what keys can pass our test
if (textfield.isFocusOwner())
if (e.getKeyChar() != KeyEvent.VK_BACK_SPACE) // we allow backspace, obviously
if (!Character.isDigit(e.getKeyChar())) // if key is not a digit.. cancel editing
{
// when it detects an invalid input, set editable to false. this prevents the input to register
textfield.setEditable(false);
textfield.setBackground(Color.WHITE);
return;
}
textfield.setEditable(true);
}
});
}
}
class MyCellEditor extends AbstractCellEditor implements TableCellEditor
{
private static final long serialVersionUID = 1L;
private JTextField textField;
public MyCellEditor(JTextField textField)
{
this.textField=textField;
}
#Override
public boolean isCellEditable(EventObject e)
{
if (super.isCellEditable(e)) {
if (e instanceof MouseEvent) {
MouseEvent me = (MouseEvent) e;
return me.getClickCount() >= 2;
}
if (e instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) e;
return ke.getKeyCode() == KeyEvent.VK_F2;
}
}
return false;
}
#Override
public Object getCellEditorValue()
{
return this.textField.getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
this.textField.setFont(table.getFont());
this.textField.setText(value.toString());
return this.textField;
}
}
class CustomTableModel extends DefaultTableModel
{
CustomTableModel(String[][] data,String[] names)
{
super(data, names);
}
// we always pass true in our tablemodel so we can validate somewhere else
public boolean isCellEditable(int row,int cols)
{
return true;
}
}

JTable reseting to original state after minimize/maximize

I've got a Swing screen that opens with a JTable full of itenms and a JList that is empty. After an event from a button I move the itens from JTable to JList, making JTable empty and JList full of items as I desire. But I've got a weird problem that JTable goes back to its original state with all the items again when the frame is minimized and then maximized.
It should not happen as I remove the items from the array that keeps the JTable values. I used sysout to watch on console the array size as the items are being removed and I am sure in the end its size has come to zero.
Plus, I put break points in the getXXX that retrieves the array value to JTable and a repaint() method I put myself to overwrite its original and I got no break point pause of any of them.
So....I don't know where it is getting the value to reset to original state!
Finally, I've just noticed it happens when the table's area is clicked, so change the JFrame to a JDialog where there is no minimize/maximize button would not solve the problem at all.
I don't know if some code would help but in any case, I've got an init method just to initialize the JTable.
private void initTable(Object rowData[][]) {
documents = rowData;
dataModel = new DataModel(rowData, COLUMNS);
scrollPane = new JScrollPane();
scrollPane.setBounds(13, 188, 300, 148);
contentPane.add(scrollPane);
table = new JTable(dataModel) {
#Override
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
super.changeSelection(rowIndex, columnIndex, true, false);
}
};
scrollPane.setViewportView(table);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getColumnModel().getColumn(0).setPreferredWidth(30);
table.getColumnModel().getColumn(1).setPreferredWidth(260);
table.setCellSelectionEnabled(true);
table.setRowSelectionAllowed(false);
table.setColumnSelectionAllowed(false);
ListSelectionModel cellSelectionModel = table.getSelectionModel();
cellSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
int selectedRow = table.getSelectedRow();
int selectedColumn = table.getSelectedColumn();
if (selectedRow >= 0) {
if (selectedColumn == 0) {
Boolean valorCol= (Boolean) documents[selectedRow][0];
if (valorCol== true) {
documents[selectedRow][0] = false;
}
else {
documents[selectedRow][0] = true;
}
}
}
}
table.clearSelection();
}
});
}
_______EDITING_______
The way I remove the items are made of a List not the original array. After the procedure that moves the items from the JTable, I call the method above but this time the list is empty. Here it goes the "missing code"
After moving all the items...
Object[][] documentsMoved = buildTableDataFromList(myVO.getDocuments());
initTable(documentsMoved );
private Object[][] buildTableDataFromList(List<MyVO> list) {
Object[][] retorno = new Object[list.size()][COLUMNS.length];
for (int i = 0; i < list.size(); i++) {
MyVO vo = lista.get(i);
retorno[i][CHECK_COL] = Boolean.TRUE;
retorno[i][DOC_COL] = vo.getFileName();
}
return retorno;
}
It appears you are changing the dataVector of the DataModel directly. This is not the way you should be doing things. What you should do is change cell values through the interface of DataModel (using model indexes) or through the JTable interface (using view indexes).
So my advice would be to change your program to do what I just told. However if you insist on working the way you are you can signal the DataModel about changes in its underlying dataVector, if your DataModel extends DefaultTableModel which I assume it does or implements the AbstractTableModel interface. Call documents.fireTableDataChanged(); after your changes to the whole model, or more granular when changing cells using documents.fireTableCellUpdated(rowModelId,colModelId);.
Another mistake you are making is mixing up view indexes and model indexes. These can be different if rows are sorted and/or columns moved around in your table. Before indexing the model with indexes returned from the view, you should be converting these view indexes with JTable.convertRowIndexToModel and JTable.convertColumnIndexToModel.
Applying this to your selectionListener:
What you should be doing:
cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
int selectedRow = table.getSelectedRow();
int selectedColumn = table.getSelectedColumn();
if (selectedRow >= 0) {
if (table.convertColumnIndexToModel(selectedColumn) == 0) {
Boolean valorCol = (Boolean) table.getValueAt(selectedRow,selectedColumn);
if (valorCol == true) {
table.setValueAt(Boolean.FALSE,selectedRow,selectedColumn);
}
else {
table.setValueAt(Boolean.TRUE,selectedRow,selectedColumn);
}
}
}
}
table.clearSelection();
}
});
If you insist on working the way you are:
cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
int selectedRow = table.getSelectedRow();
int selectedColumn = table.getSelectedColumn();
if (selectedRow >= 0) {
int rowModelId = table.convertRowIndexToModel(selectedRow);
int colModelId = table.convertColumnIndexToModel(selectedColumn);
if (colModelId == 0) {
Boolean valorCol= (Boolean) documents[rowModelId][0];
if (valorCol== true) {
documents[rowModelId][0] = false;
}
else {
documents[rowModelId][0] = true;
}
dataModel.fireTableCellUpdated(rowModelId,0);
}
}
}
table.clearSelection();
}
});
Alas I think with your understanding of swing and JTable, there are likely more problems in your code.

Show Customer's Data in Jtable using Java

I want show customer details from a MySQL database in a JTable, but I don't see any result in my panel when I click the "show" button.
This is the method to add the table to the JScrollPane:
void addTable()
{
for(int i=0 ; i<myTableModel.getColumnCount();i++)
{
myTableModel.getColumnName(i);
}
showCustomers();
table.setModel(myTableModel);//mytablemodel is a object from MyTableModel Class
scrollPane.add(table); //was on another part of program but i edit it for helping to answers
panel_show.add(scrollPane);
}
And here is MyTableClass, implementing TableModel, with a new method, addCustomer. addCustomer will add a Customer to the CustomerList. I am trying ArrayList for first time to show Customer data but it doesn't work.
Also, columnName will make the table headers with the column names from the database.
public class MyTableModel implements TableModel
{
private ArrayList<Customer> customerList;
private String[] columnName =
{"id", "name", "family", "idc", "age", "sex", "balance", "tel", "haveFamily", "population"};
#Override
public int getRowCount()
{
//return customerList.size();
return 1;
}
#Override
public int getColumnCount()
{
return 10;
}
#Override
public String getColumnName(int columnIndex)
{
return columnName[columnIndex];
}
#Override
public Class<?> getColumnClass(int columnIndex)
{
if(columnIndex == 0)
return Integer.class;
return String.class;
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return false;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex)
{
if(columnIndex == 0)
return customerList.get(rowIndex).getId();
else if(columnIndex == 1)
return customerList.get(rowIndex).getName();
else if(columnIndex == 2)
return customerList.get(rowIndex).getFamily();
else if(columnIndex == 3)
return customerList.get(rowIndex).getIdc();
else if(columnIndex == 4)
return customerList.get(rowIndex).getDate();
else if(columnIndex == 5)
return customerList.get(rowIndex).getSex();
else if(columnIndex == 6)
return customerList.get(rowIndex).getBalance();
else if(columnIndex == 7)
return customerList.get(rowIndex).getTel();
else if(columnIndex == 8)
return customerList.get(rowIndex).isHaveFamily();
else if(columnIndex == 9)
return customerList.get(rowIndex).getPopulation();
else
return null;
}
public void addCustomer(Customer customer)
{
CustomerManager customerManager = new CustomerManager();
customerManager.addCustomer(customer);
customerList.add(customer);
}
The showCustomer method will be open a database connection and create a TableModel with customers, which is then used for the table on my panel.
public void showCustomers()
{
Connection conn = null;
try
{
//String user = "root";
// String pass = null;
//String url = "jdbc:mysql://localhost/estate";
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection("jdbc:mysql://localhost/estate", "root", null);
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * from customer");
//int columnCount = rsmd.getColumnCount();
while (rs.next())
{
myTableModel.addCustomer(new Customer(1,"david","schmidt","0025674433","31","Male","200000","4545552132","true","2");
}//Original Form --> Customer({"id","name","family","idc","age",
// "sex","balance","tel","haveFamily","population"});
}
In MyTableModel I make an addCustomer method and fill the customer data using a ResultSet. Is it needed?
My question: How can I show my Customers using a JTable?
After some fiddling I now also have a problem with myTableModel.addCustomer(rs.getInt(), ...). The error I am getting is this:
Error in addCustomer,Duplicate entry '0' for KEY PRIMARY
However, I don't have a customer with an ID of 0.
When displaying a JTable you first add the table to a scroll pane and then you add the scroll pane to a panel.
When adding a component to a visible GUI you need to make sure the layout manager has been invoked so that the component has a size and location.
So the basic code would be:
table.setModel(...);
JScrollPane scrollPane = new JScrollPane( table );
panel.add( scrollPane );
panel.revalidate();
panel.repaint();
The other approach is the create an empty table and add the scroll pane to the GUI when you first create the GUI. Then all the code you need is:
table.setModel(...);
Edit:
You question is about displaying a table in a panel, when you click a button. So that is ALL the SSCCE should do. Where the data comes from is irrelevant, so posting code dealing with a database is completely unnecessary, because we can't execute the code. A custom TableModel is irrelevant to the real question.
Here is a simple SSCCE that uses my second suggestion of updating an existing table with a new model. Every time you click the button the number of columns changes. This simulates getting new data from somewhere.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class RefreshSSCCE extends JPanel
{
private JTable table = new JTable();
private int columns = 3;
public RefreshSSCCE()
{
setLayout( new BorderLayout() );
JButton refresh = new JButton( "Refresh Data" );
add(refresh, BorderLayout.NORTH);
refresh.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
refreshData();
}
});
add(new JScrollPane(table), BorderLayout.CENTER);
}
private void refreshData()
{
DefaultTableModel model = new DefaultTableModel(5, columns++);
table.setModel( model );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Refresh SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new RefreshSSCCE() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
See how easy that code is to understand? The code is complete and in one class. It can easily be copied and pasted so others can test the code.
When you simplify the problem then solution is usually much easier. That is why you take the time to create a SSCCE. Even if the SSCCE doesn't work the way you want, we only have a couple of lines of code to look at to understand what you are attempting to do. There is no need to complicate the question with SQL code.
Once you get the simple code working you then modify the refreshData method to get real data. That is what I mean by hardcoding data. There is no need for a dynamic query of the database to demonstrate your problem of displaying a table in a panel.

Button in JTable cell not click-able

I have a jtable with the first column having jbuttons. However when i try to click the button nothing happens. Hovering over the button also doesn't change it's shade to show that it's clickable..
I am running this from within a Java Applet.
I am using the Button Column Class from here:
http://www.camick.com/java/source/ButtonColumn.java
and here is the code i inserted myself
tablemodel = new DefaultTableModel();
//PnlThinClientTable.COLUMNS is an array of strings with the titles of the columns
tablemodel.setColumnIdentifiers(PnlThinClientTable.COLUMNS);
JTable table = new JTable(tablemodel);
table.setEnabled(false);
table.setDefaultRenderer(table.getColumnClass(5), new CustomTblCellRenderer());
table.setBackground(Color.WHITE);
Action wakeUpRow = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e){
JTable table = (JTable)e.getSource();
int modelRow = Integer.valueOf( e.getActionCommand() );
System.out.println("Action Performed");
}
};
// Main.hm_language.get(Language.WAKE_ON_LAN) returns the title of the column i'm interested in
table.getColumn(Main.hm_language.get(Language.WAKE_ON_LAN)).setCellRenderer(new ButtonColumn(table,wakeUpRow,0));
table.getColumn(Main.hm_language.get(Language.WAKE_ON_LAN)).setCellEditor(new ButtonColumn(table, wakeUpRow, 0));
Thanks to #alex2410 for the solution
I had to make sure the cell was Editable
this can be done by either extending the Table upon declaration and overriding the isCellEditable(int row, int col): boolean method,
or in my case I overrode isCellEditable(EventObject e):boolean in the Cell Editor which I apply to the column,
hence the snippet within the Cell Editor I am using would be
#Override
public boolean isCellEditable(EventObject e){
return true;
}
This is as all cells to which the editor is applied need to be editable, as they are all buttons in my case.
Answering to the comment of "how to make 1st column editable" here's how
class MyTableModel extends AbstractTableModel {
public boolean isCellEditable(int row, int col) {
if (col == 1) {
return true;
} else {
return false;
}
}
}
Anyway I leave How to Use Tables Documentation in case it's needed.
And also this post that could help: How to make a table (Jtable) not editable

How to make a JTable non-editable

How to make a JTable non-editable? I don't want my users to be able to edit the values in cells by double-clicking them.
You can override the method isCellEditable and implement as you want
for example:
//instance table model
DefaultTableModel tableModel = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column) {
//all cells false
return false;
}
};
table.setModel(tableModel);
or
//instance table model
DefaultTableModel tableModel = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column) {
//Only the third column
return column == 3;
}
};
table.setModel(tableModel);
Note for if your JTable disappears
If your JTable is disappearing when you use this it is most likely because you need to use the DefaultTableModel(Object[][] data, Object[] columnNames) constructor instead.
//instance table model
DefaultTableModel tableModel = new DefaultTableModel(data, columnNames) {
#Override
public boolean isCellEditable(int row, int column) {
//all cells false
return false;
}
};
table.setModel(tableModel);
table.setDefaultEditor(Object.class, null);
just add
table.setEnabled(false);
it works fine for me.
You can use a TableModel.
Define a class like this:
public class MyModel extends AbstractTableModel{
//not necessary
}
actually isCellEditable() is false by default so you may omit it. (see: http://docs.oracle.com/javase/6/docs/api/javax/swing/table/AbstractTableModel.html)
Then use the setModel() method of your JTable.
JTable myTable = new JTable();
myTable.setModel(new MyModel());
If you are creating the TableModel automatically from a set of values (with "new JTable(Vector, Vector)"), perhaps it is easier to remove editors from columns:
JTable table = new JTable(my_rows, my_header);
for (int c = 0; c < table.getColumnCount(); c++)
{
Class<?> col_class = table.getColumnClass(c);
table.setDefaultEditor(col_class, null); // remove editor
}
Without editors, data will be not editable.
I used this and it worked : it is very simple and works fine.
JTable myTable = new JTable();
myTable.setEnabled(false);
create new DefaultCellEditor class :
public static class Editor_name extends DefaultCellEditor {
public Editor_name(JCheckBox checkBox) {
super(checkBox);
}
#Override
public boolean isCellEditable(EventObject anEvent) {
return false;
}
}
and use setCellEditor :
JTable table = new JTable();
table.getColumn("columnName").setCellEditor(new Editor_name(new JCheckBox()));

Categories

Resources