I have got JTable with datas from DataBase. Once the table is filled but somotimes (totally random) not. Connection with DB is correct. I haven't got any idea why in one situation table is filled and in other not. there is absolutely no rule.
Model class:
public class MaterialModel extends AbstractTableModel
{
public List<Material> materials = new ArrayList<Material>();
String[] columns = {"ID_Material", "Nazwa"};
public int getRowCount() {
return this.materials.size();
}
public int getColumnCount() {
return columns.length;
}
public String getColumnName(int col){
return columns[col];
}
public Object getValueAt(int rowIndex, int columnIndex) {
Material material = materials.get(rowIndex);
switch (columnIndex)
{
case 0: return material.id;
case 1: return material.name;
}
return null;
}
public void setListMaterials(List<Material> listMaterials){
this.materials = listMaterials;
}
public void reset(){
this.materials.clear();
}
}
Form class:
public class Form extends JFrame{
private JTable materialTable;
MaterialDAO materialDAO;
public MaterialModel materialModel;
public Form() throws SQLException {
super("Magazyn");
setContentPane(mainPane);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500,500);
this.initComponets();
materialDAO = new MaterialDaoImpl();
materialTable.setModel(new MaterialModel());
this.fillTable();
}
public void fillTable() throws SQLException {
this.materialTable.repaint();
materialModel = (MaterialModel) this.materialTable.getModel();
materialModel.reset();
materialModel.setListMaterials(materialDAO.getAllMaterials());
}
}
Thank you a lot for your help.
As i see there is no SQL query, check if you are executing a sql query, i don't know if you are using Hibernate or something other, try to put the part of executing sql query, by this way we can see the error you did.
Related
I have a list of travel offers that I read and parsed from a XML file and added them to my GUI using JTable. I also have some update functionalities (at interval and instantly on click) that updates the GUI as soon as new offers are added to the XML. My aim is to add the offers in the GUI in thread safe way.
This is the class (UpdateData.java) where i perform doInBackground() using Swingworker and more concern about safety. (Other classes are also shown below if anyone is interested to take a deeper look) Can SwingUtilities.invokeLater() be used to make it thread-safe? Does overriding Swingworkers done(), execute() and process() will help in some way to achieve safety? In that case how? (newbie at thread prog) (Other classes are given below if anyone is interested to get a deeper look). Some Help / Feedback will be highly appreciated.
Class: UpdateData.java
public class UpdateData extends SwingWorker<Integer, Integer> {
private ArrayList<RawTravelData> listOfOffer;
private TravelData offerData;
private XMLReader parseData;
//the controller
private ControlUpdate updtController;
//constructor
public UpdateData(TravelData o, ControlUpdate offerController) {
updtController = offerController;
parseData = new XMLReader();
offerData = o;
}
#Override
protected Integer doInBackground() throws Exception {
listOfOffer = parseData.fetchData();
offerData.setData(listOfOffer);
updtController.setOfferArray(listOfOffer);
return null;
}
}
Class: RawTravelData.java
public class RawTravelData {
private String destination = "";
private String travelDate = "";
private int currPrice;
//empty constructor
public RawTravelData() {
}
//setters ad getters for destination, travel date and currprise
}
Class: TravelData.java
public class TravelData extends AbstractTableModel {
//the table header strings
private String[] colNames = { "Destination", "Date", "Price", "Details" };
private static final long serialVersionUID = 1L;
//arraylist of the offer data
private ArrayList<RawTravelData> offerList;
//constructor
public TravelData(ArrayList<RawTravelData> rtd) {
offerList = rtd;
}
//second constructor to create empty list
public TravelData() {
offerList = new ArrayList<RawTravelData>();
}
//add the list
public void setData(ArrayList<RawTravelData> o) {
offerList = o;
this.fireTableDataChanged();
}
//get the offer list
public ArrayList<RawTravelData> getOfferList() {
return offerList;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return Integer.class;
case 2:
return String.class;
case 3:
return String.class;
default:
break;
}
return String.class;
}
#Override
public int getColumnCount() {
return colNames.length;
}
#Override
public int getRowCount() {
return offerList.size();
}
#Override
public Object getValueAt(int arg0, int arg1) {
switch (arg1) {
case 0:
return offerList.get(arg0).getDestination();
case 1:
return offerList.get(arg0).getPrice();
case 2:
return offerList.get(arg0).getTravelDate();
case 3:
return "Details";
default:
break;
}
return "null";
}
#Override
public String getColumnName(int col) {
return colNames[col];
}
}
Class: XMLReader.java
public class XMLReader {
//Method to fetch and read all the data from the XML file
public ArrayList<RawTravelData> fetchData() {
//parse data and return as arraylist of offers
return arrayOfOffer;
}
}
Class: ControlUpdate.java
//This class is responsible for controlling the updating of the offer data in the background
public class ControlUpdate {
private TablePanel tablePane;
private ArrayList<RawTravelData> offerArray;
//..
//Constructor
public ControlUpdate(TablePanel tablePane) {
settingsVal = new SaveSettings();
this.tablePane = tablePane;
tablePane.getOfferTable().addMouseListener(
new TableSortListener(tablePane.getOfferTable(), this));
runUpdateTask();
setUpdateInterval(settingsVal.readSettings());
}
//run the updates
private void runUpdateTask() {
//used Timer and ScheduledThreadPool
}
//get the table panel
public TablePanel getTablePanel() {
return tablePane;
}
//setting the list to a new offer list for the updater
public void setOfferArray(ArrayList<RawTravelData> rtd) {
offerArray = rtd;
}
}
All modifications of Components and their models need to be performed in the AWT event dispatch thread, not in a background thread. The second and third lines of your doInBackground method should be moved to the done method, which is guaranteed to be executed in the AWT event thread.
It is also customary to have the SwingWorker's value type be the data you're obtaining in the background.
public class UpdateData
extends SwingWorker<List<RawTravelData>, Integer> {
// ...
#Override
protected List<RawTravelData> doInBackground() throws Exception {
return parseData.fetchData();
}
#Override
protected void done() {
try {
List<RawTravelData> listOfOffer = get();
offerData.setData(listOfOffer);
updtController.setOfferArray(listOfOffer);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
// Someone wants us to exit cleanly.
e.printStackTrace();
}
}
}
I'm a complete newbie to Java. I've only been learning it for half a year now. Right now I am working on a Project for school and I've hit a complete wall:
I am basically making a Program to manage your own Books. I have a class that is "Books", which holds the data for the book objects. Then there's the class "Library" which holds an ArrayList of Books. For the TableModel, I am using a class ("LibraryTableModel") that extends AbstractTableModel. I then have a GUI class wich displays the table.
The table actually works, but there are two instances where the program crashes:
When I add a Book to an empty Library, the table doesn't update. However, the Book IS added when I start the program anew (I save the Library class as a .ser file).
Then the instance which I am asking about: I have a button that removes Books from the table. the Button itself works fine, but when I remove a book, the program throws an ArrayOutOfBoundsException. When I create the table anew, it updates and the book is removed. What is the problem here, why does the program crash instead of update the table?
Code for TableModel:
public class LibraryTableModel extends AbstractTableModel
{
private String[] columnNames = {"Titel", "Autor", "Status", "Genre", "Verlag", "Seitenzahl", "ISBN", "Sprache", "Bewertung"};
private Object[][] data = {};
ArrayList<Book> lib;
public LibraryTableModel(Library l)
{
//This Method returns the ArrayList in the Library class
lib = l.getList();
int libSize = lib.size();
data = new Object[bib.size()][];
for (Book b : lib)
{
int index = bib.indexOf(b);
//(...)
//CODE HERE gets all the data that is supposed to be displayed
//from each book in the ArrayList
Object[] oA = {tit, aut, sta, gen, ver, sei, isb, spr, bew};
data[index] = oA;
}
}
public int getColumnCount()
{
return columnNames.length;
}
public int getRowCount()
{
return data.length;
}
public String getColumnName(int col)
{
return columnNames[col];
}
public Object getValueAt(int row, int col)
{
return data[row][col];
//When I try to remove a Book, the ArrayOutOfBounds Exception comes from here
}
public Class getColumnClass(int c)
{
return getValueAt(0, c).getClass();
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
fireTableCellUpdated(row, col);
}
public void removeRow(int row)
{
lib.remove(row);
fireTableRowsDeleted(row, row);
}
Code in the GUI class that is revolving around the table and the tablemodel:
public class GUI implements ActionListener
{
JTable table;
LibraryTableModel model;
TableRowSorter<BibliothekTableModel> sorter;
Library lib;
JMenuItem deleteBook;
(...) The Library is loaded through the .ser file
public void showTable() //This method is envoked in the GUI constructor through pressing a button
{
model = new LibraryTableModel(lib);
table.setModel(model);
deleteBook.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
model.removeRow(row);
//Code that saves the library at this point
table.setModel(new LibraryTableModel(lib));
}
});
popupMenu.add(deleteBook);
table.setComponentPopupMenu(popupMenu);
sorter = new TableRowSorter<BibliothekTableModel>(model);
table.setRowSorter(sorter);
JScrollPane scrollTable = new JScrollPane(table);
//Next is code, that adds this ScrollPane to my Frame
}
When I add a Book to an empty Library, the table doesn't update. However, the Book IS added when I start the program anew (I save the Library class as a .ser file).
There is no information provided which demonstrates how this works...and what's a .ser file?
Then the instance which I am asking about: I have a button that
removes Books from the table. the Button itself works fine, but when I
remove a book, the program throws an ArrayOutOfBoundsException. When I
create the table anew, it updates and the book is removed. What is the
problem here, why does the program crash instead of update the table?
There are two issues...
First, because you are using a RowSorter on the table, the visual row index returned by JTable#getSelectedRow and the physical row index in the model won't be the same, you need to use JTable#convertRowIndexToModel
int row = table.getSelectedRow();
row = table.convertRowIndexToModel(row);
model.removeRow(row);
//Code that saves the library at this point
Second, you're removing the book from the lib, but not updating the internal cache...
public void removeRow(int row)
{
lib.remove(row);
fireTableRowsDeleted(row, row);
}
The model isn't using the lib as it's source for the data, but is using the data array, which you have not updated.
While you could simply rebuild the data array, a better solution would be to get rid of it and use the lib directly, for example...
public class LibraryTableModel extends AbstractTableModel {
private String[] columnNames = {"Titel", "Autor", "Status", "Genre", "Verlag", "Seitenzahl", "ISBN", "Sprache", "Bewertung"};
private Object[][] data = {};
private Library lib;
public LibraryTableModel(Library l) {
lib = l;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return lib.getList().size();
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
Book book = lib.getList().get(row);
Object value = null;
switch (col) {
case 0:
value = ...;
break;
case 1:
value = ...;
break;
case 2:
value = ...;
break;
case 3:
value = ...;
break;
case 4:
value = ...;
break;
case 5:
value = ...;
break;
case 6:
value = ...;
break;
case 7:
value = ...;
break;
case 8:
value = ...;
break;
}
return value;
//When I try to remove a Book, the ArrayOutOfBounds Exception comes from here
}
public Class getColumnClass(int c) {
// Don't do this, know the actualy value and return it
// Otherwise you could end up with a NullPointerException
return getValueAt(0, c).getClass();
}
public void setValueAt(Object value, int row, int col) {
// Use a simular technquie to getValueAt to extract the Book for the give
// row and update the Book's attributes
fireTableCellUpdated(row, col);
}
public void removeRow(int row) {
lib.remove(row);
fireTableRowsDeleted(row, row);
}
}
I've figured out why my arraylist was always returning a size of 0 but I can't fix the problem. I have a custom model with an "addHuman(Human h) method that is intended to add to an array. Only problem is that it doesn't. Now, if I were to use the regular method, say model.add(index, object o) it would actually work and increment the size of my arraylist but doesn't display on my jtable. My question is how can I make this work for my custom addHuman method? Any help much appreciated!
and the following is the main class that uses that method. When I click on the button to addIndividual, it's supposed to add the human to my HumanListModel:
addIndividual.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Human temp;
try {
temp = new Human();
modelx.addHuman(indexPoint, temp);
///the addHuman method does display on jtable but doesn't increment arraylist, meaning that the size is always 0 which creates many problems/////
//modelx.add(indexPoint, temp); does indeed increment the arraysize but then it doesn't display the values on the jtable////
indexPoint++;
System.out.println(modelx.size());
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
newbiex.revalidate(); ////is the jtable////
}
});
here is my custom HumanListModel:
public class HumanListModel extends DefaultListModel implements TableModel
{
private ArrayList<Human> data;
public HumanListModel()
{
super();
data = new ArrayList<Human>();
}
public void addHuman(int k, Human h)
{
data.add(k, h);
fireIntervalAdded(this, data.size(), data.size());
}
public Human getHuman(int o)
{
return data.get(o);
}
public void removeHuman(Human h)
{
data.remove(h);
}
public int getColumnCount()
{
// the number of columns you want to display
return 1;
}
public int getRowCount()
{
return data.size();
}
public Object getValueAt(int row, int col)
{
return (row < data.size()) ? data.get(row) : null;
}
public String getColumnName(int col)
{
return "Human";
}
public Class getColumnClass(int col)
{
return Human.class;
}
public void addTableModelListener(TableModelListener arg0) {
}
#Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
public void removeTableModelListener(TableModelListener arg0) {
}
public void setValueAt(Object arg0, int arg1, int arg2) {
}
}
You have to fire model changes when you change the data underlying the
public void addHuman(Human h)
{
data.add(h);
fireIntervalAdded(this, data.size(), data.size());
}
Similar methods with similar events need calling whenever you change the underlying data to tell the List that it has to update the screen image.
For example, removeHuman() will need a similar call. Consult the javadoc at http://docs.oracle.com/javase/6/docs/api/javax/swing/AbstractListModel.html for the methods that do that. (In this example, fireIntervalRemoved() and the event will need to contain the index of the row removed.)
You are going to also need a getElementAt() method that returns the data element for that row. In your case, return the Human at that row but it will need a toString() method. Alternately, you could format a string from the Human
and return it.
Note - A previous version of this answer was based on my confusion, thinking this was a TableModel and not a ListModel. It's been fixed.
I have a vector with HashMap elements.
I want to put it in a table and every HashTable value must be in column with HashTable key column-title.
So elements with key "key1" must appear on table column with name "key1".
The problem is when I try to add/remove columns of table with setHash() function.
I pass a String[] with more/fewer elements and when this function run the fireTableStructureChanged() java throws like crazy.
I don't understand where is the problem. Can you help me please?
The implementation of Table Model is here:
public class ResizableTableModel extends AbstractTableModel {
protected DataSource src;
protected String[] hash;
//......................
public void setHash(String[] hash) {
this.hash = hash;
fireTableStructureChanged(); // THROWS!
}
public ArrayList getData() { return src.getData(); }
public int getColumnCount() { return hash.length; }
public int getRowCount() { return getData() == null ? 0 : getData().size(); }
public String getColumnName(int col) { return hash[col]; }
public boolean isCellEditable(int row, int col) { return true; }
public Object getValueAt(int row, int col) {
try {
return ((HashMap) getData().get(row)).get(hash[col]);
} catch (Exception e) {
return null;
}
}
public void setValueAt(Object obj, int row, int col) {
try {
//...................
} catch (Exception e) {}
fireTableDataChanged();
}
}
don't to remove Columns from XxxTableModel,
remove Column from JTables view only, data are still stored and accesible in XxxTableModel
I have a table model. I want to delete a row from a table. I am not able to find the model.removeRow method. Can someone tell he how to remove a row? Below is the code for the model.
class TableModel extends AbstractTableModel {
private Object[][] data;
private String[] columnNames;
public TableModel(Object[][] data) {
this.data = data;
columnNames=new String[1];
columnNames[0]="Data";
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
public Class getColumnClass(int c) {
return String.class;
}
public boolean isCellEditable(int rowIndes, int columnIndex) {
return false;
}
public String getColumnName(int index) {
return columnNames[index];
}
public void setValueAt(Object value, int rowIndex, int columnIndex) {
data[rowIndex][columnIndex] = value;
fireTableCellUpdated(rowIndex, columnIndex);
}
}
Use DefaultTableModel. It has public void removeRow(int row) method.
you must be missing something that is obvious in the default model, maybe you're mot overriding properly if you're doing your own and you might thing it's missing :
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// Create some data
model.addColumn("Col1");
model.addRow(new Object[]{"r1"});
model.addRow(new Object[]{"r2"});
model.addRow(new Object[]{"r3"});
// Remove the first row
model.removeRow(0);
// Remove the last row
model.removeRow(model.getRowCount()-1);
DefaultTableModel is one solution. But if yo still want to use abstrac table model, this is how you do.
This is the new model definition.
class TableModel extends AbstractTableModel {
private Object[][] data;
private String[] columnNames;
public TableModel(Object[][] data) {
this.data = data;
columnNames=new String[1];
columnNames[0]="Data";
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
public Class getColumnClass(int c) {
return String.class;
}
public boolean isCellEditable(int rowIndes, int columnIndex) {
return false;
}
public String getColumnName(int index) {
return columnNames[index];
}
public void removeRow(int row)
{
Object [][]newData=new Object[data.length-1][data[0].length];
for(int i=0;i<newData.length;i++){
for(int j=0;j<data[0].length;j++){
newData[i][j]=data[i+1][j];
}
}
data=new Object[newData.length][columnNames.length];
data=newData;
fireTableRowsDeleted(row, row);
}
public void setValueAt(Object value, int rowIndex, int columnIndex) {
data[rowIndex][columnIndex] = value;
fireTableCellUpdated(rowIndex, columnIndex);
}
}
You first need to remove the row data from the data object. and then remove the row.
Kaushik, if you really want to make your own implementation of the TableModel interface and deal with the storage of rows manually (as you obviously do by using Object[][] data), then you must implement the removeRow() method because abstract table model does not "know" how to do it. removeRow() will have to fireTableRowsDeleted() at the end...
A good alternative is to refactor your class and make it extend the DefaultTableModel.
Another suggestion - since table model changes a lot, a dynamic array may be a bad choice for storage because you must either reallocate space every time you add a row (bad), or you preallocate enough space for certain number of rows, then whenever there is no enough space you allocate new Object[][] with some extra space (for next N rows). Typically people allocate enough space for 2^n rows during the reallocation process.