I have a swing application where I mainly have a Jtree and a JTable. when the app starts, the tree shows a list of values and the table only displays its column names.Once a node is selected from the tree, some data related to the selected node needs to be displayed in the table.
I have a Table model class which extends the AbstractTableModel as below
import javax.swing.table.AbstractTableModel;
import java.util.List;
public class PropertiesTableModel extends AbstractTableModel{
private List<Field> fieldList;
private final static String[] columnNames= new String[]{"Field","Value"};
public PropertiesTableModel(List<Field> list){
this.fieldList=list;
}
#Override
public String getColumnName(int columnIndex){
return columnNames[columnIndex];
}
#Override
public int getRowCount() {
return fieldList.size();
}
#Override
public int getColumnCount() {
return 2;
}
//this method is called to set the value of each cell
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Field field= (Field) fieldList.get(rowIndex);
switch(columnIndex){
case 0:
return field.getFieldDef().getfName();
case 1:
return field.getDefaultValue();
}
return null;
}
#Override
public Class<?> getColumnClass(int columnIndex){
switch (columnIndex){
case 0:
return String.class;
case 1:
return Object.class;
}
return null;
}
}
from another class I use this table model as below
public void populateTableData(List<Field> list){
this.fieldList=list;
JTable propertiesTable=new JTable();
propertiesTable.setModel(new PropertiesTableModel(fieldList));
}
When I run the application and select a node from the tree, the table is not getting populated with expected data. I made sure that the fieldList data is passed to the TableModel but only the getColumnName() and the getColumnCount() methods are getting called.
I want to know if something is missing in my code.
Probably you forgot to include the fact that you need to trigger the view (JTable) to update itself from your Model if the underlying data changes in the Model (using fireTableDataChanged)... I assume that initially your list is empty and data gets added to the list and that dats is not displayed in the JTable.
I can recommend you to have a look at GlazedLists !!! (http://www.glazedlists.com/)
This freeware library suits your needs perfectly !
Related
I've added a checkbox to rows on my table, but unfortunately I'm unable to select/deselect them.
I'm using an own Table Model that I got on internet.
Table Model's code:
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
/**************/
public class ModeloTabela extends AbstractTableModel {
private ArrayList linhas = null;
private String [] colunas = null;
public ModeloTabela(ArrayList lin, String[] col){
setLinhas(lin);
setColunas(col);
}
public ArrayList getLinhas(){
return linhas;
}
public void setLinhas(ArrayList dados){
linhas = dados;
}
public String[] getColunas(){
return colunas;
}
public void setColunas(String [] nomes){
colunas = nomes;
}
public int getColumnCount(){
return colunas.length;
}
public int getRowCount(){
return linhas.size();
}
public String getColumnCount (int numCol){
return colunas[numCol];
}
public Object getValueAt(int numLin, int numCol){
Object[] linha = (Object[])getLinhas().get(numLin);
return linha[numCol];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) {
return true;
}
}
And this Method will fill the Table:
public void PreencheTabela(String sql, JTable jt1, JTextField j1){
c.conexao();
ArrayList dados = new ArrayList();
String [] Colunas = new String[] {"STATUS", "ID", "FABRICANTE", "FORNECEDOR", "NOME", "CATEGORIA", "DATA DO CADASTRO", " CODIGO DE BARRAS", "QUANTIDADE"};
c.executaSQL(sql);
try {
c.rs.first();
do{
dados.add(new Object[]{c.rs.getInt("prod_id"),c.rs.getString("prod_fabricante"),c.rs.getString("prod_fornecedor"),c.rs.getString("prod_nome"),
c.rs.getString("prod_categoria"),c.rs.getDate("prod_datacadastro"),c.rs.getString("prod_codbarras"), c.rs.getInt("est_quantidade")});
j1.setBorder(BorderFactory.createLineBorder(Color.black));
}while(c.rs.next());
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro!\n"+ex.getMessage());
}
ModeloTabela modelo = new ModeloTabela(dados, Colunas);
jt1.setModel(modelo);
}
Which code can I use? Also, where do I put this code??
but unfortunately I'm unable to select/deselect them.
You didn't implement the setValueAt(...) method in your TableModel so the value can never be updated in the model.
I'm using an own Table Model that I got on internet.
Why are you using a custom TableModel? You can use the DefaultTableModel. It implements the setValueAt(...) method correctly. It also has an addRow(..) method that allows you to dynamically update the model.
Are you actually storing Boolean objects in the TableModel? I don't see you using getBoolean() to get the data from your ResultSet. The default renderers/editors for a check box will only be used when you have Boolean data in the column.
Also take a look at: Can't create column with checkboxes in JTable for a better implementation of the getColumnClass() method.
If you insist on using your custom TableModel, then take a look at the Swing tutorial link you were given in your last question. It shows and example of implementing the setValueAt() method.
I want to add data to my own JTable model in runtime. I have the table and add button on my interface. As I understand I cant do it with two dimensional array and want to use Arraylist in my custom made table model but I dont know how to make the constructor if I use such type of data.
static String[] columnNames = {"A", "B", "C"};
static Object data[][] = new Object[15][3];
public MyTableModel() {
super(data, columnNames);
}
this is the constructor for data as two dimansional array but I want to use:
ArrayList<Object[]> data = new ArrayList<Object[]>();
How to make it
One way to do it, is to use AbstractTableModel. Here is an example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public class TestTable {
public static class MyModel extends AbstractTableModel {
private List<Object[]> data;
private List<String> columnNames;
public MyModel(List<String> columnNames, List<Object[]> data) {
super();
this.columnNames = columnNames;
this.data = data;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnNames.size();
}
#Override
public String getColumnName(int column) {
return columnNames.get(column);
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex)[columnIndex];
}
}
protected void initUI() {
JFrame frame = new JFrame(TestTable.class.getSimpleName());
List<String> columns = Arrays.asList("Name", "Age");
List<Object[]> data = new ArrayList<Object[]>();
for (int i = 0; i < 50; i++) {
Object[] value = new Object[2];
value[0] = "Name-" + i;
value[1] = 12 + i;
data.add(value);
}
JTable table = new JTable(new MyModel(columns, data));
frame.add(new JScrollPane(table));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestTable().initUI();
}
});
}
}
If you need to to modify your data List<Object[]>, don't forget to fire appropriate Table Events. AbstractTableModel contains them all already.
It's a bit hard to tell what you're doing as you haven't included the full source code of your table model, so I'm going to make a few assumptions here.
You're probably either extending AbstractTableModel or DefaultTableModel. In either case, you shouldn't have to add your data to the model via the constructor. Instead, you will want to override the following methods in your TableModel extension:
getRowCount()
getColumnCount()
getValueAt(int row, int column)
Make it so that each of these methods indexes into your ArrayList<Object[]> data object - e.g., getValueAt(row,column) should return something like data.get(row)[column]. Then add your TableModel to a JTable and you should be good to go, as far as displaying the custom data goes.
Now... when your data changes (either you changed the value of a cell in the table or you added/removed rows), you just call fireTableDataChanged() on your TableModel (assuming it has extended AbstractTableModel or one of its subclasses). This will force the UI to update with the changes you made to the underlying data.
The most straightforward way to create your own table model is to inherit from AbstractTableModel. Then override, at a minimum, getRowCount, getColumnCount, and getValueAt.
You can then either create the table using "new JTable(mymodel)", where "mymodel" is an instance of the model you have created, or you could create it with just "new JTable", and then later do setModel to attach your model to the JTable.
For example -- and while I've done this a bazillion times, I'm writing this off the top of my head so no warranties expressed or implied, odds are there's a syntax error or two in there somewhere:
class ArrayListModel extends AbstractTableModel
{
ArrayList<Object[]> list;
public ArrayListModel(ArrayList<Object[]> list)
{
this.list=list;
}
public int getRowCount()
{
return list.size();
}
public int getColumnCount()
{
if (list.size()==0)
{
return 0;
}
else
{
return list.get(0).length;
}
}
public Object getValueat(int row, int column)
{
return list.get(row)[column];
}
}
... somewhere else ...
ArrayListModel mymodel=new ArrayListModel(somedata);
JTable mytable=new JTable(mymodel);
... etc ...
Side note: When I was first learning Java, I thought that the "normal" way to create a JTable was to use the default model, create a vector of vectors or a 2-D array and then populate. I thought creating your own model would be something you did in rare, odd cases. But I've since figured out that the default model is only the best way in rare, simple cases. Now I almost always create my own model: it's usually easier to code and easier to understand. Typically I have an ArrayList of some class that I've created with specific fields, and then in my model class I have something like:
public Object getValueAt(int row, int col)
{
Whatever w=list.get(row);
if (col==0) return w.foo;
else if (col==1) return w.bar;
else if (col==2) return w.plugh;
else throw SomeException();
}
Or use a case statement. Same idea.
I have a sample code that we use to dynamic row numbers in Java Swing Table i.e JTable. I new to JavaFX and would like to the same in JavaFX. Is there is any way to set automatic row numbers in JavaFX Table
class LineNumberTable extends JTable {
private JTable mainTable;
public LineNumberTable(JTable table) {
super();
mainTable = table;
setAutoCreateColumnsFromModel(false);
setModel(mainTable.getModel());
setAutoscrolls(false);
addColumn(new TableColumn());
getColumnModel().getColumn(0).setCellRenderer(mainTable.getTableHeader().getDefaultRenderer());
getColumnModel().getColumn(0).setPreferredWidth(40);
setPreferredScrollableViewportSize(getPreferredSize());
}
#Override
public boolean isCellEditable(int row, int col) {
if (col == uneditableColumn) {
return false;
}
return bEdit;
}
#Override
public Object getValueAt(int row, int column) {
return Integer.valueOf(row + 1);
}
#Override
public int getRowHeight(int row) {
return mainTable.getRowHeight();
}
}
In JavaFX, you use TableColumns with CellFactories and CellValueFactories to populate your TableView.
The JavaFX tutorials have an article that might get you started.
In one approach I have used I convert the business objects to display into presentation objects and add all necessary properties (like in your case, the number) to them.
EDIT: In a second, cleaner approach, you could set your CellFactory to create a TableCell that shows its own index property in TableCell#updateItem(S, boolean):
public class NumberedCell extends TableCell{
protected void updateItem(Object object, boolean selected){
setText(String.valueOf(getIndex());
}
}
I'm using Glazed lists, in a jTable where I have a column which is boolean.
By default the jTable renders a checkbox where the column is type Boolean.Class.
Using Glazed lists i cannot get the checkbox which is needed. I rendered checkboxs extending the DefaultTableCellRenderer but i'm not satisfied with it because the checkboxs are not "clickable".
In the GL faq http://www.glazedlists.com/documentation/faq i found:
*Q: How do I specify that my boolean table cells be rendered with a checkbox?
For some reason, Glazed Lists has no getColumnClass() method.
A: If you need to specify the column class, you need to implement the AdvancedTableFormat interface instead of the regular TableFormat class.
If you are using the GlazedLists.tableFormat() factory method, you must specify the base Object's class for a proper implementation of the AdvancedTableFormat.getColumnClass() method.*
Does some of you have experience with this I did not find any links with an example. The essential link in the faq is broken.
I tried with this:
public class CheckBoxTableModel implements AdvancedTableFormat {
public Class getColumnClass(int column) {
if(column==4)
return Boolean.class;
else
return Object.class;
}
}
Please help!
EDIT:
I tried with this, the form with the jtable does not show
private class TicketTableFormat implements AdvancedTableFormat<Ticket> {
private final String[] cols = new String[]{"Id", "From", "Subject", "Date", "Incomplete"};
public int getColumnCount() {
return cols.length;
}
public String getColumnName(int colId) {
return cols[colId];
}
public Class getColumnClass(int col) {
if (col == 4) {
return Boolean.class;
} else {
return Object.class;
}
}
public Object getColumnValue(Ticket ticket, int colId) {
switch (colId) {
case 0:
return ticket.getId();
case 1:
return ticket.getFrom();
case 2:
return ticket.getSubject();
case 3:
return ticket.getDate();
case 4:
return ticket.getIncomplete();
}
return null;
}
public boolean isEditable(Ticket e, int col) {
if (col < 4) {
return false;
} else {
return true;
}
}
public Ticket setColumnValue(Ticket e, Object o, int i) {
e.setB((Boolean) editedValue);
return e;
}
public Comparator getColumnComparator(int i) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
i call it with this:
TicketTableFormat tbFormat = new TicketTableFormat();
TicketsModel = new EventTableModel(textFilteredTickets, tbFormat);
ticketTable.setModel(TicketsModel);
The basic point here is that rendering table cells and eiting them are two different things. For table cell rendering, the renderer only serves as a 'stamp', i.e. the check box is initialized to the state that should be rendered and aterwards the Table only takes apicture of the renderer (by invoking its paint method) and places the tat picture in the appropriate cell - for rendering all the cells, the same instance of checkbox is re-configured over and over again to represent the according cell value. What you did in your code, is specifying the data type flavor of the model, so that the default table cell renderer chosen by the table is a checkbox renderer.
For the checkbox to be editable, a cell editor must be attached to the table cell (e.g. by configuring an editor for the particular column). In case a table cell receives input focus, the table cell editor component is initialized and placed inside the table cell (i.e. above the image that was painted by the renderer before). This cell editor component (would be a checkbox in your case) is remainig there (accepting user input via mouse or keyboard) until the user navigates away from that particzular table call. In the moment when editing ends, the cell editor is asked for the vale it has captured from the editing process, (i.e. getCellEditorValue() is called on the editor) and hte value is taken by the table and written back to the table model for that cell.
So in short: The renderer is only stamping data on the cell, i.e. outputting, an editor component is necessary to receive input.
Example code for custom table cell editor
Java tuorial explaining the thing in detail and having also checkbox examples and code
Did you implement isEditable(...) & setColumnValue(...) in your implementation of AdvancedTableFormat?
Implementing the following methods works for me.
public int getColumnCount()
public String getColumnName(int column)
public Object getColumnValue(E model, int column)
public boolean isEditable(E model, int column) // For making the checkbox editable
public IFdsModel setColumnValue(E model, Object value, int column)
public Class getColumnClass(int column) // For making it a Checkbox
public Comparator<E> getColumnComparator(int arg0) // for sorting (if you have a SortedList)
Edit: an example (quick and dirty)
import java.util.Comparator;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.gui.AdvancedTableFormat;
import ca.odell.glazedlists.gui.WritableTableFormat;
import ca.odell.glazedlists.swing.EventTableModel;
public class Tester {
private static class MyBoolean {
private Boolean b = Boolean.FALSE;
public Boolean getB() {
return b;
}
public void setB(Boolean b) {
this.b = b;
}
}
private static class BooleanTableFormat implements AdvancedTableFormat<MyBoolean>, WritableTableFormat<MyBoolean> {
#Override
public int getColumnCount() {
return 1;
}
#Override
public String getColumnName(int column) {
return "Bool";
}
#Override
public Object getColumnValue(MyBoolean baseObject, int column) {
return baseObject.getB();
}
#Override
public Class getColumnClass(int column) {
return Boolean.class;
}
#Override
public Comparator getColumnComparator(int column) {
throw new IllegalStateException("Not yet implemented.");
}
#Override
public boolean isEditable(MyBoolean baseObject, int column) {
return true;
}
#Override
public MyBoolean setColumnValue(MyBoolean baseObject, Object editedValue, int column) {
baseObject.setB((Boolean) editedValue);
return baseObject;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
EventList<MyBoolean> list = new BasicEventList<MyBoolean>();
list.add(new MyBoolean());
list.add(new MyBoolean());
EventTableModel<MyBoolean> etm = new EventTableModel<MyBoolean>(list, new BooleanTableFormat());
JTable table = new JTable(etm);
JFrame f = new JFrame("Tester");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.getContentPane().add(new JScrollPane(table));
f.setVisible(true);
}
});
}
}
I have developed a basic custom JTableModel as follows
public class CustomTableModel extends DefaultTableModel {
List<MyClass> data;
public CustomTableModel(List<MyClass> data) {
this.data = data;
}
public Class<?> getColumnClass(int columnIndex) {
return MyClass.class;
}
public MyClass getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex);
}
// ...
}
I then use a basic custom JTableCellRenderer as follows
public class CustomTableCellRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
MyClass myClass = (MyClass)value;
lbl.setText(myClass.getString());
return this;
}
}
I also have a custom JPanel that displays various information as follows
public class MyPanel extends JPanel {
private MyClass myClass;
public MyPanel(MyClass myClass) {
// initialize components
}
public setMyClass(MyClass myClass) {
this.myClass = myClass;
updateFields();
}
private void updateFields() {
this.fieldString.setText(myClass == null ? "" : myClass.getString());
// ...
}
}
Finally, I use a table to list my data and the custom panel to display the details of the selected data.
public class JCustomFrame extends JFrame {
public JCustomFrame(List<MyClass> data) {
// ...
JTable table = new JTable(new CustomTableModel(data));
table.setDefaultRenderer(MyClass.class, new CustomTableCellRenderer());
}
}
What I am trying to accomplish is get the selected MyClass from the table regardless of sorting.
I tried ListSelectionListener but the methods do not return anything other than the selected indexes. Even if I have the index, if the table is sorted, my model is not so sophisticated and will return the wrong object.
...Even if I have the index, if the table is sorted, my model is not so sophisticated and will return the wrong object...
You have to use:
JTable.convertRowIndexToModel( int viewIndex )
Maps the index of the row in terms of the view to the underlying TableModel. If the contents of the model are not sorted the model and view indices are the same.
With that index you can access your table model and see what's the object you need.
Note Table sorting along with this method was introduced in Java 1.6