AbstractTableModel and cell editor - java

The example i have found:
http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm
show how to create a JTable with specified column (button). It works properly, but the my problem is, that i need to use AbstractTableModel instead of DefaultTableModel (as at the example shows).
So i created my own TableModel, which extends AbstractTableModel:
public class TableModel extends AbstractTableModel {
//..
}
and replaced:
DefaultTableModel dm = new DefaultTableModel();
dm.setDataVector(new Object[][] { { "button 1", "foo" },
{ "button 2", "bar" } }, new Object[] { "Button", "String" });
JTable table = new JTable(dm);
for:
JTable table = new JTable(new TableModel());
And then nothing happens, when i will click button at some row. Any suggestions?

Make sure you override AbstractTableModel.isCellEditable method to return true for the column with the button otherwise the editor will not be triggered. This method by default returns false.
Also, make sure you override getColumnName() to return proper name since the sample that you linked tries to find a column with name "Button" to setup the editor.
You may find a Table Button Column implementation by #camickr useful.
This demo model works OK with the editor and the renderer from the linked sample:
public class DemoTableModel extends AbstractTableModel {
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return (columnIndex == 0);
}
#Override
public int getRowCount() {
return 2;
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0:
return "Button";
case 1:
return "Value";
}
return null;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return "Button";
case 1:
return "Value";
}
return null;
}
}

Related

How to stop adding already added value from JCombobox to JTable

I am working on netbeans and creating a swing application. I have created a JComboBox and a JTable. I am able to add value from JComboBox to JTable on a button click but if I repeat the same process the same value is again again added to the table. How to stop adding the existed value of JComboBox.
This is the code of JComboBox
private void populateCombo(){
organizationComboBox.removeAllItems();
for (Organization.Type type : Organization.Type.values()){
organizationComboBox.addItem(type);
}
}
This is the code of JTable
private void populateTable(){
DefaultTableModel model = (DefaultTableModel) organizationTable.getModel();
model.setRowCount(0);
for (Organization organization : organizationDirectory.getOrganizationList()){
Object[] row = new Object[2];
row[0] = organization.getOrganizationID();
row[1] = organization.getName();
model.addRow(row);
}
}
This is the code for my add button
Type type = (Type) organizationComboBox.getSelectedItem();
Organization o = organizationDirectory.createOrganization(type);
if(type.equals(Type.Receptionist)){
o.getSupportedRole().add(new ReceptionistRole());
}else
if(type.equals(Type.Doctor)){
o.getSupportedRole().add(new DoctorRole());
}else
if(type.equals(Type.VaccineManager)){
o.getSupportedRole().add(new VaccineManagerRole());
}else
if(type.equals(Type.LabAssistant)){
o.getSupportedRole().add(new LabAssistantRole());
}else
if(type.equals(Type.Donor)){
o.getSupportedRole().add(new DonorRole());
}else
if(type.equals(Type.Patient)){
o.getSupportedRole().add(new PatientRole());
}
populateTable();
Thanks in advance.
Don't use DefaultTableModel. This class is only for simple cases and demo applications. Simply look here for example of your own model.
So your model will looks like:
public class OrganizationModel extends AbstractTableModel {
protected String[] columnNames;
protected List<Organization> dataVector;
public OrganizationModel(String[] columnNames) {
this.columnNames = columnNames;
dataVector = new ArrayList<Organization>();
}
public String getColumnName(int column) {
return columnNames[column];
}
public boolean isCellEditable(int row, int column) {
return false;
}
public Class getColumnClass(int column) {
return String.class;
}
public Object getValueAt(int row, int column) {
return column == 0? dataVector.get(row).getOrganizationID() : dataVector.get(row).getName();
}
public void addRowWhenNotExist(Organization o) {
if (!dataVector.contains(o)) {
dataVector.add(o);
fireTableRowsInserted(dataVector.size() - 1, dataVector.size() - 1);
}
}
}
For correct working of this example you also need correct definition of methods equals and hashCode for your class Organization.
public class Organization {
// your stuff
public boolean equals(Object another) {
if (another instanceof Organization) {
return getOrganizationID() == ((Organization) another).getOrganizationID();
} else {
return false;
}
}
public int hashCode() {
return getOrganizationID();
}
}

