I've run into a very strange issue. I wrote a model for a table and for the most part it works perfect. When I update the row data via the setValueAt function it works and the data in the ArrayList is updated and complete. But when i run the getTotalPay function the same array is empty and i get a null value exception.
I've rewrote the code a number of different ways and tried a couple of different approaches to the problem but the problem persists. I know i've done something wrong i just cannot figure out what the problem is. After search the net and not finding a solution i'm posting this.
Things i've tried are replacing the variable, putting the data into two different variables.
Here is the model
public class WeeklyWagesModel extends AbstractTableModel {
private String defaultValue = "Click to edit";
private String[] headings = { "Date From", "Date To", "Wages", "Pay Date" };
private ArrayList<String[]> theData = new ArrayList<String[]>();
public WeeklyWagesModel() {
theData.add(createDefaultRow());
}
#Override
public int getColumnCount() {
return headings.length;
}
public String getColumnName(int col) {
return headings[col];
}
#Override
public int getRowCount() {
return theData.size();
}
#Override
public Object getValueAt(int row, int col) {
return theData.get(row)[col];
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
theData.get(row)[col] = String.valueOf(value);
if (row == (theData.size() - 1)) {
theData.add(createDefaultRow());
}
fireTableDataChanged();
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public ArrayList<String[]> getData() {
return theData;
}
public String getTotalPay() {
System.out.println("Total Pay: " + theData.size());
BigDecimal total = BigDecimal.ZERO;
for (String[] eachRow : theData) {
if (StringUtils.isNumeric(eachRow[2])) {
total.add(new BigDecimal(eachRow[2]));
}
}
return NumberFormat.getCurrencyInstance().format(total);
}
public String getTotalWeeks() {
return "";
}
private String[] createDefaultRow() {
String[] newRow = new String[headings.length];
for (int i = 0; i < newRow.length; i++) {
newRow[i] = defaultValue;
}
return newRow;
}
}
Related
I'm looking for a way to make data entries for a table from data collected from a SQL database. I have the code made for grabbing the data from the database but I need help with turning that data into table entries
First create an object to represent each row in the table.
public class MyData {
private String name;
private String desc;
//add getters/setters
}
Then you should create a table model
public class MyTableModel extends AbstractTableModel {
List<MyData> list = new ArrayList<>();
public void addRow(MyData data) {
list.add(data);
fireTableRowsInserted(list.size()-1, list.size()-1);
}
//then fill in the required method
public String getColumnName(int col) {
switch (col) {
case 0:
return "Name";
case 1:
return "Description";
}
return "";
}
public int getRowCount() {
return list.size();
}
public int getColumnCount() {
return 2; //or however many columns you need
}
public Object getValueAt(int row, int col) {
MyData data = list.get(row);
if (col == 0) {
return data.getName();
} else if (col == 1) {
return data.getDesc();
}
return null;
}
}
Then use that model in your table;
MyTableModel tableModel = new MyTableModel();
JTable table = new JTable(tableModel);
Then you you can read data from the database you just have to call
tableModel.add(data);
this is my TableModel:
public class ScheduledRecordsTableModel extends AbstractTableModel {
private String[] headers = {"Interpret", "Titel"};
private List<ScheduledRecord> scheduledRecords;
public ScheduledRecordsTableModel(List<ScheduledRecord> recordsList) {
super();
this.scheduledRecords = recordsList;
}
#Override
public int getRowCount() {
return scheduledRecords.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public String getColumnName(int column) {
return headers[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
ScheduledRecord r = scheduledRecords.get(rowIndex);
switch (columnIndex) {
case 0:
return r.getActor();
case 1:
return r.getTitle();
default:
return null;
}
}
public void addRow(ScheduledRecord r) {
ScheduledRecord toAdd = null;
for (Iterator<ScheduledRecord> recordIterator = scheduledRecords.iterator(); recordIterator.hasNext(); ) {
ScheduledRecord record = recordIterator.next();
if (record.equals(r)) {
throw new IllegalArgumentException("Scheduled Record " + r.toString() + " already exists");
} else {
toAdd = record;
}
}
scheduledRecords.add(toAdd);
}
public void removeRow(ScheduledRecord r) {
scheduledRecords.remove(r);
fireTableDataChanged();
}
public ScheduledRecord getScheduledRecordFromIndex(int index) {
return scheduledRecords.get(index);
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
}
here is how i add new entries:
private void saveScheduledRecord() {
if (checkInputValues()) {
WebradioPlayer.addScheduledRecord(new ScheduledRecord(titleField.getText(), artistField.getText()));
this.dispose();
} else {
JOptionPane.showMessageDialog(this, "Please enter a valid artist/title", "Invalid input", JOptionPane.ERROR_MESSAGE);
throw new IllegalArgumentException("artist or title input did not match the specifications");
}
}
and here the addScheduledRecord method:
public static synchronized boolean addScheduledRecord(ScheduledRecord record) {
RecorderController.getInstance().addScheduledRecord(record);
Gui.getInstance().getRecorderTab().getScheduledRecordsWindow().getTable().getScheduledRecordsTableModel().addRow(record);
Gui.getInstance().getRecorderTab().getScheduledRecordsWindow().getTable().getScheduledRecordsTableModel().fireTableDataChanged();
databaseConnector.addScheduledRecord(record);
return true;
}
If i add an entry, the 'previous' one is added to the table, however if i close the table and open it again it is all correct. RecorderController just holds an own list for other purposes (this list is modified in another way)
Does anyone see my mistake here?
This should fix the addRow method (no need to iterate, while there is a contains method):
public void addRow(ScheduledRecord r) {
if (scheduledRecords.contains(r)) {
throw new IllegalArgumentException("Scheduled Record " + r.toString() + " already exists");
}
scheduledRecords.add(r);
}
I got an AbstractTableModel, like this:
public class TableModelClienteFornecedor extends AbstractTableModel {
private List<ClienteFornecedorDTO> linhas;
private String[] colunas = new String[]{"Nome", "Conta"};
public TableModelClienteFornecedor() {
linhas = new ArrayList<>();
}
#Override
public int getRowCount() {
return linhas.size();
}
#Override
public int getColumnCount() {
return colunas.length;
}
#Override
public String getColumnName(int column) {
return colunas[column];
}
#Override
public Class getColumnClass(int column) {
return (getValueAt(0, column).getClass());
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
ClienteFornecedorDTO cf = linhas.get(rowIndex);
switch (columnIndex) {
case 0:
return cf.getNome();
case 1:
return cf.getConta();
default:
throw new IndexOutOfBoundsException("Coluna incorreta");
}
}
public void clear(JTable table) {
table.setRowSorter(null);
int indiceAntigo = this.getRowCount();
linhas.clear();
int indiceNovo = this.getRowCount();
this.fireTableRowsDeleted(indiceAntigo, indiceNovo);
}
public boolean isEmpty() {
return linhas.isEmpty();
}
public void add(ClienteFornecedorDTO cf) {
linhas.add(cf);
int index = this.getRowCount();
fireTableRowsInserted(index, index);
}
public void addList(List<ClienteFornecedorDTO> list, JTable table) {
int tamanhoAntigo = this.getRowCount();
linhas.addAll(list);
int tamanhoNovo = this.getRowCount() - 1;
this.fireTableRowsInserted(tamanhoAntigo, tamanhoNovo);
table.setAutoCreateRowSorter(true);
}
public ClienteFornecedorDTO get(int i) {
return linhas.get(i);
}
}
And the code below works ok to fill the my Jtable with data:
private void realizarBusca(String nome) {
IContaDAO dao = new ContaDAO();
boolean isFornecedor = radioFornecedor.isSelected();
List<ClienteFornecedorDTO> retorno =
dao.retornaContaClienteFornecedor(isFornecedor, nome);
tableModelClienteFornecedor.clear();
tableModelClienteFornecedor.addList(retorno, tableClienteFornecedor);
tableClienteFornecedor.updateUI();
}
Everything's working fine to me, and when I sort my Jtable visibily it's ok too, the problem is when I click on a specific row from my Jtable after I sorted it, the row it's not updated.
Anyone can help me with that?
I would appreciate, 'cause I'm on it since yesterday and still wasn't able to find a way to solve it.
Look at the methods convertRowIndexToModel() and convertRowIndexToView() in JTable.
When the table is sorted, the indices of the rows in the view don't match with the indices in the model anymore, and you have to use the above methods to convert from index to view and vice-versa.
For example, if you call JTable.getSelectedRow(), you'll get the view index of the selected row. You'll have to convert it to the model index (using convertRowIndexToModel()) to be able to get the selected object from the list in your model.
I'm making a database management system using java and mySQL. I'm using a jTable as a interface to the database.
Though the post look little long, the problem wont be that much of complex, for an experienced person (i guess).
This is my problem. After selecting a cell, i can enter values, (no prob with that). But after entering values, when i click on some other cell, the entered values get disappeared and it gets back to null.
Can't figure out the reason. I don't have much experience on jTables. But i think the problem is with the tablemodel.
This is my tablemodel
import Templates.TableEntry;
import java.util.LinkedList;
import javax.swing.table.AbstractTableModel;
public class myTableModel extends AbstractTableModel {
public static final int DATE_INDEX = 0;
public static final int ORDERNO_INDEX = 1;
public static final int ROOT_INDEX = 2;
public static final int HIDDEN_INDEX = 3;
public String[] columnnames;
public LinkedList<TableEntry> entryList;
public myTableModel(String[] columnNames) {
this.columnnames = columnNames;
entryList = new LinkedList<TableEntry>();
}
#Override
public String getColumnName(int column) {
return columnnames[column];
}
#Override
public boolean isCellEditable(int row, int column) {
if (column == HIDDEN_INDEX) {
return false;
} else {
return true;
}
}
#Override
public Class getColumnClass(int column) {
return String.class;
}
#Override
public String getValueAt(int row, int column) {
TableEntry record = entryList.get(row);
switch (column) {
case DATE_INDEX:
return record.date;
case ORDERNO_INDEX:
return record.jobOdrerNo;
case ROOT_INDEX:
return record.rootCardNos;
default:
return null;
}
}
public void setValueAt(String value, int row, int column) {
TableEntry record = entryList.get(row);
switch (column) {
case DATE_INDEX:
record.date = value;
break;
case ORDERNO_INDEX:
record.jobOdrerNo = value;
break;
case ROOT_INDEX:
record.rootCardNos = value;
break;
default:
System.out.println("invalid index");
}
updateTable(row, column);
}
public void updateTable(int row, int column) {
fireTableCellUpdated(row, column);
}
#Override
public int getRowCount() {
return entryList.size();
}
#Override
public int getColumnCount() {
return columnnames.length;
}
public boolean hasEmptyRow() {
if (entryList.size() == 0) {
return false;
}
TableEntry entry = entryList.get(entryList.size() - 1);
if ("".equals(entry.date)) {
return true;
} else {
return false;
}
}
public void addEmptyRow() {
entryList.add(new TableEntry());
fireTableRowsInserted(entryList.size() - 1, entryList.size() - 1);
}
public void deleteRow(int i) {
if (i != 0) {
entryList.remove(i);
fireTableRowsDeleted(i - 1, i + 1);
}
}
}
Sorry about the length. But i posted the whole code for the sake of completeness. Most of the parts can be neglected.
TableEntry is a simple class.
package Templates;
public class TableEntry {
public String date;
public String jobOdrerNo;
public String rootCardNos;
public String yardRootCard;
public String MCISO_NO;
public String service_maintenance_breakdown;
public String jobNo;
public String machineName;
public String fault;
public String problematicPart;
public String person;
public String action;
public String startTime;
public String finishedTime;
public String durationOfRepair;
public String spareParts;
public String itemCode;
public String no;
public String value;
public String totalCost;
public String remark;
public String breakdownAndSolution;
}
Hope I've provided all the details. This has been a real bug for me. Any help is appreciated.
Thanx in advance..!
(If any clarification is needed, please let me know.. difficult to post whole project. It's a bit huge.. :D)
There's a small bug in your code. Next time, be carefull..
In the tablemodel's method "setValueAt(---)" you've put wrong arguments. you were trying to override a method of class "AbstractTableModel". Original method is,
public void setValueAt(Object aValue, int rowIndex, int columnIndex){
}
But you've written your method as,
public void setValueAt(String value, int row, int column) {
...//method body
}
Hence, it wont override the intended function. Everytime a cell is changed, tablemodel will call the original "setValueAt(...)" function. But since it hasn't overriden, it will do nothing (you must override it, original method has no body).
Hope this helps..
You can use defaultTableModal for normal use. It has extended abstractTableModal and provide methods for frequently used requirements. Try it first, if not enough, then go develop your own class...
I can't figure out something using the constructor JTable(TableModel dm).
I'm using a LinkedList to manage my data so, to display it, I extended AbstractTableModel:
public class VolumeListTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private LinkedList<Directory> datalist;
private Object[] columnNames= {"ID", "Directory", "Wildcard"};
public VolumeListTableModel(){
}
public void setDatalist(LinkedList<Directory> temp){
this.datalist = temp;
}
public LinkedList<Directory> getDatalist(){
return (LinkedList<Directory>) this.datalist.clone();
}
public Object[] getColumnNames() {
return this.columnNames;
}
#Override
public int getColumnCount() {
return Directory.numCols;
}
#Override
public int getRowCount() {
return this.datalist.size();
}
#Override
public Object getValueAt(int row, int col) {
Directory temp = this.datalist.get(row);
switch(col){
case 0:
return temp.getId();
case 1:
return temp.getPath();
case 2:
return temp.getWildcard();
default:
return null;
}
}
I'm doing something wrong because when I run my GUI I get column names labeled A,*B*,C.
There is no method in AbstractTableModel called getColumnNames, so I believe your method is being ignored. The actual method you want to override is the getColumnName method.
Try adding this method to your VolumeListTableModel class
public String getColumnName(int column) {
return columnNames[column];
}
You need to override the getColumnName method which in your case will simply
return columnNames[column];
You have to Override this method :
public String getColumnName(int column)
AbstractTableModel does not have a getColumnNames method, but it is easy to implement:
public class VolumeListTableModel extends AbstractTableModel {
// [...]
public String[] getColumnNames() {
String[] columnNames = new String[this.getColumnCount()];
for (int i = 0, columnCount = this.getColumnCount(); i < columnCount; i++) {
columnNames[i] = this.getColumnName(i);
}
return columnNames;
}
// [...]
}