AbstractTableModel won't update JTable - java

i'm trying to make my JTable show changes made to my TableModel extending AbstractTableModel. I made a Heap to insert all the documents and then I apply a heapSort on my heap array, so this ordered array should be my TableModel data. It looks like this:
public class ModeloTabla extends AbstractTableModel {
private Heap heap;
private Nodo[] datos;
#Override
public int getRowCount() {
return heap.getNumNodos();
}
#Override
public int getColumnCount() {
return 4;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
if ( !heap.empty() ) {
datos = heap.heapSort();
}
Documento doc = datos[rowIndex].getDocumento();
switch ( columnIndex ) {
case 0:
return doc.getNombre();
case 1:
return doc.getHojas();
case 2:
return doc.getPrioridad();
default:
return null;
}
}
}
Inside the getValueAt method when I call heap.heapSort() the heap internal array is destroyed and it returns a Nodo[] with the ordered nodes. So when datos has an ordered array with nodes, my JTable won't show the data. Now, if I don't execute the heap.heapSort() and instead just call for the unordered array from the heap, my JTable shows everything.
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
datos = heap.getDatos();
Documento doc = datos[rowIndex].getDocumento();
... //This works but datos is unordered
}
}
I've tried replacing the Heap unordered array with the ordered one inside heapSort() and returning it using getDatos() but then the JTable again won't show up, also I've checked for the returning array from heapSort() and it's working well, the data is the same as the one from getDatos() but ordered. Any help with this would be very appreciated, thanks.

In the getValueAt() method you are retrieving the data from the datos object.
Documento doc = datos[rowIndex].getDocumento();
So the row count should be based on the number of rows in the datos object.
public int getRowCount() {
//return heap.getNumNodos();
return datos.length;
}
The getValueAt() method should NOT be sorting the data. The data in the model should already be sorted. Either sort it externally or sort it when you create the model. That is the getValueAt() method should not be changing the structure of the data. Also every time you change the data you would need to resort.

Related

Why we extends AbstractTabelModel when set values into JTabel?

