I try to put my ResultSet data into a JTable with help of DefaultTableModel class. As a solution I found a solution on Stackoverflow but modified it a bit (not really relevant here):
public static DefaultTableModel buildTableModel(ResultSet rs) {
try {
ResultSetMetaData metaData = rs.getMetaData();
Vector<String> columnNames = new Vector<String>();
int columnCount = metaData.getColumnCount();
for (int column = 1; column <= columnCount;++column) {
columnNames.add(metaData.getColumnName(column));
}
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
while (rs.next()) {
Vector<Object> vector = new Vector<Object>();
for (int columnIndex = 1; columnIndex <= columnCount;++columnIndex) {
vector.add(rs.getObject(columnIndex));
}
data.add(vector);
}
return new DefaultTableModel(data, columnNames);
} catch(SQLException e) {
e.printStackTrace();
return new DefaultTableModel(new Vector<>(), new Vector<>());
}
}
While I debugged this code I was able to see that:
ResultSet rs has data,
ColumnNames is populated,
RowCount is zero
and I think the issue is this line vector.add(rs.getObject(columnIndex));
It looks like my vector becomes empty because getObject() returns already no data.
Can someone help me with this or explains where the issue is? When I bind my generated DefaultTableModel to my JTable it is empty (no data is shown).
I recommend using the AbstractTableModel as a base. Some years ago, I found within the examples from Sun a class called JDBCAdapter.java. This class does, what you want. Search the web for this class and you will have something, that fulfills probably most of your needs. It might be a challenge, if your application should be able to write changes back to the DB, but just for displaying the table its fine.
I just found the issue short time ago: the problem was the fact that the cursor was set to last row because other methods iterated over the same ResultSet already and thus the cursor had to be set to first row again with first-method of ResultSet class.
Related
I am using JTable in swing to display a MySQL table, although the table values are present in the row object (as in the output in screenshot) but jtable in the application is empty.
The output in the screenshot shoes the Object[] array but when I pass this in the addRow method, it doesn't show anything on the JTable GUI.
private void tableSubmitButtonActionPerformed(java.awt.event.ActionEvent evt) {
//fetch the name of the database to be created
String dbName = tableDBName.getText();
//fetch the root password
String password = new String(tableDBPass.getPassword());
// fetch table name
String tableName = tableTableName.getText();
DefaultTableModel tableModel = (DefaultTableModel)tableViewTable.getModel();
int rowCount = tableModel.getRowCount();
for(int i = 0; i<rowCount; i++){
tableModel.removeRow(0);
}
try{
// create connection
CreateConnection newCon = new CreateConnection();
Statement newStat = newCon.initiate(dbName, password);
// result set contains the data fetched from the MySQL table
ResultSet rs = newStat.executeQuery("select * from "+tableName);
// get column names and column count
ResultSetMetaData metaData = rs.getMetaData();
int n_columns = metaData.getColumnCount();
ArrayList<String> columnNames = new ArrayList<>();
for(int i = 1; i<=n_columns; i++){
columnNames.add(metaData.getColumnName(i));
}
while(rs.next()){
ArrayList row = new ArrayList(n_columns);
for(int i = 1; i<=n_columns; i++){
row.add(rs.getObject(i));
}
Object[] obj = row.toArray();
tableModel.addRow(obj);
System.out.println("table updated..: "+Arrays.toString(obj));
}
}catch(SQLException e){
System.out.println(e.getMessage());
}
}
Besides this I deleted all the rows that are initially present when you insert the JTable in the form.
DefaultTableModel tableModel = (DefaultTableModel)tableViewTable.getModel();
So you start with an empty TableModel, which means the model has no columns or rows.
So even though you invoke the addRow() method, your model has no columns so there is nothing to display in the JTable
ArrayList<String> columnNames = new ArrayList<>();
for(int i = 1; i<=n_columns; i++){
columnNames.add(metaData.getColumnName(i));
}
The above code does nothing. All it does is add some data to an ArrayList, but that ArrayList is never used.
What you want to do is:
Use a Vector, not an ArrayList
Then you need to create an empty DefaultTableModel with just the columns names. Read the API for the appropriate constructor.
Then in your logic that iterates through the ResultSet you want to:
Again use a Vector for each row of data
add the data to the Vector
invoke the addRow(...) method of the model. The model will also accept a Vector so there is no need to convert it to an array
After all the data is added to the model you then need to:
Use tableModelView.setModel(...) to replace the model in your table.
Now your table model will have both columns and rows of data.
I am trying to show a data into a table but got some error there. The method I have used returns me all the related data but when I try to bind data into table it shows me error and error says:
The requested operation is not supported on forward only result sets.
This is how I implemented my code:
public class Table {
public static DefaultTableModel buildDataTable(ResultSet rs) {
ResultSetMetaData metaData;
Object[][] data = null;
Object[] columnNames = null;
try {
metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
columnNames = new Object[columnCount];
int index = 0;
for (int column = 1; column <= columnCount; column++) {
columnNames[index] = metaData.getColumnName(column).toUpperCase();
index++;
}
rs.last();
data = new Object[rs.getRow()][columnCount];
rs.beforeFirst();
while (rs.next()) {
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
data[rs.getRow() - 1][columnIndex - 1] = rs.getObject(columnIndex);
}
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
return new DefaultTableModel(data, columnNames);
}
}
Following code shows how I have bound data into jtable:
try {
dtm = com.gaurav.auctionhouse.common.Table.buildDataTable(new ItemDAOImp().getItemByUserId(MainClass.userId));
jTable1.setModel(dtm);
} catch (SQLException ex) {
Logger.getLogger(SellerPage.class.getName()).log(Level.SEVERE, null, ex);
}
The method to return a data in terms of ResultSet
public ResultSet getItemByUserId(int id) throws SQLException {
String query = "SELECT id, type, description, state, reservedPrice, itemName, image FROM tbl_item WHERE userId = ?";
try {
pst = DBConnection.getConnection().prepareStatement(query);
pst.setInt(1, id);
res = pst.executeQuery();
return res;
} catch (SQLException ex) {
throw new SQLException(ex);
} finally {
DBConnection.getConnection().close();
}
}
The full stacktrace
com.microsoft.sqlserver.jdbc.SQLServerException: The requested operation is not supported on forward only result sets.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:191)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.throwNotScrollable(SQLServerResultSet.java:414)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.verifyResultSetIsScrollable(SQLServerResultSet.java:437)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.last(SQLServerResultSet.java:1477)
at com.gaurav.auctionhouse.common.Table.buildDataTable(Table.java:34)
at com.gaurav.auctionhouse.view.SellerPage.(SellerPage.java:29)
at com.gaurav.auctionhouse.view.AddItems.jbtnSubmitActionPerformed(AddItems.java:265)
at com.gaurav.auctionhouse.view.AddItems.access$100(AddItems.java:33)
at com.gaurav.auctionhouse.view.AddItems$2.actionPerformed(AddItems.java:111)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
Hoping for positive response.
This:
rs.last();
data = new Object[rs.getRow()][columnCount];
rs.beforeFirst();
isn't going to work with a forward-only ResultSet. Apart from that, fetching the last row and getting its number is not a very reliable way of determining the number of rows, quite apart from performance considerations.
Also, the JavaDoc on ResultSet states the following:
Note:Support for the getRow method is optional for ResultSets with a result set type of TYPE_FORWARD_ONLY
So that's not going to work either.
The root of your problem, however, is that you're using arrays. Arrays in Java are best avoided, because the Collection framework offers much more flexibility.
In your case, make data a List<Object[]>, and create a new Object[columnCount] for each row read from the database. Better yet, use a List for that as well.
In general, your code looks like old-fashioned C converted into Java: no final variables, declaring the variables at the beginning of the code, not using the Collections framework, etc. That is something that you may want to take a look at.
Edit: Adding the correct solution... sure, but you need to learn Java properly. You may get a solution now, but you'll still need to write code. The below still has issues, such as the exception handling, which also stops me from making all variables final, but you can deal with that yourself.
public class Table {
public static DefaultTableModel buildDataTable(final ResultSet rs) {
final List<Object[]> data = new ArrayList<>();
String[] columnNames = null;
int columnCount = 0;
try {
final ResultSetMetaData metaData = rs.getMetaData();
columnCount = metaData.getColumnCount();
columnNames = new String[columnCount];
for (int column = 0; column < columnCount; column++) {
columnNames[column] = metaData.getColumnName(column + 1).toUpperCase();
}
while (rs.next()) {
final Object[] row = new Object[columnCount];
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
row[columnIndex] = rs.getObject(columnIndex + 1);
}
data.add(row);
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
return new DefaultTableModel(data.toArray(new Object[data.size()][columnCount]), columnNames);
}
}
This is happened due to lower version of sql server if you are using JPA or hibernate or simple jdbc then change your driver if its lower than 2006 of mssql and if its above or equal to 2006 version then change your dialect in hbm configuration.
I want to display column name row while accessing table. Here I tried this code... but only table displayed without column name.
using java eclipse and sqlite database
try
{
String query="Select * from client";
PreparedStatement pst=conn.prepareStatement(query);
ResultSet rs=pst.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
DefaultTableModel tm = (DefaultTableModel) table.getModel();
for(int i=1;i<=columnCount;i++)
{
tm.addColumn(rsmd.getColumnName(i));
}
while (rs.next())
{
String[] a = new String[columnCount];
for(int i = 0; i < columnCount; i++)
{
a[i] = rs.getString(i+1);
}
tm.addRow(a);
// tm.fireTableDataChanged();
rs.close();
pst.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
You can use following code to get column names:
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount(); // get column count
for (int i = 1; i <= count; i++){
System.out.println(metaData.getColumnLabel(i));
}
ResultSet always contains the returned rows but not the column names.
To get the column names you can use below code.
ResultSetMetaData metadata = rs.getMetaData();
int columnCount = metadata.getColumnCount();
String column_names[] = new String[ columnCount ]; // define a array to store the column names
for (int i=0; i<=columnCount; i++) {
column_names[ i ] = metadata.getColumnLabel(i); // push column names into array
}
DefaultTableModel table_model = new DefaultTableModel( column_names, columnCount ); // create a table model based of the columns and column count
table=new JTable( table_model ); // create a new table with that model
String column_i = table.getModel().getColumnName(i);
Iterate through 'i'; as it represents the index of the column.
Cheers!
JScrollPane pane = new JScrollPane(table);
contentPane.add(table);
JscrollPane.add(table);
The above code is all confused:
First you create a scrollpane using the table (which is correct), but then you add the table to the content pane (which is incorrect). A table can only have a single parent so it gets removed from the scrollpane.
Then you try to add the table back to the scrollpane which won't work because you need to add the table to the viewport of the scrollpane, not the scrollpane directly.
So bottom line all you need is:
JScrollPane pane = new JScrollPane(table);
//contentPane.add(table);
//JscrollPane.add(table);
Edit:
First get the code working without the SQL. Use the above suggestion and then change your current code:
//table.setModel(DbUtils.resultSetToTableModel(rs));
table.setModel( new DefaultTableModel(5,5) );
This should display an empty table with 5 rows and 5 columns.
If you see the table then the problem is with your SQL, you are returning an empty ResultSet.
If you don't see the table then you have a problems somewhere else in your code.
I have a very simple java application intended to reach into a db and pull out a resultset based on an input on a java form. However, any parameters added to the SQL Statement end with a loss of the final record in the recordset (though it does seem to pull the proper result.)
The below code results in my entire dataset, with example at the top (as expected.)
Name|Location|Details
A|Here|7854
A|There|7854
B|Here|8761
C|Gone|5312
public void actionPerformed(ActionEvent e) {
try {
String url = "jdbc:sqlserver://localhost:1433;DatabaseName=$DBname;user=$user;password=$password";
String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
Class.forName(driver).newInstance();
Connection dbconn = DriverManager.getConnection(url);
Statement stmt = dbconn.createStatement();
ResultSet rs;
rs = stmt.executeQuery("SELECT * from schema.table");
tblServers.setModel(buildTableModel(rs));
dbconn.close();
} catch (Exception f) {
System.err.println("Downloading Servers from the Database Failed! ");
System.err.println(f.getMessage());
}
}
private DefaultTableModel buildTableModel(ResultSet rs) throws SQLException {
ResultSetMetaData rsmetaData = rs.getMetaData();
//Get Column Names
int numCols = rsmetaData.getColumnCount();
Vector<String> columnNames = new Vector<String>();
for (int column = 1; column <= numCols; column++) {
columnNames.add(rsmetaData.getColumnName(column));
}
//Iterate through rows
Vector<Object> data = new Vector<Object>();
while (rs.next()) {
Vector<Object> rows = new Vector<Object>();
for (int colIndex = 1; colIndex <= numCols ; colIndex++) {
rows.add(rs.getObject(colIndex));
}
data.add(rows);
}
return new DefaultTableModel(data, columnNames);
}
}
);
Now if I change nothing but the SQL line to any variant with a "where" clause, like:
rs = stmt.executeQuery("SELECT * from schema.table where name = 'A'");
I get:
Name|Location|Details
A|Here|7854
Or if searched for B, I get no results:
Name|Location|Details
|||
Any ideas are appreciated; I'm sure this is something extremely simple.
#Sasha: Yes, I am sure I am getting 1 result. I have tried with many permutations and it always results in either a blank resultset (but with accurate headers) or headers, and resultset, minus the final row.
#PM77-1: As soon as the code spits back the return (data, ColumnNames) my JTable has the resultset visible to the user.
#Glenn: On your suggestion, I added System.out.println(data) and 'System.out.println(rs)' to just before the 'return new DefaultTableModel'. The output is [] and SQLServerResultSet:1, respectively
#JohnnyAW The results for that with a where clause are the same as my comment above - no "tests" appear in the syslog. When I remove the where clause, I get a bunch of syslog entries with "test" prefacing my records.
Correction: I get "testtesttest" to the sum of 8 tests, my entire testing recordset. One test gets missed when I have a Where clause.
How to view database resultset in Java swing? My options are
jeditorpane
jtable.
After view that file i want to save the file either in .rtf or .pdf. how is this possible in Java desktop apps?
Note: Do not use third party API or libraries
Viewing your result - JTable is your best choice
Saving the results, well, unless you want to use a 3rd part library, you options are very limited, unless your very familiar with the various file formats you want to use.
Out of the box, I'd say CVS would be easy to achieve.
JTable will do best, here is the code for display ResultSet on JTable
public static void main(String[] args) throws Exception {
// The Connection is obtained
ResultSet rs = stmt.executeQuery("select * from product_info");
// It creates and displays the table
JTable table = new JTable(buildTableModel(rs));
JOptionPane.showMessageDialog(null, new JScrollPane(table)); // or can you other swing component
// Closes the Connection
}
The method buildTableModel:
public static DefaultTableModel buildTableModel(ResultSet rs)
throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
// names of columns
Vector<String> columnNames = new Vector<String>();
int columnCount = metaData.getColumnCount();
for (int column = 1; column <= columnCount; column++) {
columnNames.add(metaData.getColumnName(column));
}
// data of the table
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
while (rs.next()) {
Vector<Object> vector = new Vector<Object>();
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
vector.add(rs.getObject(columnIndex));
}
data.add(vector);
}
return new DefaultTableModel(data, columnNames);
}
it would be hard to export data to pdf or rtf without using 3rd party api