Displaying data from database in JTable - java

I'm writing a program using jdbc that will be an interface to database(smth like CRUD aplication). I assume that I have to write a class(e.g. DBCLass) that will do all the operations with database(select, update, insert, delete and maybe some other logic that will be reduced to these operations). User interface consists of a set of tables and a few buttons. To use a Jtable I need to implement a class(e.g Model) which is a subclass of AbstractTableModel. So this class will display my data to the user. I need to implement such model for all tables in my database schema. I don't want to write the logic in that classes that display data to the user and I think it is not very good thing to write the logic code in such classes. But it is also incorrect to load all the data from the db table to memory(e.g. ArrayList) and then display it in Model.
So, I want an advise which is the best way to solve such problem.
edit:
A small example:
Statement stmt = ....;
ResaultSet rs = stmt.executeQuery("SELECT * FROM table1");
javadoc says that executeQuery method returns a ResultSet object that contains the data produced by the given query. So If we have a lot of data(which size is more than permited size to our virtual machine), our program will fail.
So my question is still relevant

Download the source for SQuirreL SQl and have a look at the table implementation.
Some things to note:
Database tables aren't Java JTables. A table in a database is in fact a set (curse the fool who used the wrong term) with items and each item has properties (usually called "columns" which isn't a JColumn which explains why it's so hard to map the two).
A set can grow to any size. It has no intrinsic order. You can do lots of set operations on it like: union, difference, sub set.
Therefore, it's not a table, especially not a UI table.
There is no easy UI paradigm which maps "set" to "table". You can
Load N records and page through the results.
You can load more as the user scrolls down
You can count the size of the set and adjust the scrollbar accordingly. As the user scrolls through the data, it is fetched from the DB and displayed.
Pros + cons:
Solution 1 is most simple to implement and the one which users hate most. Why do they need to wait to see data again when the go backwards? This is especially frustrating if each fetch takes 15 seconds. Page ... wait ... page ... oops! There it was! Damn! Wait wait wait ... back ... wait ... aaargh.
Also databases often have a hard time to page data. For some queries, performance can be disastrous.
Solution 2 is simple to implement, especially if you can keep the ResultSet open forever. But 100% of the time, you can't. It will start to fail if you keep it open for a couple of hours or a day. After that time, the DB will think "oh, it's dead, Jim" and close the connection and your user will get a nice error message and you will get an angry user.
So you need to page here, too, but not as often. On the positive side, users need not wait again for data they already have. One huge point: If the set contains millions of rows, users intuitively understand that they need to attack the problem from a different angle as they scroll down. Eventually, they will get tired and ask for a better solution (instead of being angry at you because your stupid program can't display 15 million rows in less than 0.0000000001s).
Solution 3 is worse than #2, again. If the table grows, the UI will become unusable: Even looking at the scroll know will move you to a random place in the table. So it makes your mouse useless. And your users angry.
So I usually try a solution which:
Reads 1000 rows, max. Plus I stop after 100 rows (so the user has at least some data) if reading the rows takes more than 1 second. Usually, the query is slow and reading the result set takes virtually no time, but I like being defensive here.
On top of each column is a filter and an "order by" which can be mapped directly to SQL. That way, I can make sure that if you want the data sorted by a column, it's sorted by all values (and not only those which you can see on the screen).
This allows users to chop huge amounts of data into meaningful sub sets.

Table From Database has a couple of ideas.

Maks,
Here is another example on generic sql to table implementation:
http://www.oreillynet.com/pub/a/oreilly/java/news/javaex_1000.html
It may be a good place to look for your answer.
Also, this local question/answer may help you with ResultSet size: Java JDBC Lazy-Loaded ResultSet
Hope this helps,
Robert

This blog post explains how to lazy load data into a table model: JTable Bound to a Database With Lazy Loading

You want to use the DBTable component from the QuickTable project.
Check this SO answer with sample code usage.

Here's a class that extract data rows and columns from database.
Look at table = new JTable(rows(), columns());
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.print.PrinterException;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import com.swtdesigner.SwingResourceManager;
import java.util.*;
import java.sql.*;
import javax.swing.*;
public class listing extends JDialog {
private JTable table;
public static Vector rows() {
Vector data = new Vector();
String sql= null;
Connection C;
try {
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
C = (Connection) DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE",
"system", "manager");
Statement stmt = C.createStatement();
ResultSet rset = stmt.executeQuery("SELECT * FROM site ");
ResultSetMetaData md = rset.getMetaData();
int columns = md.getColumnCount();
while (rset.next()) {
Vector row = new Vector(columns);
for (int i = 1; i <= columns; i++) {
row.addElement(rset.getObject(i));
}
data.addElement(row);
}
rset.close();
stmt.close();
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.getStackTrace());
}
//System.out.println("lignes : "+data);
return data;
}
public static Vector columns()
{ Connection c ;
Vector cols = new Vector ();
String sql2=null;
try {
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
c = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE",
"system", "manager");
sql2 = "select * from SITE";
Statement stmt = c.createStatement();
ResultSet rs = stmt.executeQuery(sql2);
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
//récupération des noms des colonnes dans la table site
for (int i = 1; i <= columns; i++) {
cols.addElement(md.getColumnName(i));
}
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.getStackTrace());
}
//System.out.println("colonnes ::: "+cols);
return cols;
}
public static void main(String args[]) {
try {
listing dialog = new listing();
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
dialog.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public listing() {
super();
getContentPane().setLayout(null);
setTitle("Listing de la table \"SITE\"");
setBounds(100, 100, 500, 363);
setResizable(false);
final JLabel laTablesiteLabel = new JLabel();
laTablesiteLabel.setText("La table \"SITE\" contient . . . ");
laTablesiteLabel.setBounds(10, 34, 274, 16);
getContentPane().add(laTablesiteLabel);
final JLabel label = new JLabel();
label.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/130.png"));
label.setBounds(402, 18, 49, 48);
getContentPane().add(label);
final JButton okButton = new JButton();
okButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent arg0) {
dispose();
setVisible(false);
}
});
okButton.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/33-32x32.png"));
okButton.setText("Ok");
okButton.setBounds(10, 291, 148, 32);
getContentPane().add(okButton);
final JButton refeshButton_1 = new JButton();
refeshButton_1.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/48-32x32.png"));
refeshButton_1.setText("Actualiser");
refeshButton_1.setBounds(171, 291, 148, 32);
getContentPane().add(refeshButton_1);
final JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 85, 474, 187);
getContentPane().add(scrollPane);
table = new JTable(rows(), columns()); // chargement de JTable
scrollPane.setViewportView(table);
final JButton printButton_1_1 = new JButton();
printButton_1_1.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent arg0) {
try {
table.print();
} catch (PrinterException e) {
e.printStackTrace();
}
}
});
printButton_1_1.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/Printer_h.png"));
printButton_1_1.setText("Imprimer");
printButton_1_1.setBounds(336, 291, 148, 32);
getContentPane().add(printButton_1_1);
}
}

