at the moment I have an app that allows me to display data in a Jtable and then when I double click the Jtable this open a little window to edit only 3 fields, comments, expiration date and description. I update the this values (whit a preparedStatement) the thing is that everytime that I make an update to the database my table just refresh itself, changing the dateFormat with the new value that I've just inserted in my other window but with a different format!. How is this possible?
I' don't understand this because the only I only set a model to the table when I press my "search" button which contains the following code:
ArrayList<FiltrosResumen> filtrosResumenList = MainFrame.dataBase.searchFiltroResumen(query);
FiltrosResumenTableModel resumenModel = new FiltrosResumenTableModel(filtrosResumenList);
this.resumenTable.setModel(resumenModel);
hideColumns(1);
I'm using a custom table model containing all the table Fields, so first as you can see I colect all the rows from the database into a ArrayList from a custom object "FiltrosResumen", then I pass this to the constructor from my customTable model "FiltrosResumenTableModel" which extends AbstractTableMode I'm not using any special renders the most important methods are
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return this.filtrosResumen.get(rowIndex).getIdFiltro();
//....
//case 9:
default:
return null;
}
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
FiltrosResumen filtroResumen = new FiltrosResumen();
switch (columnIndex) {
case 0:
filtroResumen = this.filtrosResumen.get(rowIndex);
filtroResumen.setIdFiltro(Long.parseLong(aValue.toString()));
this.fireTableCellUpdated(rowIndex, columnIndex);
break;}
//....
//case 9:
}
And the constructor
public FiltrosResumenTableModel(List<FiltrosResumen> filtrosResumen) {
this.filtrosResumen = filtrosResumen;
}
And as I stated before, the database does not interact directly whit the table since storing the query result in a ArrayList, and then sending this to the constructor of my customTableModel.
EDIT: In order to change the value from one of the rows items I send a FiltrosResumen Object in this way:
FiltrosResumenTableModel modelo = (FiltrosResumenTableModel) this.resumenTable.getModel();
resumen = modelo.getResumen(row);
EditResumenIF editConexionesIF = new EditResumenIF(resumen);
EDIT: Passing a the resumen object to a InternalFrame Constructor (EditResumenIF).So in this new InternalFrame (EditResumenIF) I assign the values to a JCalendar and a JTextField to change the values and then save them. Afther the same object received by the constructor to a method that does the query and then return a string, ( if the string it's empty it' means that the query was successful without any mistakes)
String error = MainFrame.dataBase.updateResumen(resumen, resumen.getIdFiltro());
How comes that my Table knows that the value changed?
The default renderer for a cell of type Object.class is "a label that displays the object's string value." Unless your implementation of TableModel override's getColumnClass() to return some other value, your result is not unexpected. You might compare this example using DefaultTableModel to your implementation.
Addendum: How does my table know that the value changed?
JTable is a TableModelListener; any change to the model is (or should be) propagated to the table. Absent a complete example, I'm guessing that you are using a second table, table2, to edit a copy of certain data obtained from the original, table1.
Verify that you are copying the data in getResumen() and not just copying a reference to the table1 model.
In your implementation of setValueAt() in the TableModel of table2, update the model of table1. The exact mechanism depends on your TableModel; two approaches are contrasted here.
Addendum: I'm not using another tableā¦I'm passing a reference to my internal frame.
The same principles would apply. As an alternative to directly coupling the models, let the table's model be a PropertyChangeListener to the internal frame, as shown here.
Related
I have a class called "Product", with a double attribute "price". I'm showing it on a table column inside a table view, but i wanted to show the price formatted -- "US$ 20.00" instead of just "20.00".
Here's my code for populating the table view:
priceProductColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
I tried everything: convert the returned value to a string, using the method toString that priceProperty has, etc, but not seems to work.
Do i need to bind an event of something like that?
Use the cellValueFactory as you have it to determine the data that is displayed. The cell value factory is basically a function that takes a CellDataFeatures object and returns an ObservableValue wrapping up the value to be displayed in the table cell. You usually want to call getValue() on the CellDataFeatures object to get the value for the row, and then retrieve a property from it, exactly as you do in your posted code.
Use a cellFactory to determine how to display those data. The cellFactory is a function that takes a TableColumn (which you usually don't need) and returns a TableCell object. Typically you return a subclass of TableCell that override the updateItem() method to set the text (and sometimes the graphic) for the cell, based on the new value it is displaying. In your case you get the price as a Number, and just need to format it as you require and pass the formatted value to the cell's setText(...) method.
It's worth reading the relevant Javadocs: TableColumn.cellFactoryProperty(), and also Cell for a general discussion of cells and cell factories.
priceProductColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
priceProductColumn.setCellFactory(col ->
new TableCell<Product, Number>() {
#Override
public void updateItem(Number price, boolean empty) {
super.updateItem(price, empty);
if (empty) {
setText(null);
} else {
setText(String.format("US$%.2f", price.doubleValue()));
}
}
});
(I'm assuming priceProductColumn is a TableColumn<Product, Number> and Product.priceProperty() returns a DoubleProperty.)
If you have not, read this together with #James_D post.
https://docs.oracle.com/javafx/2/ui_controls/table-view.htm
I am working on a GUI application in Java for a client. One of the parts of that GUI needs to upload about a 1000 records each having 17 attributes simultaneously(i.e. it needs a 1000 X 17 table). Now Netbeans IDE 7.2.1 allows at most 100 rows at a time in a Jtable. Any suggestions how can i make one for displaying 1000 entries at a time. I considered having 10 tables one after other but that will leave a very messy coding to be done later at the back end!
Don't use an IDE to create your GUI. The IDE generates terrible code that creates a table with the null values for the number of rows that you want to create.
There is no restriction on the number of rows a table can hold. If you create the code manually you can do something simple like:
DefaultTableModel model = new DefaultTableModel(columnNames, 0);
JTable table = new JTable(model);
which will create an empty table with the column names that you specify
Then you can add rows individually using the DefaultTableModel.addRow(...) method.
Or you can add all the rows at one time by using the DefaultTableModel.setDataVector(...) method.
You can create your GUI with any IDE you like. There is no problem with Netbeans in this area. Netbeans, like any other editing tool, allows you perfectly well to create some class like i.e. MyModel that extends an AbstractTableModel, which has no GUI and you should use in order to separate your Model from the View and Controller that have a GUI.
Your JTable will then automatically call getValueAt(row, col) and getRowCount() in order to show the tiny subset of your 1.000 or maybe 1.000.000 lines that need to be displayed.
You must not necessarily load all 1000 records to any Vector or ArrayList. Just make getValueAt(row, col) read each row and return every column.
There is a high probability that your user will not scroll down every time and will not ask the TableModel to provide anything more than the 40-60 lines that should be visible after the first rendering.
This example shows the getValueAt, used on a scrollable ResultSet sr from a database:
#Override
public Object getValueAt(int row, int column) {
try {
sr.absolute(row + 1); // position your ResultSet.
switch (column) {
case 0:
return sr.getInt("...");
case 1:
return sr.getString("...");
case 2:
return sr.getString("...");
case 3:
return ......
default:
return ("-");
}
} catch (SQLException sex) {
........
}
}
This is what happens at the GUI side:
Is the JTable. Since you use a TableModel it will show you the JTable only at runtime.
Here is the place that allows you to bind your model to the auto-generated code of NetBeans.
This is the instance of your model. You could also write something like "new MyModel()" here.
The generated code is no monster either:
...
jTable1.setModel(etb);
jTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jTable1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
myMouseClicked(evt);
}
});
jScrollPane1.setViewportView(jTable1);
...
I have a custom AbstractTableModel
That model stores the data in a HashMap. So for my method for getValueAt(int rowIndex, int columnIndex)
I do
new ArrayList<Object>(data.values()).get(index);
However my data has over 2000 entries, so doing this every single time whenever I have to get the data for my table creates a huge performance hit.
So what solution can you recommend?
Should I try using List to store all my data in instead of HashMap?What is the accepted standard for storing data when using table models?
Thanks to anyone for their suggestion, and I aplogize for what might be a stupid question, but I am not too great when it comes to tables and how to store data in them.
A HashMap doesn't generally make a good fit for a table model because the table needs the ability to access data at an row/col location.
A ArrayList of ArrayLists is a reasonable way to store a table model. This still gives you fast access. Getting to a particular row is a constant time lookup, and then getting the column is also a constant time lookup.
If you don't want the overhead of the lists, you can always store the data in a 2D array.
Yes, the code you sight is going to suck in performance terms - for every cell you render, you're creating a new ArrayList based on the values in your Map (you can do the math).
At the very least, do the list creation once, probably in the constructor of your table model, like this (which assumes you've got some arbitary object, that you don't mention in your question, as the values of the map):
public class MyTableModel extends AbstractTableModel
{
private static final int COLUMN_0 = 0;
private static final int COLUMN_1 = 1;
private List<MyObject> data;
public MyTableModel(Map<?, MyObject> data)
{
this.data = new ArrayList<MyObject>(data.values());
}
public Object getValueAt(int rowIndex, int columnIndex)
{
switch (columnIndex)
{
case COLUMN_0: return this.data.get(rowIndex).getColumn0();
case COLUMN_1: return this.data.get(rowIndex).getColumn1();
...
case COLUMN_N: return this.data.get(rowIndex).getColumnN();
}
throw new IllegalStateException("Unhandled column index: " + columnIndex);
}
}
Can any one drop a line of code to show how to make a GlazdJTable's cell editable?
JTable table = new Jtable();
TableFormat tableFormat = GlazedLists.tableFormat(properties, headers);
model = new EventTableModel<Artikel>(filterList, tableFormat);
selectionModel = new EventSelectionModel<Artikel>(filterList);
table.setSelectionModel(selectionModel);
table.setModel(model);
// how to set table cell editable?
Note: I know that TableFormat must implement the WritableTableFormat interface. but i don't know should i create a custom table format or it is possble to set the Jtable cell editable just like a JTable.
Override TableModel's method
public boolean isCellEditable(int rowIndex, int columnIndex) to return true for editable and false for the rest cells.
The recommended way is to use a WritableTableFormat. The EventTableModel checks to see whether the table format is a WritableTableFormat and if so delegates the isEditable() question to that (as described in the EventTableModel docs). Otherwise EventTableModel assumes the table is not editable.
At the moment you're using the GlazedLists.tableFormat() convenience method rather than instantiating your own TableFormat. That's fine, there is a method precisely for this case where you specify whether each column is editable by passing in an array of booleans. See the GlazedLists.tableFormat(String[] propertyNames, String[] columnLabels, boolean[] editable) documentation.
I have question that how can I delete all datas from my jTable in GUI when a user entered a key?
thanks
You can set a new empty data model:
TableModel newModel = new DefaultTableModel();
jtable.setModel(newModel);
You need to understand that a JTable is a view of the data, while the actual data resides in the TableModel. If you need to clear out the table, then you need to clear out the TableModel.
If your TableModel is an AbstractTableModel, you must provide implementations of 3 methods:
public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);
Frequently the actual data objects are stored in an additional data structure (e.g. a list), and then the AbstractTableModel queries that list.
List<DomainObject> objects = new ArrayList<DomainObject>();
public int getRowCount() { return objects.size(); }
// How many columns you make depends on what features of the objects you're exposing.
public int getColumnCount() { return NUMBER_OF_COLUMNS; }
public Object getValueAt(int row, int column) {
DomainObject object = objects.get(row);
... // pull out the property based on the column they pass in
}
// By exposing this method, you can allow your Controller code to reach into this model
// and delete all the rows.
public void clear() {
objects.clear()
}
What HH is suggesting you do is change the model of your JTable to reference an empty model, which will in effect clear out the table. However, the columns etc. will not be persisted correctly (the new DefaultTableModel has no idea what those column names would be).
After you've researched how the view and model fit together more, take a look at GlazedLists. It allows a very powerful way to create TableModels which provide dynamic views of your data, e.g. by filtering out rows that do not match certain criteria.
To sum up - you're not going to find a method on the JTable to clear out its contents, because that's the job of the TableModel. You need some way of ensuring that the TableModel's backing data structures are cleared out.
If you are using the DefaultTableModel then you can just use:
model.setRowCount(0);
This is better than creating a new DefaultTableModel. Creating a new TableModel causes the TableColumnModel to be recreated, which means all the TableColumns will be resize to default values and recreated in the order in which the columns exist in the model. The user may have changed these properties and shouldn't be forced to do it again.
If you are just deleting certain rows that contain a particulsar value, then you can use the DefaultTableModel.removeRow(...) method. Make sure you start by deleting row from the end of the model and count down to 0.
call removeAll of j_table method at addActionListener
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
j_table.removeAll();
data_model_table.setRowCount(0);
}
});