Adding a JButton into a JTable which uses abstract table model

I am trying to add a JButton as the first column on the table I created. I did make a research and couldn't find any solution for the tables that use abstract table model.
Here, I create an object array for each record that has texts and boolean variables to have the table render check boxes. Then those object arrays saved into an ArrayList
Here's my code to create my table data.
public ArrayList<Object[]> setTableData(){
/*
* ItemInfo fields
**********************
* line[0] - ReferenceNo
* line[1] - Quantity
* line[2] - ItemNameDescriptionSKU
* line[3] - Cube
*/
//Setting the data for the table
ArrayList<Object[]> itemList = new ArrayList<>();
for (int i=0; i<this.itemInfo.size();i++){
Object[] tempArray = new Object[7];
tempArray[0] = this.itemInfo.get(i)[1]; //Quantity
tempArray[1] = this.itemInfo.get(i)[2].toUpperCase(); //Item description
tempArray[2] = this.itemInfo.get(i)[3]; //Cube
//This adds charges if the payment type is COD
//To not to write the charge amount for every row
//checks the COD type only at the first record of items
if (i==0 && this.invoice[8].equals("COD"))
tempArray[3] = this.invoice[22]; //Charges if the invoice type is COD, null otherwise
else
tempArray[3] = " ";
tempArray[4] = new Boolean (false); //Loaded
tempArray[5] = new Boolean (false); //Delivered (Will be ignored if pickup)
itemList.add(tempArray);
}
return itemList;
Here's my table model
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
public class TicketTableModel extends AbstractTableModel {
private ArrayList<Object[]> data;
private boolean isDelivery;
private String[] columns;
public TicketTableModel(ArrayList<Object[]> itemInfo, boolean isDelivery){
super();
this.data = itemInfo;
this.isDelivery = isDelivery;
}
#Override
public String getColumnName(int i) {
return this.columns[i];
}
public void setColumns ( String[] columns1 ){
this.columns = columns1;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columns.length;
}
#Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
if (col < 3)
return false;
else
return true;
}
#Override
public void setValueAt(Object value, int row, int col) {
data.get(row)[col] = value;
fireTableCellUpdated(row, col);
}
#Override
public Object getValueAt(int row, int col) {
return this.data.get(row)[col];
}
Take a look at Table Button Column.
This class implements the render/editor needed to make the button functional. You also provide the Action to invoke when the button is pressed.
The type of TableModel is irrelevant. If you want to "show" a button on a JTable, you supply a TableCellRenderer (and probably a TableCellEditor) for the column which is capable of rendering the button based on the values of the column it represents.
This will mean that your TableModel will need to support a column within it's model which represents the button.
Take a closer look at Using Custom Renderers, Using Other Editors and How to Use Tables

Select Value of Checkbox JTable on button click

I have a JTable in which the last column is Checkbox(multiple select). I want to get the values of the rows selected on a particular button click. Only the values which are checked are needed. Any idea regarding this?
Object[] columnNamesTest = {"Request No","Assigned To","Copy Data","Updated Req Number"};
Object[][] rowDataTest = {
{"111111", "ABC",false,""},
{"222222", "XYZ", true,"999999"},
{"333333", "LMN",true,"444444"},
{"444444", "PQR", false,"555555"}
};
DefaultTableModel model = new DefaultTableModel(rowDataTest, columnNamesTest);
JTable table = new JTable(model){
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return String.class;
case 2:
return Boolean.class;
default:
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int column) {
//Only the third column
return column == 2;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
container.add(scrollPane);
I want to get the values of the rows selected on a particular button click.Only the values which are checked are needed.
Simply check the value of third column and get it the desired value from DefaultTableModel.
sample code:
JButton button = new JButton("Show selcted records");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
for (int i = 0; i < model.getRowCount(); i++) {
Boolean value = (Boolean) model.getValueAt(i, 2);// check state
if (value) {
System.out.println(model.getValueAt(i, 1));// second column value
}
}
}
});