Related

I can't re-reference a TableRow with findViewById

I have an activity where I create Tablerow programatically, as I don't know how many files I need.
Each TableRow has an ID starting by 100 and continue 200, 300 and so on.
When I create the row 3 the TableRow's ID is 300.
Then when someone edit other row I need to know what row is just to work with the elements of the row.
My problem: previous value:
trActiva.getId()=300
Then this is my code I put:
lineaActiva = (tv.getId()) / 100 * 100;
trActiva = findViewById(lineaActiva);
just on the point before these two lines trActiva.getId()=300
after the first row of the code lineaActiva = 200
That means after the second line trActiva.getId() should be 200 but it is still 300.
More weird things:
after these two lines:
trActiva.getId()=300
findViewById(lineaActiva).getId()=200
What is happening here? Why trActiva is not changing?
Thank you!!
We are unsure how you are increasing your Id and how you are storing your data as well how do you view 300 rows on a computer screen
So a lot of code is missing to give a very pointed answer to your question
Here is a table we populate from a Derby Database
The table is named ptable and we might also mention we are using a Model View Controller pattern to manage the data to GET and SET variables
First we read from the Database and populate the ptable with this code
private void ReadFromParent() throws SQLException{
ObservableList<ParentModel> TableData = FXCollections.observableArrayList();
stmnt = conn.createStatement();
ResultSet rs = stmnt.executeQuery("SELECT * FROM Parent");
while (rs.next()){// Add data to observableArrayList TableData to select a table ROW
TableData.add(new ParentModel(rs.getString("PID"),rs.getString("pMonth"),rs.getString("pYear")));
}
PropertyValueFactory<ParentModel, String> IDCellValueFactory = new PropertyValueFactory<>("PID");
colID.setCellValueFactory(IDCellValueFactory);
PropertyValueFactory<ParentModel, String> DateCellValueFactory = new PropertyValueFactory<>("pMonth");
colMonth.setCellValueFactory(DateCellValueFactory);
PropertyValueFactory<ParentModel, String> TypeCellValueFactory = new PropertyValueFactory<>("pYear");
colYear.setCellValueFactory(TypeCellValueFactory);
// ================================================================
// colTxDate are the ID's for the tableview columns
// sortDate are the Column Names for the Database TABLE CDBalance
// ================================================================
colMonth.setStyle("-fx-alignment: CENTER;");
colYear.setStyle("-fx-alignment:CENTER;");
Collections.sort(TableData, (p2, p1)-> p1.getPID().compareToIgnoreCase(p2.getPID()));
// Line of Code above Sorts Database Columns based on VARIABLE in ParentModel
// Change p2,p1 to sort Ascending or Descending
if(TableData.size() < 15) {// Format TableView to display Vertical ScrollBar
ptable.setPrefWidth(336);// 19 is the off set
}else {
ptable.setPrefWidth(355);
} ptable.setItems(TableData);
stmnt.close();
}
Then we write listener code to permit us to view the details of the row selected
Notice we get the ID from the row selected
This is where you can use that value to find the new entry that is greater than 300
OR you can write a Search query on the table that finds all records that have an ID greater than 300
Here is the code that permits you to click on a row in the table
private void showTableDataDetails(ParentModel info) throws IOException{
if (info != null) {
info = (ParentModel) ptable.getSelectionModel().getSelectedItem();
strID = info.getPID();
strMONTH = info.getPMonth();
strYEAR = info.getPYear();
toChildView();
System.out.println("########### PID "+strID);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
ptable.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends ParentModel>
observable,ParentModel oldValue, ParentModel newValue) -> {
try {
showTableDataDetails((ParentModel) newValue); // When a row of the table is Selected call
// Proper Construction // showTableDataDetails method
} catch (IOException ex) {
Logger.getLogger(ParentTableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
Hope this helps and Welcome to Stack Overflow
PLEASE post a little more code in the future so your question can have a more definitive answer

Printer won't print the entire jTable [duplicate]

Question Now once the data is fetched from the database and shown in the JTable object "table" embedded in the scrollPane, how do we create a print job that makes it possible to print the displayed table as such in A3 sized paper ?
My code to fetch the data from the database is shown below:
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConnection("jdbc:mysql://localhost/newb","root","pass");
Statement stat=con.createStatement();
ResultSet res=stat.executeQuery("select * from table where name = '"+name+"'");
ResultSetMetaData rsmd = res.getMetaData();
int colcount = rsmd.getColumnCount();
Vector columns = new Vector(colcount);
for(int i=3; i<=colcount; i++)
{
columns.add(rsmd.getColumnName(i));
}
Vector data = new Vector();
Vector row;
// Store row data
while(res.next())
{
row = new Vector(colcount);
for(int i=3; i<=colcount; i++)
{
row.add(res.getString(i));
}
data.add(row);
}
table = new JTable(data, columns);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
scrollPane.setViewportView(table);
}
catch(Exception ex)
{
System.out.println(ex);
}
I am using vector class to fetch the data from the table. How do we print the data shown in the displayed table to a paper?
just use JTable.print() method. here is an article about sending JTable into printer and another one with more parameters
You obviously didn't read the links provided in your previous question.
From the Printing section of How to use Tables
Printing
JTable provides a simple API for printing tables. The easiest way to
print out a table is to invoke JTable.print with no arguments:
try {
if (! table.print()) {
System.err.println("User cancelled printing");
}
} catch (java.awt.print.PrinterException e) {
System.err.format("Cannot print %s%n", e.getMessage());
}
Invoking print on a normal Swing application brings up a standard printing
dialog box. (On a headless application, the table is simply printed.)
The return value indicates whether the user went ahead with the print
job or cancelled it. JTable.print can throw
java.awt.print.PrinterException, which is a checked exception; that's
why the above example uses a try ... catch.
JTable provides several overloads of print with various options. The
following code from TablePrintDemo.java shows how to define a page
header:
MessageFormat header = new MessageFormat("Page {0,number,integer}");
try {
table.print(JTable.PrintMode.FIT_WIDTH, header, null);
} catch (java.awt.print.PrinterException e) {
System.err.format("Cannot print %s%n", e.getMessage());
}
For more sophisticated printing applications, use JTable.getPrintable to obtain
a Printable object for the table. For more on Printable, refer to the
Printing lesson in the 2D Graphics trail.
i hope help you with this code try it its for How to print JTable in Java netbeans
private void btn_printActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
MessageFormat header = new MessageFormat("Print Report");
MessageFormat footer = new MessageFormat("Page{0,number,integer}");
try {
table_employee.print(JTable.PrintMode.FIT_WIDTH, header, footer);
} catch (java.awt.print.PrinterAbortException e) {
} catch (PrinterException ex) {
Logger.getLogger(employee_info.class.getName()).log(Level.SEVERE, null, ex);
}
}

JTable reverts to old cells when clicked on

This Code is in a While Loop, and each time I run a new Query it will go through this block after I have chosen what to filter it by, the problem is when I run it a second time and click on a cell in my table it will revert to cells in my previous table/query. I attached an image to show what I mean(I need 10 reputation for that so nevermind on the picture), I filtered the table by procsessState = -1 and when I clicked on some cells it reverted to what the previous table had. Help would be greatly appreciated. The program is around 1000 lines long and I did a terrible job of splitting it into different classes So I just posted where I am almost certain the issue arises.
I declared
final String columnNamesForTable[] = {"Error Message", "ID", "Locked By", "Message Id", "Process State",
"Row Date", "Sender", "Sent Date", "Subject" };
At The top, then I have this a bit later on.
else if (checkBoxCounter != 0)
{
DefaultTableModel tableModel = new DefaultTableModel(columnNamesForTable, 0);
tableModel.fireTableDataChanged();
try
{
Connection conn = DatabaseConnection.getConnection();
System.out.println("Connected");
PreparedStatement statement = conn.prepareStatement(sb.toString(),
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
// Change CONCUR_READ_ONLY to CONCUR_UPDATABLE
ResultSet resultSet = statement.executeQuery();
int errorMessageIndex = resultSet.findColumn("ErrorMessage");
int idIndex = resultSet.findColumn("Id");
int lockedByIndex = resultSet.findColumn("LockedBy");
int messageIdIndex = resultSet.findColumn("MessageId");
int processStateIndex = resultSet.findColumn("ProcessState");
int rowDateIndex = resultSet.findColumn("RowDate");
int senderIndex = resultSet.findColumn("Sender");
int sentDateIndex = resultSet.findColumn("SentDate");
int subjectIndex = resultSet.findColumn("Subject");
while (resultSet.next()) {
Object[] rowsForTable = { resultSet.getString(errorMessageIndex),
resultSet.getString(idIndex), resultSet.getString(lockedByIndex),
resultSet.getString(messageIdIndex), resultSet.getString(processStateIndex),
resultSet.getString(rowDateIndex), resultSet.getString(senderIndex),
resultSet.getString(sentDateIndex), resultSet.getString(subjectIndex)};
tableModel.addRow(rowsForTable);
}
resultSet.close();
statement.close();
conn.close();
filterFrame.setVisible(false);
JTable resultsTable = new JTable(tableModel);
JScrollPane pane = new JScrollPane(resultsTable);
displayPnl.add(pane);
pack();
resultsTable.repaint();
isDone= true;
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Database error");
ex.printStackTrace();
isDone = true;
} catch (ClassNotFoundException ex) {
JOptionPane.showMessageDialog(null, "Error loading database driver");
ex.printStackTrace();
isDone = true;
}
}
This Code is in a While Loop
Why would it be in a while loop. Swing is event driven. Code should only be executed when the uses generates some kind of event like clicking on a button, typing text, editing a cell.
I have chosen what to filter it by,
Don't create a whole new table and scroll pane. Just update the TableModel of the existing JTable.
pack();
Why would you pack the frame. The query could have 100's of rows of data. Pick a reasonable size for the table when the frame is created and there is no need to use pack() or repaint(). When you invoke the setModel(...) method of the JTable to replace the current model the table will be repainted automatically.
So all the code you need should be:
//filterFrame.setVisible(false);
//JTable resultsTable = new JTable(tableModel);
//JScrollPane pane = new JScrollPane(resultsTable);
//displayPnl.add(pane);
//pack();
//resultsTable.repaint();
existingTable.setModel( tableModel );
I cant comment I do not have enough reputation.
You fire tabledatachanged before changing data.
TableDataChanged does not always properly update rows , it seems better to fire update rows.
If your table is editable , if you clicked the table you need to release the editor.

Adding row to JTable using JCreator

I want to add rows in JTable, but it didn't work well. Could someone help me? Table is displaying normal but not dynamically
//displays all data in Jtable
void refresh()
{
Vector<Vector<String>> data = new Vector<>();
ResultSet rs = st.executeQuery("SELECT * FROM tblInfo");
while(rs.next())
{
Vector<String> d = new Vector<>();
d.add(rs.getString("ID"));
d.add(rs.getString("Name"));
d.add(rs.getString("User"));
d.add(rs.getString("Pass"));
data.add(d);
}
Vector<String> header = new Vector<>();
header.add("ID");
header.add("Name");
header.add("Username");
header.add("Password");
model = new DefaultTableModel(data, header);
table = new JTable(model);
st.close();
rs.close();
table.setBackground(Color.LIGHT_GRAY);
table.setForeground(Color.white);
scroll = new JScrollPane(table);
getContentPane().add(scroll);
st.close();
rs.close();
}
//adding data to database
void addDoctor()
{
st.executeUpdate("INSERT INTO tblInfo(Name) VALUES ('Name')");
st.close();
}
public void actionPerformed(ActionEvent e){
Object source = e.getSource();
else if(btnAdd == source)
{
addDoctor();
refresh();
}
Thanks for any response. :)
I have edited this code before i've posted.
1) Don't create any Objects inside try - catch - finally block; for Swing GUI, prepare these Objects before, better as local variables.
2) You created a new
model = new DefaultTableModel(data, header);
table = new JTable(model);
and those Object maybe never added to the already visible GUI. Swing GUI doesn't care somehow, and the container doesn't know that you changed (reset, reinitialize) the underlaying model and with JTable. You have to notify Swing GUI for changes, but this isn't the proper of way.
3) Don't to recreate this Object on runtime, reuse Objects that already exist, create JTable and DefaultTableModel only one time.
4) Reset DefaultTableModel by using model.setRowCount(0); and then to add a new rows from JDBC
5) Don't to reinvent the wheel, search for ResultSetTableModel or TableFromDatabase.
6) Move code lines st.close(); & rs.close(); to the finally block.
Use DefaultTableModel.setDataVector() to add a new Vector with the new Data to the existing TableModel/JTable. Or use the insertRow/removeRow methods. Or implement your own AbstractTableModel.

