I'm facing problems when fetching and processing a huge ResultSet from a database using JDBC (a few million rows), in this case MySQL's Connector/J. One of those problems is that even though I'm using a SwingWorker and taking measures not to perform any long processing on the Event Dispatch thread, the UI still freezes occasionally. This only happens with huge queries; the approach I'm using works for small ones.
Is there something that can be done to remedy this? Am I improperly handling such large ResultSet?
Note: I'm using the Employees sample database, more specifically the Salaries table.
Sample code
public class TestFrame extends javax.swing.JFrame {
static final String URL = "jdbc:mysql://localhost:3306/employees";
static final String USERNAME = "root";
static final String PASSWORD = "";
private Connection conn;
public TestFrame() {
initComponents();
initConnection();
}
public void initConnection() {
try {
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
System.out.println("Connected.");
} catch (SQLException e) {
e.printStackTrace();
}
}
#SuppressWarnings("unchecked")
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
jScrollPane1 = new javax.swing.JScrollPane();
uiTable = new javax.swing.JTable();
btnRun = new javax.swing.JButton();
txtQuery = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new java.awt.GridBagLayout());
jScrollPane1.setViewportView(uiTable);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.ipadx = 643;
gridBagConstraints.ipady = 374;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(6, 10, 0, 10);
getContentPane().add(jScrollPane1, gridBagConstraints);
btnRun.setText("Run");
btnRun.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRunActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(6, 625, 11, 10);
getContentPane().add(btnRun, gridBagConstraints);
txtQuery.setText("SELECT * FROM Salaries");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.ipadx = 660;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(11, 10, 0, 10);
getContentPane().add(txtQuery, gridBagConstraints);
pack();
}
private void btnRunActionPerformed(java.awt.event.ActionEvent evt) {
String query = txtQuery.getText();
SwingWorker<DefaultTableModel, Object> worker = new SwingWorker<DefaultTableModel, Object>() {
#Override
protected DefaultTableModel doInBackground() {
DefaultTableModel tableModel = null;
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
String[] columnNames = new String[rsmd.getColumnCount()];
for (int i = 1; i <= columnNames.length; i++) {
columnNames[i - 1] = rsmd.getColumnName(i);
}
tableModel = new DefaultTableModel(columnNames, 0);
while (rs.next()) {
Vector row = new Vector();
for (int i = 1; i <= columnNames.length; i++) {
row.add(rs.getString(i));
}
tableModel.addRow(row);
}
} catch (Exception e) {
e.printStackTrace();
}
return tableModel;
}
#Override
protected void done() {
try {
DefaultTableModel tableModel;
if ((tableModel = get()) != null) {
uiTable.setModel(tableModel);
}
} catch (InterruptedException | ExecutionException ex) {
}
}
};
worker.execute();
}
public static void main(String args[]) {
try {
javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
}
java.awt.EventQueue.invokeLater(() -> {
new TestFrame().setVisible(true);
});
}
private javax.swing.JButton btnRun;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField txtQuery;
private javax.swing.JTable uiTable;
}
It's also worth mentioning that the UI freezes even before I start to populate the table model.
The problem is that you shouldn't read the million records. Doesn't matter how you read the result set, if you read one million things it takes time... And if you put all the records in memory it takes a bunch of memory too.
The usual way to do that is reading some records, let's say ¿200?, presenting the 200 records and adding buttons to go forward and read another 200, and backward, to read the previous 200 records, so the user can navigate through the data without moving one million records between the server and yout client.
Just need to add some conditions in your query WHERE clausule and keep record of the last read record, so when you make a query you start the cursor from the last record:
select * from ***
where ****
AND ID > 'myStoredLastReadID'
Or something like that. Then, change the while ( rs.next()) for a
int ix = 0;
while ( rs.next() && (ix++) < 200 ) {
And add the buttons to your GUI. You will need something more, for example to go backward, but I think you can catch the idea.
If you really need to show one million records to your user... well, it will be slow whatever you do because you are going to move one million things from the server to your client, store one million things in memory, calculate which part of that million things the GUI must paint in the screen...
Use an AbstractTableModel on your own page caching, and just keep reading some pages when not in the cache. Keep the cache limited.
With COUNT(*). and LIMIT you can fetch the pages you are displaying, a kind of caching. This becomes even a bit harder with a faster paging technique, using index fields: say the ID. Then on a sorted table one could page by storing page border IDs.
You probably need to keep the connection open, reopen it on failure. Make a page cache.
Also create a Vector with an initial capacity of the correct size.
new Vector(columnNames.length);
This is an (quick and very dirty) example of how to call something slow from a button without freezing the main Swing thread.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestUI extends JFrame implements ActionListener {
JButton but;
public TestUI() {
super( "Test...");
but = new JButton( "Test");
but.setActionCommand( "BUTTON");
but.addActionListener( this);
getContentPane().add( but, BorderLayout.CENTER);
pack();
setVisible( true);
}
public void actionPerformed( ActionEvent ev) {
if ( ev.getActionCommand().equals( "BUTTON") ) {
SlowClass sc = new SlowClass( TestUI.this);
sc.start();
/** THIS FREEEZES
try {
sc.join();
}
catch ( InterruptedException e) {
}
*/
}
else if ( ev.getActionCommand().equals( "QUERY_END") ) {
System.out.println( "END");
but.setText( "Query over");
}
}
public class SlowClass extends Thread {
ActionListener listener;
SlowClass( ActionListener listener) {
this.listener = listener;
}
public void run() {
try {
Thread.sleep( 10000);
listener.actionPerformed( new ActionEvent( this, 0, "QUERY_END"));
}
catch ( Exception ex) {
ex.printStackTrace();
}
}
}
public static void main( String args[]) throws Exception {
TestUI tui = new TestUI();
}
}
Create a new thread, start the thread from the event hadler and, using a listener, wait to be notified when the work is done. If you wait in the same invocation, in the commented lines, the main Swing thread freezes waiting for the end, so the listener is important.
This example starts a thread that doesn't consume CPU, so it works because nobady is fighting for the machine resources, you can resize the freame while the thread is working because Swing is free to work. But this is not your case, you are doing a lot of things, so we don't know if Swing hangs because there's something wrong in the code or because there isn't enough CPU and memory for Swing and the query.
Try something like this (cleaner, please, handling the listener correctly, not adding it in the constructor...) to see what happens. Or change the superquery for a sleep(20000) in your code to see if it hangs to get a hint of what happens.
Related
I'm trying to code a primitive spammer. Is it okay to use thread.sleep() when coding a bot?
I'm a novice programmer. If there is any place in my code to fix it, I would appreciate it if you let me know. I may have used JComponents improperly. If it catches your eye, you can specify. Thank you.
Note: "It looks like your post is mostly code; please add some more details." I'm writing this note because I can't find any more details to add. Sorry
public class Spammer extends JFrame implements Runnable{
private boolean running = false;
private JButton jButton1;
private JLabel jLabel1, jLabel2;
private JScrollPane jScrollPane1;
private JSpinner jSpinner1;
private JTextArea jTextArea1;
public Spammer() {
setLayout(null);
jLabel1 = new JLabel("Text: ");
jTextArea1 = new JTextArea(10,28);
jLabel2 = new JLabel("Interval: ");
jSpinner1 = new JSpinner();
jScrollPane1 = new JScrollPane();
jButton1 = new JButton("Spam");
jButton1.setSize(350, 60);
jButton1.setLocation(100, 220);
jLabel1.setSize(50, 150);
jLabel1.setLocation(15, 10);
jLabel1.setFont(new Font("Verdana" , Font.BOLD , 14));
jTextArea1.setSize(350, 150);
jTextArea1.setLocation(100, 10);
jLabel2.setSize(80, 25);
jLabel2.setLocation(15, 180);
jLabel2.setFont(new Font("Verdana" , Font.BOLD , 12));
jSpinner1.setSize(350, 25);
jSpinner1.setLocation(100, 180);
getContentPane().add(jLabel1);
getContentPane().add(jTextArea1);
getContentPane().add(jLabel2);
getContentPane().add(jSpinner1);
getContentPane().add(jScrollPane1);
getContentPane().add(jButton1);
setTitle("Spammer by Me");
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(500, 340));
pack();
jButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1ActionPerformed();
}
} );
}
private void jButton1ActionPerformed() {
if(!running) {
jTextArea1.setEnabled(false);
jSpinner1.setEnabled(false);
jButton1.setText("Spamming in 3 seconds...");
jButton1.setEnabled(false);
running = true;
new Thread(this).start();
}else {
jTextArea1.setEnabled(true);
jSpinner1.setEnabled(true);
jButton1.setText("Spam");
running = false;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Spammer().setVisible(true);
}
});
}
public void run() {
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
int[] keys = new int[jTextArea1.getText().length()];
if((int) jSpinner1.getValue() < 0) {
jSpinner1.setValue((int) 0);
}
int interval = (int) jSpinner1.getValue();
for(int i = 0 ; i < keys.length; i++) {
keys[i] = KeyEvent.getExtendedKeyCodeForChar(jTextArea1.getText().charAt(i));
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jButton1.setEnabled(true);
jButton1.setText("Stop");
while(running) {
for(int i = 0 ; i < keys.length; i++) {
robot.keyPress(keys[i]);
robot.keyRelease(keys[i]);
}
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The key principle at work here is primarily the 'EDT' - the Event Dispatch Thread. This is a thread that does GUI stuff - if for example you drag the titlebar of a completely different app's window across the screen, and this moves that app's window over yours, the EDT is hard at work redrawing everything. The EDT is the thread that sees you press your mouse down on a button, and will render the button in the 'pressed in' view.
The EDT is the only thread from which you can do GUI stuff, whether it is to retrieve info, such as getText(), or whether it is to change things, such as updating the text of a label or whatnot.
The EDT is also the thread you're in when your code runs that you registered as a handler for events, such as the code that responds to a button click or whatnot.
You therefore must not sleep on the EDT (Because then your app looks non-responsive; the thread that responds to button clicks or repaints what needs repainting is not actively running), but you can only fetch GUI data / set GUI stuff from the EDT.
The rules:
Do not interact with any GUI elements unless you are in the EDT
Never sleep in the EDT
Your code is broken, not because you sleep (that's fine - that run() method is not in the EDT), but because you do GUI stuff from this non-EDT thread.
You need to do a careful dance here: You want to sleep (not allowed on the EDT), but interact with GUI elements, such as the interval box, to know how long to sleep, which can only be done on the EDT.
To do this, you can 'send' code to run in the EDT via SwingWorkers, or simply via:
SwingUtilities.invokeAndWait(() -> {
// code that will run in the EDT goes here
});
You can't set any variables from within this code, but you can use AtomicReference and friends to create objects you can change. So, instead of:
int[] keys = new int[jTextArea1.getText().length()];
if (jSpinner1.getValue() < 0) {
jSpinner1.setValue(0);
}
int interval = (int) jSpinner1.getValue();
which is doing GUI stuff, do:
AtomicInteger interval = new AtomicInteger();
SwingUtilities.invokeAndWait(() -> {
int[] keys = new int[jTextArea1.getText().length()];
if (jSpinner1.getValue() < 0) {
jSpinner1.setValue(0);
}
interval.set((int) jSpinner1.getValue());
};
I have a JTable which populates data from DB. I want to refresh data in JTable every 10 minutes (for testing 10 sec is enough). I tried do it with a Thread, but I found that it is not good idea, and I need to use SwingWorker
public class Monitor extends JFrame{
JTable jtable = null;
JTabbedPane jtp = null;
JPanel jp1 = null;
JPanel jp2 = null;
JLabel label1 = null;
JLabel label2 = null;
public void setJTable(Vector data, Vector columnNames) {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jtable = new JTable(data, columnNames);
JScrollPane scrollPane = new JScrollPane(jtable);
jp1.add(scrollPane);
}
public void updateJTable(Vector data, Vector columnNames) {
jtable = new JTable(data, columnNames);
}
public Monitor() {
setTitle("Monitor System");
//Panel with tabs for navigation
jtp = new JTabbedPane();
getContentPane().add(jtp);
//tab1, info from dba_jobs
jp1 = new JPanel();
//tab2 info from QueueInfo
jp2 = new JPanel();
label1 = new JLabel();
label1.setText("tab1");
label2 = new JLabel();
label2.setText("tab2");
jp1.add(label1);
jp2.add(label2);
jtp.add("Tab1", jp1);
jtp.add("Tab2", jp2);
}
}
And my Demo class:
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Statement stmt = null;
Connection conn = null;
ResultSet rs = null;
Vector<String> columnNames = new Vector<String>();
Vector<Vector> rowData = new Vector<Vector>();
DBMonitor dbmonitor = new DBMonitor();
Monitor monitor = new Monitor();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
rowData = dbmonitor.getJobsData();
columnNames = dbmonitor.getColumnNames();
monitor.setJTable(rowData, columnNames);
monitor.setSize((int) dim.getWidth(), (int) dim.getHeight());
monitor.setVisible(true);
boolean interrupt = true;
while (interrupt) {
try {
rowData = dbmonitor.getJobsData();
columnNames = dbmonitor.getColumnNames();
monitor.updateJTable(rowData, columnNames);
try {
Thread.sleep(10000);
} catch (InterruptedException ie) {
return;
}
JOptionPane.showMessageDialog(null, "SLEEP!");
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
System.err.println(e.getMessage());
}
}
}
}
How I can do it with SwingWorker? I don't get a concept of that way.
In the doInBackground() method of the SwingWorker you have you while loop that:
retrieves the data from the database
creates your TableModel
use the publish() method of the SwingWorker to pass the TableModel to the 'process()` method of your SwingWorker
sleeps for 10 seconds
Then in the process() method of the SwingWorker you:
use the TableModel that was passed to the process() method to update your JTable.
Read the section from the Swing tutorial on Concurrency for more information and a working example or search the forum for more SwingWorker examples.
First, I would start with a Timer of some sort, I'm going to use a Swing Timer as it easy, but you could use a java.util.Timer instead...
private Timer updateTimer;
//...
updateTimer = new Time(10000, new ActionListener() {
public void actionListener(ActionEvent e) {
}
});
updateTimer.setRepeats(false);
updateTimer.start();
This allows you to be notified in about 10 seconds time...
Then you need a SwingWorker that can do the actual work...
public class UpdateWorker extends SwingWorker<TableModel, Void> {
private Monitor monitor;
private Timer updateTimer;
public UpdateWorker(Monitor monitor, Timer updateTimer) {
this.monitor = monitor;
this.updateTimer = updateTimer;
}
#Override
protected TableModel doInBackground() throws Exception {
Vector<Vector> rowData = dbmonitor.getJobsData();
Vector columnNames = dbmonitor.getColumnNames();
DefaultTableModel model = new DefaultTableModel(rowData, columnNames);
return model;
}
#Override
protected void done() {
try {
TableModel model = get();
monitor.updateTable(model);
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
updateTimer.restart();
}
}
Now in the actionPerformed method of the ActionListener assigned to the timer, you would do something like..
public void actionListener(ActionEvent e) {
UpdateWorker worker = new UpdateWorker(monitor, this);
worker.execute();
}
To execute the worker. The reason for having a non-repeating timer is to ensure that the next update is set for n seconds from when the update completes, so you don't get overlapping updates
Oh, and this will require to update your Monitor to accept a TableModel rather then the Vectors you are using to create one, it's just simpler that way...
I want to create jcomponents dynamically using database. when I open any jframe or jpanel components like jlabel, jtextfields, jcombobox, etc should be created by reading database rows.
I am confused in how to give reference from database value i.e. in the String to the jcomponent's object.
this is my database table
try{
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db","root","pass");
stat = con.createStatement();
ResultSet rs = stat.executeQuery("select * from design");
while(rs.next()){
jTextField1 = new JTextField();
jTextField1.setSize(rs.getInt("height"),rs.getInt("width"));
jTextField1.setLocation(rs.getInt("x"), rs.getInt("y"));
}
rs.close();
stat.close();
con.close();
}
catch(Exception e){
System.out.println(e);
}
this is demo table.
I know this will not work because I can't communicate with objects and database.
I want to print jcomponents on jframe. I will write for loop to print them multiple times.
please help me.
First of all see this #AndrewThompson's wise advice:
Java GUIs might have to work on a number of platforms, on different
screen resolutions & using different PLAFs. As such they are not
conducive to exact placement of components. To organize the components
for a robust GUI, instead use layout managers, or combinations of
them, along with layout padding & borders for white space.
There are some helpful topics to understand what it means here:
Non resizable window border and positioning
Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
Nested Layout Example
Providing white space in a Swing GUI
You'll see the use of methods like setLocation(), setBounds() or setSize() is highly discouraged. However I've seen this approach before applied to allow customizing forms. But instead of specific (x,y) coordinates and fixed (width,height) you can store constraints for GridBagLayout. Let's say you have a table like this:
I'd start first with a class to wrap data from the DB:
public class Data {
private String componentType, text;
private int column, row, width, height, weightX, weightY;
public Data(String componentType, int column, int row, int width, int height
,int weightX, int weightY, String text) {
this.componentType = componentType;
this.column = column;
this.row = row;
this.width = width;
this.height = height;
this.weightX = weightX;
this.weightY = weightY;
this.text = text;
}
// getters and setters here
}
As database calls are time consuming task you have to consider use a SwingWorker to do the database call (time consuming task) in a background thread and create/update your GUI in the Event Dispatch Thread.
Having said this you may have something like this:
public class Demo {
private JPanel content;
private JFrame frame;
private void createAndShowGUI() {
content = new JPanel(new GridBagLayout());
SwingWorker<Void, Data> worker = new SwingWorker<Void, Data>() {
#Override
protected Void doInBackground() {
try{
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db","root","password");
Statement stat = con.createStatement();
ResultSet rs = stat.executeQuery("select * from TableName");
while(rs.next()){
String componentType = rs.getString("component");
int column = rs.getInt("x");
int row = rs.getInt("y");
int width = rs.getInt("width");
int height = rs.getInt("height");
int weightx = rs.getInt("weightx");
int weighty = rs.getInt("weighty");
String text = rs.getString("text");
Data data = new Data(componentType, column, row, width, height
,weightx, weighty, text);
publish(data);
}
rs.close();
stat.close();
con.close();
} catch(Exception e) {
System.out.println(e);
}
return null;
}
#Override
protected void process(List<Data> chunks) {
for(Data data : chunks) {
JComponent component = null;
if(data.getComponentType().equalsIgnoreCase("JTextField")) {
component = new JTextField(data.getText());
}
if(data.getComponentType().equalsIgnoreCase("JComboBox")) {
component = new JComboBox();
}
if(data.getComponentType().equalsIgnoreCase("JLabel")) {
component = new JLabel(data.getText());
}
if(component != null) {
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = data.getColumn();
constraints.gridy = data.getRow();
constraints.gridwidth = data.getWidth();
constraints.gridheight = data.getHeight();
constraints.weightx = data.getWeightX();
constraints.weighty = data.getWeightY();
constraints.anchor = GridBagConstraints.WEST;
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(8,8,8,8);
content.add(component, constraints);
}
}
}
#Override
protected void done() {
frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
};
worker.execute();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
And you'll see something like this:
I have a JPanel with three JComboBox. Here is the code I wrote:
public class Main {
private static String pat_order;
private static String PS_selection;
private static String ovlp_selection;
public static void main(String args[]) throws FileNotFoundException, IOException {
Date start_time = new Date();
try {
GridBagConstraints gbc = new GridBagConstraints();
final JComboBox jc = new JComboBox();
jc.addItem("ARR");
jc.addItem("SRR");
final JComboBox jc1 = new JComboBox();
jc1.addItem("RR");
jc1.addItem("IQC");
final JComboBox jc2 = new JComboBox();
jc2.addItem("YES");
jc2.addItem("NO");
JPanel myPanel = new JPanel(new GridBagLayout());
myPanel.add(jc, gbc);
myPanel.add(jc1, gbc);
myPanel.add(jc2, gbc);
jc.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
String order = (String) jc.getSelectedItem();
pat_order = order;
}
});
jc1.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
String PS_method = (String) jc1.getSelectedItem();
PS_selection = PS_method;
}
});
jc2.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
String ovlp_user = (String) jc2.getSelectedItem();
ovlp_selection = ovlp_user;
}
});
if (pat_order == "ARR") {
Arrays.sort(patterns_array, new ColumnComparator(0));
} else if (pat_order == "SRR") {
Arrays.sort(patterns_array, new ColumnComparator(1));
}
if (PS_selection == "RR") {
System.out.println("RR");
} else if (PS_selection == "IQC") {
System.out.println("IQC");
}
if (ovlp_selection == "YES") {
Overlap a = new Overlap(Xdisc, final_patterns, k, Yresid, Xresid, projectname, pat_order, PS_selection);
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
} finally {
}
}
}
The problem is that the first JComboBox is working fine, but the second and third is doing nothing. It would be great if you can help me in this problem.
You seem to be running your UI as if it was a console program. UI's don't work this way, they respond to events. These events may come in any order and at any time...
Dialogs are a great way of control the flow of the execution. They will block code until the dialog is closed, allowing you to ascertain the results and take appropriate action.
Take a look at How to use dialogs for more details...
While you there, you might also want to take a look through Creating a UI with Swing which will explain more of the concepts you need to understand.
Like the fact that a UI needs some kind of Window in order to be displayed on the screen
Try to add ActionListener instead of ItemListener
I have created one GUI in Swing Java in which I have used JTable.Now I want to display next page information into it by using pagination. How should I do that ?
Another option to implement this is to use a scrollbar-less scrollpane and a couple nav buttons to effect the control. The buttons that have been added are normal JButtons for the prototype.
A quick prototype is added below. It makes a couple assumptions, one of which is that the table model has all of its data. Work could be done to ensure that rows end up flush at the top of the view upon navigation.
private void buildFrame() {
frame = new JFrame("Demo");
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addStuffToFrame();
frame.setVisible(true);
}
private void addStuffToFrame() {
final JTable table = getTable();
final JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
final JButton next = new JButton("next");
final JButton prev = new JButton("prev");
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent e) {
Rectangle rect = scrollPane.getVisibleRect();
JScrollBar bar = scrollPane.getVerticalScrollBar();
int blockIncr = scrollPane.getViewport().getViewRect().height;
if (e.getSource() == next) {
bar.setValue(bar.getValue() + blockIncr);
} else if (e.getSource() == prev) {
bar.setValue(bar.getValue() - blockIncr);
}
scrollPane.scrollRectToVisible(rect);
}
};
next.addActionListener(al);
prev.addActionListener(al);
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.add(prev);
buttonPanel.add(next);
panel.add(buttonPanel, BorderLayout.NORTH);
panel.add(scrollPane, BorderLayout.CENTER);
frame.getContentPane().add(panel);
}
private JTable getTable() {
String[] colNames = new String[]{
"col 0", "col 1", "col 2", "col 3"
};
String[][] data = new String[100][4];
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 4; j++) {
data[i][j] = "r:" + i + " c:" + j;
}
}
return new JTable(data,colNames);
}
alt text http://img7.imageshack.us/img7/4205/picture4qv.png
Paging in a Swing JTable looks like a nice article.
Here is an excerpt:
As far as I remember the solution for this problem lies in the concept of paging: just retrieve the data that the user wants to see and nothing more. This also means you have to sometimes get extra data from the db server (or appserver) if your user scrolls down the list.
Big was my surprise that there wasn't really an out-of-the-box solution (not even a copy- paste solution) for this problem. Anyone that knows one, please don't hesitate to extend my (rather limited) knowledge of the J2EE platform.
So we dug in, and tried to build a solution ourselves.
What we eventually came up with was an adapted TableModel class to takes care of the paging.
You can try with 2 query, first query is to count total rows in DB and second query is for the real data :) And for the UI side, you can try like this:
public class MainForm extends javax.swing.JFrame {
private void initDefaultValue() {
rowsPerPage = Integer.valueOf(cmbPageSize.getSelectedItem().toString());
totalRows = Main.getTablePagingService().countComments();
Double dblTotPage = Math.ceil(totalRows.doubleValue()/rowsPerPage.doubleValue());
totalPage = dblTotPage.intValue();
if (pageNumber == 1) {
btnFirst.setEnabled(false);
btnPrevious.setEnabled(false);
} else {
btnFirst.setEnabled(true);
btnPrevious.setEnabled(true);
}
if (pageNumber.equals(totalPage)) {
btnNext.setEnabled(false);
btnLast.setEnabled(false);
} else {
btnNext.setEnabled(true);
btnLast.setEnabled(true);
}
txtPageNumber.setText(String.valueOf(pageNumber));
lblPageOf.setText(" of " + totalPage + " ");
lblTotalRecord.setText("Total Record " + totalRows + " rows.");
List wPComments = Main.getTablePagingService().findAllComment(pageNumber, rowsPerPage);
jTable1.setModel(new CommentTableModel(wPComments));
autoResizeColumn(jTable1);
}
private void btnFirstActionPerformed(ActionEvent evt) {
pageNumber = 1; initDefaultValue();
}
private void btnPreviousActionPerformed(ActionEvent evt) {
if (pageNumber > 1) {
pageNumber -= 1; initDefaultValue();
}
}
private void btnNextActionPerformed(ActionEvent evt) {
if (pageNumber
And in service layer, you just need use limit function like this :
public List findAllComment(Integer pageNumber, Integer rowsPerPage) {
try {
List listWP = new ArrayList();
preparedFindAll.setInt(1, (rowsPerPage*(pageNumber-1)));
preparedFindAll.setInt(2, rowsPerPage);
ResultSet rs = preparedFindAll.executeQuery();
while (rs.next()) {
WPComment comment = new WPComment();
comment.setCommentID(rs.getInt("comment_ID"));
comment.setCommentAuthor(rs.getString("comment_author"));
comment.setCommentDate(rs.getDate("comment_date"));
comment.setCommentContent(rs.getString("comment_content"));
listWP.add(comment);
}
return listWP;
} catch (SQLException ex) {
Logger.getLogger(TablePagingServiceJDBC.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public Integer countComments() {
try {
Integer totalRows = 0;
ResultSet rs = preparedCount.executeQuery();
while (rs.next()) {
totalRows = rs.getInt("count(*)");
}
return totalRows;
} catch (SQLException ex) {
Logger.getLogger(TablePagingServiceJDBC.class.getName()).log(Level.SEVERE, null, ex);
}
return 0;
}
Or you can fork me on github at Project Page Table Paging on Swing :)
I have written a Java pagination tool dataj. It uses JQuery dataTables plug-in pagination metadata to build up the result page.
I have also added some client classes for Java Swing including a TableRowSorter that calls the (server side) sorting instead of sorting inside the table model.
Feel free to download it and contact me if you have any questions. It's under Apache 2 license.
Alternatively, you can make use of the QuickTable project.
Screenshot
Here is the DBTable component in action:
The DBTable component is embedded in a traditionnal JFrame.
Sample code
The following sample code produces the window shown in the previous screenshot:
import javax.swing.JFrame;
import javax.swing.UIManager;
import quick.dbtable.DBTable;
public class QuickTableFrame extends JFrame {
private static final long serialVersionUID = -631092023960707898L;
public QuickTableFrame() {
try {
// Use system look and feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// set Frame properties
setSize(300, 200);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// create a new quicktable
DBTable dBTable1 = new DBTable();
// add to frame
getContentPane().add(dBTable1);
// set the database driver to be used, we are using jdbc-odbc driver
dBTable1.setDatabaseDriver("org.h2.Driver");
/*
* set the jdbc url,"quicktabledemo" is the data source we have
* created for the database
*/
dBTable1.setJdbcUrl("jdbc:h2:mem:test;INIT=create table employee as select * from CSVREAD('test.csv');");
// set the select statement which should be used by the table
dBTable1.setSelectSql("select * from employee");
// to create the navigation bars for the table
dBTable1.createControlPanel();
// connect to database & create a connection
dBTable1.connectDatabase();
// fetch the data from database to fill the table
dBTable1.refresh();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// create a new table frame
QuickTableFrame myframe = new QuickTableFrame();
}
}
Resources and dependencies
test.csv
empid,emp_name,emp_dept,emp_salary
1,Azalia,ornare,114918
2,Jade,tristique,152878
3,Willa,In scelerisque scelerisque,166733
...
H2
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.187</version>
</dependency>
References
QuickTable basic tutorial
QuickTable official tutorials
Download latest jar
h2 database