Controlled editing of a row selection in JTable

I have a JTable displaying rows from an SQL database. The table is relatively small (only 4 columns and up to 1000 rows).
I would like to give the user the opportunity to edit any cells in the table but want to avoid restricting it so much so that they must use an edit dialog box (this makes for far easier error checking and validation but is less intuitive)
I have tried a few different ways of controlling edit selections using the valueChanged method of my JTable but haven't had much luck.
I would like each row to be edited and written to the database at the conclusion of editing. I would like that once a cell has been clicked to start the editing of that row, no other rows can be selected until the user has finished editing the row (other rows are grayed out). After editing each cell and pressing enter, the edit selection should jump to the next column in the same row.
Can anyone give pointers on how I can achieve this?
// Create table with database data
table = new JTable(new DefaultTableModel(data, columnNames)) {
public Class getColumnClass(int column) {
for (int row = 0; row < getRowCount(); row++) {
Object o = getValueAt(row, column);
if (o != null){
return o.getClass();
}
}
return Object.class;
}
#Override
public boolean isCellEditable(int row, int col){
return true;
}
#Override
public boolean editCellAt(int row, int column) {
boolean ans = super.editCellAt(row, column);
if (ans) {
Component editor = table.getEditorComponent();
editor.requestFocusInWindow();
}
return ans;
}
#Override
public void valueChanged(ListSelectionEvent source) {
super.valueChanged(source);
if (table!=null)
table.changeSelection(getSelectedRow(), getSelectedColumn()+1, false, false);
}
};
Edit - custom cell editor with table pointer seems to be a start
public class ExchangeTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTable table;
JComponent component = new JTextField();
public ExchangeTableCellEditor(JTable table) {
this.table = table;
}
public boolean stopCellEditing() {
boolean ans = super.stopCellEditing();
//now we want to increment the cell count
table.editCellAt(table.getSelectedRow(), table.getSelectedColumn()+1);
return ans;
}
#Override
public void cancelCellEditing() {
//do nothing... must accept cell changes
}
#Override
public Object getCellEditorValue() {
return ((JTextField)component).getText();
}
#Override
public Component getTableCellEditorComponent(JTable arg0, Object value,
boolean arg2, int arg3, int arg4) {
((JTextField)component).setText((String)value);
return component;
}
}
The default renderer and editor is typically adequate for most data types, but you can define custom renderers and editors as needed.
Addendum: I'm unfamiliar with the approach shown in your fragment. Instead, register a TableModelListener with your model, as shown below, and update the database with whatever granularity is warranted. See also How to Use Tables: Listening for Data Changes.
Addendum: #kleopatra is correct about your TableCellEditor. One convenient way to notify listeners is to invoke the super implementation, as shown here. Note that the delegate invokes fireEditingStopped().
/** #see https://stackoverflow.com/questions/9155596 */
public class NewJavaGUI extends JPanel {
private final JTable table;
public NewJavaGUI() {
String[] colNames = {"C1", "C2", "C3"};
DefaultTableModel model = new DefaultTableModel(colNames, 0) {
#Override
public boolean isCellEditable(int row, int col) {
// return your actual criteria
return true;
}
#Override
public Class getColumnClass(int col) {
// return your actual type tokens
return getValueAt(0, col).getClass();
}
};
// Add data; note auto-boxing
model.addRow(new Object[]{"A1", "A2", 42});
model.addRow(new Object[]{"B1", "B2", 42d});
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
// DML as indicated
}
});
table = new JTable(model);
this.add(table);
}
private void display() {
JFrame f = new JFrame("NewJavaGUI");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new NewJavaGUI().display();
}
});
}
}
The behaviour you mention can be achieved by forcing your table to start editing again.
First make sure you now yourRow and Column and that you add your own tablecelleditor that extands from the AbstractCellEditor
then add this to your stopCellEditing method:
EventQueue.invokeLater(new Runnable()
{
public void run()
{
yourTable.editCellAt( yourRow, yourColumn+1);
}
});