need help on reset/clear jcombobox values

im using below coding to add values to a jcombobox using another jcombobox and i need to add the values to the jcombobox2 according to the one get selected in the jcombobox1 without appending values so can someone tell me a way to reset or clear the combo-box values when another option selected?
below is my coding and i'm new to java and netbeans so if someone can help i'll be grateful :)
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/database1", "root", "senura123");
Statement stat = (Statement) con.createStatement();
String val=jComboBox1.getSelectedItem().toString();
String check; String col;
if ("Vehicles".equals(val)){
check = "select reg_no from vehicle;";
col="reg_no";
}
else if ("Travel Guides".equals(val)){
check = "select username from travelguide;";
col="username";
}
else{
check = "select username from transportofficer";
col="username";
}
ResultSet rslt = stat.executeQuery(check);
while (rslt.next()) {
jComboBox2.addItem(rslt.getString(col));
}
}
See DefaultComboBoxModel.removeAllElements()
Empties the list.
Set a new model into your combobox:
final List<String> values = new ArrayList<String>();
while (rslt.next()) {
values.add(rslt.getString(col));
}
jComboBox2.setModel(new DefaultComboBoxModel(values.toArray()));
See DefaultComboBoxModel.
As a further comment, however, depending on how much latency is involved in your query, you may like to split this work up into EDT and background thread parts using SwingWorker.
Usually it happens because you have an event associated JComboBox. It is solved if you have control item in the JComboBox to act, for example:
jComboBoxExample.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent e) {
     do_run ();
   }
});
public void do_run() {
int n=jComboBoxPerfilDocumentos.getItemCount(); <--THIS IS THE SOLUTION
  if (n> 0) {
    String x = jComboBoxPerfilDocumentos.getSelectedItem (). ToString ();
  }
}

Categories