Im developing a app for ordeing system and i have to set data into JTabels.
And this code is successfully working.I wanted to know what the importance of and whats happen in this class?
Why we need to import AbstractTabelModel.class?
OrderTabelModel Class:-
public class OrderTableModel extends AbstractTableModel{
protected static final String[] COLUMN_NAMES={"Item","Qty","Amount"};
private List<Order> rows;
public OrderTableModel(List<Order> rows){
this.rows = new ArrayList<>(rows);
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
#Override
public String getColumnName(int column) {
return COLUMN_NAMES[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object value = null;
Order row = rows.get(rowIndex);
switch (columnIndex) {
case 0:
value = row.getItem();
break;
case 1:
value = row.getQty();
break;
case 2:
value = row.getAmount();
break;
}
return value;
}
}
this is other class
private void tblOrderListMouseClicked(java.awt.event.MouseEvent evt) {
int raw = tblOrderList.getSelectedRow();
Order or;
String item;
Double qty,amount,total;
ArrayList<Order> arrOrder = new ArrayList<Order>();
String selectedRaw = tblOrderList.getModel().getValueAt(raw, 0).toString();
System.out.println("order id : "+selectedRaw);
String sql = "select item,qty,amount from orderdetails where orderid='"+selectedRaw+"'";
con = new DBconnector().connect();
try {
Statement ps =con.createStatement();
ResultSet rs2 = ps.executeQuery(sql);
while(rs2.next()){
or = new Order();
or.setItem(rs2.getString("item"));
System.out.println("Item :" +rs2.getString("item"));
or.setQty(rs2.getDouble("qty"));
or.setAmount(rs2.getDouble("amount"));
arrOrder.add(or);
}
rs2.close();
ps.close();
OrderTableModel tblModel = new OrderTableModel(arrOrder);
tblOrderItems.setModel(tblModel);
} catch (Exception e) {
e.printStackTrace();
}
}
Can some one explain me the process of this please?
It is not always mandatory to extend the AbstractTableModel. You can simply extend the DefaultTableModel and only override the getValueAt() method if you have to.
But most of the time for simple usages it is not even needed to override the getValueAt() method either.
By using the DefaultTableModel, you have a limitation for the converting you data (imported from DB) to an object[][] or Vector types which may be a little boring.
But you asked what is the importance of using AbstractTabelModel?
In this case I can say when JTable is started to being rendered, it needs to determine the number of rows and number of the columns and also it needs to know which data should be renedered in each cell and so on. Based on this, JTable ask for this Information from the underlying TableModel. So it is needed for your TableModel(any child or implementation of TableModel) to have those methods which are used by JTable to retrieve the needed information.
Hope this would be helpful.
Good Luck.

Refreshing JTable after changing data

I want to refresh and display my JTable after a user pressed a button. Before that the button generates an Object[][] in which the filtered data from the table is held.
The filtered data is different only in the number of rows.
I'm using the netbeans UI creator and the only way I could populate the table with data is by defining the abstractTableModel.
Here is the code of my abstractTableModel:
class myTable extends AbstractTableModel{
private String[] stolpci = {"Kategorija","Podkategorija","Opis","Cena","Datum","Boni"};
private Object[][] data = PregledovalnikGUI.vrniTabelo(); /*PregledovalnikGUI.vrniTabelo() returns a value in form of Object[][] in which the data is held*/
public int getColumnCount() {
return stolpci.length;
}
public int getRowCount() {
return vrstice.length;
}
public String getColumnName(int col) {
return stolpci[col];
}
public Object getValueAt(int row, int col) {
return vrstice[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public void setValueAt(Object value, int row, int col) {
vrstice[row][col] = value;
fireTableCellUpdated(row, col);
}
The jTable is set like:
Tabela.setModel(new myTable());
Which methods do I need to define to get the table to refresh at runtime?
inside myTable you could have a method called refresh() something like this
public void refresh(Object[][] objects){
//make the changes to the table, then call fireTableChanged
fireTableChanged(null);
}
Then in the button listener, call the above method:
Tablea.refresh(objects);//objects stores your filtered data
If you create a new TableModel, then nothing, the table will automatically update itself.
If the underlying data of the model is changed, then from within the model (seen as you extending from AbstractTableModl), you could call fireTableDataChanged, which lets the table know that the contents of the table have changed and it should redraw itself.
This may require that the model either have a refresh method of its own or that it has the capability to listen to changes from the data it is modelling

Implementing ArrayLists to Table models

Hi I have an arraylist of a class I created called Pets which has the variables below
private String name;
private String species;
private int age;
I wanted to display this arraylist into a jTable and I did that succesfully by using defaultTableModel and calling setModel().
However I needed to add a sorting and filtering function for the Jtable. I took a look at the java tutorials were they were creating a subclass of AbstractTableModel in order to sort and filter. However they were using arrays to store the data. So I tried modifying the code to use an arraylist isntead but Im stuck with this method
public Object getValueAt(int row, int col) {
return data[row][col];
}
How do I get all the values from one object from th arraylist?
Any help will be greatly appreciated. Thanks in advance.
Does your ArrayList hold a row that is it's own type of object? If so, and if your ArrayList is a generic ArrayList<RowItem> then you could do something like:
#Override
public Object getValueAt(int row, int col) {
if (row > getRowCount()) {
// throw an exception
}
RowItem rowItem = rowItemList.get(row);
switch (col) {
case 0:
return rowItem.getName();
case 1:
return rowItem.getLastSpecies();
case 2:
return rowItem.getAge();
}
return null; // or throw an exception
}
You can try this:
public Object getValueAt(int row, int col) {
switch(col) {
case 0:
return ((Pets)data.get(row)).getName();
case 1:
return ((Pets)data.get(row)).getSpecies();
case 2:
return ((Pets)data.get(row)).getAge();
}
return null;
}

Updatable ResultSet row count

I want to bind a database table to a swing JTable, and make that JTable editable by using APIs in a updatable ResultSet(#insertRow,#deleteRow(),#updateRow()).
so I need to create a TableModel implementation by wrapping a ResultSet.
public class MyTableModel implements TableModel {
private ResultSet rs;
private ResultSetMetaData rsmd;
#Override
public int getRowCount() {
return 0;
}
#Override
public int getColumnCount() {
return 0;
}
#Override
public String getColumnName(int columnIndex) {
return null;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return null;
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return null;
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
#Override
public void addTableModelListener(TableModelListener l) {
}
#Override
public void removeTableModelListener(TableModelListener l) {
}
}
then, how Can I implement the getRowCount() method ?
how to determine the numbers of rows in a updatable result set ?
for example, if user click a button "add row", then I call such methods :
rs.moveToInsertRow();
rs.updateString(1, "yqwang");
rs.insertRow();
how to sync the JTable UI and the underlying ResultSet?
You should not do that. A ResultSet needs an open connection to the database, and the changes done to the result set won't be committed to the database until you commit the connection.
This means that if the database decides to close the connection because it hasn't seen any activity for some time, or if your app crashes after three hours, you'll lose all the modifications done during these 3 hours.
This also means that you might lock some rows for a whole lot of time, and thus make other transactions wait for a whole lot of time before being able to do anything.
Copy the data from the result set into your table model, and start a new transaction each time you need to insert or update a row.
To bind JTable to database you need to refresh your JTable and relode JTable. To get no. of rows in result set just call these two methods-
rs.last();
int count = rs.getRow();
here count gives you no. of records in your ResultSet.
When you do insertRow() on the ResultSet "You cannot see INSERT result on the ResultSet". To see rows that where inserted you have to re-run your query and get new resultset.
For reference on "No result set type can see a row inserted by a result set INSERT operation." see http://docs.oracle.com/cd/B28359_01/java.111/b31224/resltset.htm#i1024719

Java JTable binding via JPA

I have tried to search for proper answers, but nothing helped me so far. I am quite new to java GUI programming, actually, to java itself.. I have however managers to understand JPA, how to retrieve, insert and delete using JPA.
Now I want the data in my database to be shown in a JTable.
I currently have the following mySQL table(which i want to show in a JTable
games
Id PK int
Title
Publisher
Genre
ReleaseDate
As far as coding concerns, I have succesfully retrieved the data contained in the table using the following:
public List<Game> getGames(){
List<Game> games;
try{
TypedQuery<Game> selectGamesQuery = entityManager.createQuery("SELECT g FROM Game g", Game.class);
games = selectGamesQuery.getResultList();
} catch(Exception e) {
System.out.println(e);
}
return games;
}
This succesfully returns a list of games whom I can iterate trough.
Then, in my view I have the following
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
tblGames = new JTable(new tblGamesModel());
tblGames.setShowVerticalLines(true);
tblGames.setShowHorizontalLines(true);
tblGames.setFillsViewportHeight(true);
scrollPane.setViewportView(tblGames);
Which ofcourse leads us to the table model,which is where I'm stuck.
public class tblGamesModel extends AbstractTableModel {
private GameRepository gameRepository;
private List<Game> games;
/**
*
*/
public tblGamesModel(){
gameRepository = new GameRepository();
games = gameRepository.getGames();
}
private static final long serialVersionUID = 1L;
#Override
public int getColumnCount() {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getRowCount() {
// TODO Auto-generated method stub
return games.size();
}
#Override
public Object getValueAt(int arg0, int arg1) {
// TODO Auto-generated method stub
return null;
}
}
I know this is alot of code for a simple post, but I really don't know how else to show the current problem. Any good links would help, or advise on its own.
Thanks for taking the time to read the code and possibly help me out.
Remember, I am just a student programming, so I have a lot to learn about conventions etc aswell. So pointers are also welcome, as I am eager to learn from more experienced developers.
The simplest option is something like this:
#Override
public int getColumnCount() {
return 5;
}
...
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Game game = games.get(rowIndex);
switch (columnIndex) {
case 0:
return game.getId();
case 1:
return game.getTitle();
case 2:
return game.getPublisher();
case 3:
return game.getGenre();
case 4:
return game.getReleaseDate();
}
return null;
}
That can be prone to maintenance problems due to all the magic numbers - a solution would be to use an enumeration for the columns:
enum GameTableColumn {
ID, TITLE, PUBLISHER, GENRE, RELEASE_DATE;
}
And then get the enumeration instance for a column using GameTableColumn.values()[columnIndex].
A few style notes - tblGamesModel is a non-standard name for a Java class, class names always start with an upper case letter. A more Java name would be GamesTableModel. Hungarian notation prefixes (such as "tbl") are generally discouraged.
Also having a database fetch in a constructor is generally a bad idea. In a Swing application you want all fetches to be explicit so you can ensure they do not block the UI. Rather than getGames() I would suggest retrieveGames(). It may be best to construct the GamesRepository outside the table model and pass it in to the constructor. You could then perform the JPA query first in a different thread. This would prevent the UI thread from freezing while the database access is in progress.
Pass loaded list to the model via constructor parameter or setter method. Then you can use following model structure:
public class TblGamesModel extends AbstractTableModel {
private static final String[] COLUMNS = {"id", "title",
...........
private static final int COL_ID = 0;
private static final int COL_TITLE = 1;
private List<Game> list; //list that is injected via constructor or setter method
public int getRowCount() {
return list.size();
}
public int getColumnCount() {
return COLUMNS.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
Game game = list.get(rowIndex);
switch (columnIndex) {
case COL_ID:
return game.getId();
........
}
}
public String getColumnName(int column) {
return COLUMNS[column];
}

Categories