Im using Window Builder plugin in eclipse to make all the visual components, and i add a JTable, and at first it was a simple JTable, and it show the data correctly. Since i need that the data of the JTable be non-editable, i create a model to use the method isCellEditable. my code is this.
public class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private String[] columnNames;
private Object[][] data;
public MyTableModel(Object[][] sentdata, String[] cnames){
columnNames = cnames;
data = sentdata;
}
#Override
public int getColumnCount() {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getRowCount() {
// TODO Auto-generated method stub
return 0;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
// TODO Auto-generated method stub
return null;
}
public boolean isCellEditable (int row, int column){
return false;
}
}//fin del modelo
and in the constructor of the class is this
String[] NombresdeColumnas = {"Nombre del Producto", "Cantidad en Inventario", "Precio Unitario"};
RegistroInventario inventariodatos = new RegistroInventario();
Object[][] data = inventariodatos.regresarInventario();
MyTableModel model1 = new MyTableModel(data, NombresdeColumnas);
Table_Inventario = new JTable(model1);
Table_Inventario.setGridColor(Color.gray);
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setViewportView(Table_Inventario);
and it doesnt show anything, but when i was doing this:
Table_Inventario = new JTable(data, NombresdeColumnas);
it was working just fine, i donĀ“t know if the error has todo with de Window Builder form eclipse or in the code cause im new doning JTables.
your issue is return 0; in
public int getColumnCount() {
and
public int getRowCount() {
use DefaultTableModel instead, sure if isn't there really important issue to use AbstractTableModel for Object[][] data or Vector of Vectors
usage of AbstractTableModel make me sence for model based on HashMap or java.util.List e.i.
Your AbstractTableModel does not contain any data.
You indicate it contains zero rows and zero columns by your implementation of the getColumnCount and getRowCount methods.
And even when you adjust those methods, you do not use the data passed in the constructor as you always return null in the getValueAt method.
I think you should start reading the 'How to create a TableModel' section from the table tutorial
Related
I have a JFrame which has a JTable and it can represent data from database. Everything is fine but I want to load or refresh it from another class after a delete operation.
I have already done the delete operation but I can not load the JTable from another class. My code is below:
scrollPane = new JScrollPane();
add(scrollPane, BorderLayout.CENTER);
DefaultTableModel model=null;
try {
model = makeTableModel();
} catch (SQLException | IOException e) {
e.printStackTrace();
}
table = new JTable(model);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
int row = table.getSelectedRow();
String getvalue = (table.getModel().getValueAt(row, 4).toString());
PopulatePhotographerClass pp=new PopulatePhotographerClass(getvalue);
}
});
table.setRowHeight(200);
scrollPane.setViewportView(table);
Here is my makeTableModel method:
public static DefaultTableModel makeTableModel() throws SQLException, IOException {
DefaultTableModel model = new DefaultTableModel(new String[]{"Image", "Name","Address","mobile-Number","NID"}, 0) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Icon.class : super.getColumnClass(columnIndex);
}
};
String cmd = "select * from photographer_lookup";
try (Connection con =database.DbConnect.getconnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
String name = rs.getString(3);
Blob blob = rs.getBlob(1);
String address=rs.getString("address");
String mobile=rs.getString("mobile_number");
String nid=rs.getString("Nid");
ImageIcon icon = null;
try (InputStream is = blob.getBinaryStream()) {
BufferedImage img = ImageIO.read(is);
icon = new ImageIcon(img);
}
model.addRow(new Object[]{icon,name,address,mobile,nid});
}
}}}
return model;
}
This is my code that I wrote. Now I want to define a method that does all work which is mentioned above and also it will be called by another class.
First off, you are making a mistake in using view indices to index the model. Listeners and all methods from JTable that return row or column indices will report view indices (except convertXXXIndexToModel methods).
As the table is sorted or columns are moved around, view indices will differ from model indices. JTable will not sort the model or rearrange columns in the model, rather it will change its mapping to the model.
If what you have is view indices and you want to look up cell values, either
Use JTable.getValueAt, which takes view indices
First convert view indices to model indices using JTable.convertRowIndexToModel and JTable.convertColumnIndexToModel before indexing in the model (JTable.getModel()).
Your mouse listener should read:
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
int row = table.getSelectedRow();
if( row < 0 ) return; // check if a row is selected first!
String getvalue = table.getValueAt(row, table.convertColumnIndexToView( 4 ) ).toString(); // use table.getValueAt, this getter takes view indices! Use convertColumnIndexToView to get a view index from a model index!
PopulatePhotographerClass pp=new PopulatePhotographerClass(getvalue);
}
});
Better still would be to implement a ListSelectionListener to listen for selection events, rather than using a MouseListener to act on selection events (thanks #mKorbel for pointing that out). This way you would be notified directly on list selection changes.
If you want operations to be done from another class, write a public method in your class that extends JFrame that does this work. If you have an instance to this class in another class, simply call this newly created public method.
Suppose your JFrame class is called MyFrameWithJTable
public class MyFrameWithJTable extends JFrame {
public void doSomeWork( /*parameters required in the operation*/ ) {
// Does the work you want to call from another class
// Eg the updates you want done in the JTable's model
}
}
Then in another class, if you have an instance of the MyFrameWithJTable class you can do
public class AnotherClass {
private MyFrameWithJTable instance;
public AnotherClass( MyFrameWithJTable instance ) {
this.instance = instance;
}
public void someMethod( ) {
instance.doSomeWork( /*supply parameters*/ );
}
}
Can someone help me with this?
It was working until I changed something trying to optimaze it... damn!
This is my table model:
class MyTableModel extends DefaultTableModel {
private String[] columnNames = {"Last Name","First Name","Next Visit"}; //column header labels
Object[][] data = new Object[100][3];
public void reloadJTable(List<Customer> list) {
for(int i=0; i< list.size(); i++){
data[i][0] = list.get(i).getLastName();
data[i][1] = list.get(i).getFirstName();
if (list.get(i).getNextVisit()==null) {
data[i][2] = "NOT SET";
} else {
String date = displayDateFormat.format(list.get(i).getNextVisit().getTime());
data[i][2] = date;
}
model.addRow(data);
}
}
public void clearJTable() {
model.setRowCount(0);
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,
* then the last column would contain text ("true"/"false"),
* rather than a check box.
*/
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don't need to implement this method unless your table's
* editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
}
and this is how I implement the JTable:
// these declarations are all private shared across the model
JTable customerTbl;
MyTableModel model;
List<Customer> customers = new ArrayList<Customer>();
SimpleDateFormat displayDateFormat = new SimpleDateFormat ("EEE dd-MM-yyyy 'at' hh:mm");
//JTable configuration
model = new MyTableModel();
customerTbl = new JTable(model);
model.reloadJTable(customers);
customerTbl.setAutoCreateRowSorter(true); //enable row sorters
DefaultRowSorter sorter = ((DefaultRowSorter)customerTbl.getRowSorter()); //default sort by Last Name
ArrayList list = new ArrayList();
list.add( new RowSorter.SortKey(0, SortOrder.ASCENDING));
sorter.setSortKeys(list); //EXCEPTION HERE
sorter.sort();
customerTbl.getColumnModel().getColumn(0).setPreferredWidth(100); //set Last Name column preferred width
customerTbl.getColumnModel().getColumn(1).setPreferredWidth(80); //set First Name column preferred width
customerTbl.getColumnModel().getColumn(2).setPreferredWidth(150); //set Last Visit column preferred width
I'm getting the following exception triggered on:
sorter.setSortKeys(list);
Exception in thread "main" java.lang.IllegalArgumentException: Invalid SortKey
at javax.swing.DefaultRowSorter.setSortKeys(Unknown Source)
at com.vetapp.customer.CustomersGUI.<init>(CustomersGUI.java:128)
at com.vetapp.main.VetApp.main(VetApp.java:31)
I believe it has to do with the TableColumnModel which is not created correctly...
The main problem is that the column count is returning 0 from the TableModel's super class DefaultTableModel. You need to override this method
#Override
public int getColumnCount() {
return columnNames.length;
}
Another side but potentially fatal issue is the fact that getColumnClass is returning the class of elements within the TableModel. This will throw a NullPointerException if the table is empty. Use a class literal instead such as String.class.
Maintaining a separate backing data array is unnecessary for DefaultTableModel. It has already has its own data vector. This approach is used when extending AbstractTableModel.
Hi I converted my arraylist into an array so I can use it to display its elements in a JTable but nothing is displaying. It is giving me an error (error is explained in code comments). I just want to have one column only which displays values from this array. Can someone guide me in the correct direction? Thanks
Here is my code:
private static class EnvDataModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private static ArrayList<Integer> list = new ArrayList<Integer>();
private Object age[];
...
public EnvDataModel() {
age=list.toArray();
}
public String getColumnName(int col) {
return "Age";
}
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return list.size();
}
public Object getValueAt(int row, int col) {
// Error message The method get(int) in the type ArrayList<Integer> is not applicable for the arguments (Object)
return list.get(age[row]);
}
}
1) ArrayList in the AbstractTableModel returns Column, please read tutorial about JTable how TableModel works
2) you can change ArrayList<Integer> to the Vector<Vector<Integer>> or Interger[][], then you don't need to define for AbstractTableModel, only use default contructor for JTable
JTable(Object[][] rowData, Object[] columnNames)
or
JTable(Vector rowData, Vector columnNames)
3) add Integer value to the DefaultTableModel
list.get(age[row]); requires list.get(int) whereas age[row] is object.
So, try this
int i =Integer.parseInt( age[row].toString() );
and than
list.get(i);
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];
}
I followed Oracle's model for implementing an AbstractTableModel
http://download.oracle.com/javase/tutorial/uiswing/examples/components/TableDemoProject/src/components/TableDemo.java
I did this because my table has to contain 3 columns, and the first has to be a JCheckBox.
Here's my code:
public class FestplattenreinigerGraphicalUserInterfaceHomePagePanelTableModel extends AbstractTableModel {
private String[] columnNames = {"Auswahl",
"Dateiname",
"Pfad"};
private Object[][] data = {
{new Boolean(true), "datei.tmp",
"/home/user/tmp"}
};
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];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) {
if (col == 0) {
return true;
} else {
return false;
}
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
Here are my questions:
How does JTable (new JTable(FestplattenreinigerGraphicalUserInterfaceHomePagePanelTableModel)) know what the column names are and their values are? Since there's no contructor in my AbstractTableModel?! Is it becaue columnNames and data must be named like they are and JTable accesses them?
How can i put new Values in my JTable? Since columnNames and data are arrays. Can i replace them with vectors? If so, how do I init these vectors? In a constructor in myAbsTableModel?
I think it's very easy to get a solution but this Table handling isn't trivial to me, so thank u very much!
All Swing components come with default model implementations. I suggest you understand how to use them first before trying to create your own. For a JTable its called the DefaultTableModel. Read the API for methods to dynamically add/remove rows of data from the model. Here is a simple example to get you started:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableBasic extends JPanel
{
public TableBasic()
{
String[] columnNames = {"Date", "String", "Integer", "Boolean"};
Object[][] data =
{
{new Date(), "A", new Double(1), Boolean.TRUE },
{new Date(), "B", new Double(2), Boolean.FALSE},
{new Date(), "C", new Double(9), Boolean.TRUE },
{new Date(), "D", new Double(4), Boolean.FALSE}
};
JTable table = new JTable(data, columnNames)
{
// Returning the Class of each column will allow different
// renderers and editors to be used based on Class
public Class getColumnClass(int column)
{
for (int row = 0; row < getRowCount(); row++)
{
Object o = getValueAt(row, column);
if (o != null)
return o.getClass();
}
return Object.class;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("TableBasic");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TableBasic() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
First, I think you need to learn a bit more about Java, especially inheritance (I'm referencing your constructor problem.
Answers to your questions :
define your column names via a private final static attribute, assuming your column names don't change.
since your class extends AbstractTableModel, you can define a constructor for it, where you'll pass the data. Redefine the getValueAt method to allow the model to use the data you're passing.
Some more advice :
don't do what you're doing in getColumnClass. Normally, all elements in a column will have the same class, so do a switch on the column index to get the classes.
to add a JCheckBox in one of your columns, you'll have to use a custom TableCellRenderer
The JTable determines how many columns by calling getColumnCount() on your column model. It then iterates and calls getColumnName(idx) for each column. Your class tells it the column name -- look at your implementation of those methods.
You can store your data in whatever format you want. The JTable calls methods on your table model to retrieve that data. If you want to add new items to your model, you can implement an addItem(Object o) method to your model; just be sure to call fireTableRowsInserted() for each new item.