Adding TableModelListener to AbstractTableModel

I've faced an issue in adding TableModelListener to AbstractTableModel. The program stops working and the JFrame doesn't response for any button-clicking or even closing the JFrame.
What I want is to make a JButton enabled iff the number of rows in myTable is equal or more than 2 rows.
Here is my code ...
My custom Table:
public class MyTable extends JPanel
{
public Main main;
public ArrayList<MyData> lstData;
public JTable table;
public MyTableModel model;
// ...
public MyTable(ArrayList<MyData> lstData, Main main)
{
this.lstData = lstData;
this.main = main;
model = new MyTableModel(lstData);
table = new JTable(model);
// ...
}
// ...
public int getTableSize()
{
return model.getRowCount();
}
public TableModel getModel()
{
return model;
}
public class MyTableModel extends AbstractTableModel
{
protected String[] columnNames = new String[ ] {"#","Name", "Phone Number"};
protected ArrayList<MyData> lstData;
protected Class[] types = new Class[]{String.class, String.class, String.class};
public MyTableModel(ArrayList<MyData> lstData)
{ this.lstData = lstData; }
public void SetData(ArrayList<MyData> lstData)
{ this.lstData = lstData; fireTableDataChanged(); }
#Override
public String getColumnName(int columnIndex)
{ return columnNames[columnIndex]; }
#Override
public Class getColumnClass(int columnIndex)
{ return types[columnIndex]; }
public Object getValueAt(int row, int column)
{
if (row < 0 || row > lstData.size()) return null;
MyData obj = lstData.get(row);
switch(column)
{
case 0: return obj.getID();
case 1: return obj.getName();
case 2: return obj.getPhoneNumber();
default: return null;
}
}
public int getRowCount() { return lstData.size(); }
public int getColumnCount() { return columnNames.length; }
}
}
Main class:
public class Main extends JFrame implements TableModelListener
{
public static ArrayList<myData> lstData;
public static MyTable table;
public static JButton myButton;
public Main()
{
// ...
table = new MyTable(lstData, this);
table.getModel().addTableModelListener(this);
myButton = new JButton();
myButton.setEnabled(false);
// ...
}
// ...
public void tableChanged(TableModelEvent e)
{
int firstRow = e.getFirstRow();
int lastRow = e.getLastRow();
int mColIndex = e.getColumn();
switch(e.getType())
{
case TableModelEvent.INSERT:
if(table.getTableSize() >= 2) myButton.setEnabled(true);
else myButton.setEnabled(false);
break;
case TableModelEvent.DELETE:
if(table.getTableSize() >= 2) myButton.setEnabled(true);
else myButton.setEnabled(false);
break;
}
}
}
Could you help me to solve this issue? Thanks in advance.
EDIT:
The GUI stop responding only if I add or delete elements from the table.
EDIT2:
No errors or exceptions are thrown after I add elements to the table, it's just freezing the gui with no response
basic tutorial about TableModelListener here or here or here
best would be camickr Table Cell Listener that implements deepest funcionalities for Listening in the TableCell
In your MyTableModel class, remove the following line:
protected TableModel model = this;
And also remove the following methods:
public void setModel(TableModel model){
this.model = model;
}
public TableModel getModel() {
return model;
}
You are already implementing a custom table model, there is no need to create that self reference inside of it. When your class is getting instantiated the this variable is not fully initialized and I suspect that is what is causing problems for you. But in any case the code is definitely not needed. Also, in your MyTable class I would recommend changing the getModel() function to defer to your wrapped table variable. Like so:
public TableModel getModel() {
return model.getModel();
}
Thank you guys for your help, I solve this issue by modifying the tableChanged method:
public void tableChanged(TableModelEvent e)
{
if(table.getTableSize() >= 2) myButton.setEnabled(true);
else myButton.setEnabled(false);
}

Categories