How can I pass a SQL connection to a Action Listener. I want to have an infinite loop, that sleeps for 100ms. Every iteration the loop is suppose to query a database. Is swing timer the best way to do this? If so how can I pass the connection to the Action Listener. If not, can someone please advise on how this can be done. Much thanks.
Code:
public static void main(String[] args) throws InterruptedException {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
AdminManager frame = new AdminManager();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
BoneCP connectionPool = null;
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
// setup the connection pool
BoneCPConfig config = new BoneCPConfig();
config.setJdbcUrl("jdbc:mysql://192.162.0.0");
config.setUsername("root");
config.setPassword("");
connectionPool = new BoneCP(config); // setup the connection pool
connection = connectionPool.getConnection(); // fetch a connection
if (connection != null){
System.out.println("Connection successful!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// Define listner
ActionListener taskPerformer = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
String sql = "SELECT * table;";
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next()) {
String symbol = rs.getString("name");
System.out.println(symbol);
}
}
};
Timer timer = new Timer( 100 , taskPerformer);
timer.setRepeats(true);
timer.start();
Thread.sleep(1000);
//connectionPool.shutdown(); // shutdown connection pool.
}
Do not the javax.swing.Timer class to periodically execute a non-Swing task. Instead, use a ScheduleExecutorService,
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.schedule(new Runnable(){
#Override
public void run(){
// query database
}
}, 0, 100, TimeUnit.MILLISECONDS);
If the background task must continually update a Swing component, use SwingWorker to process() periodic updates to the component's model. In this example, a JTextArea is updated with data obtained from an H2 database.
Related
I have a Java swing UI where I need to disable a button on the UI if I could not detect an active internet connection.
The code function properly so far, but when I get disconnected from the internet, it does not retrigger the method to update the boolean flag.
How can I add an event on that flag to let my button consume it during the lifetime of the application?
public class Main {
private static JButton button;
private static boolean testButtonEnabled;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
/*
* function that returns true/false if connected to the internet
*/
if(Utils.isConnectedToInternet()) {
logger.debug("System is connected to the internet");
testButtonEnabled=true;
} else {
logger.debug("System is not connected to the internet");
testButtonEnabled=false;
}
Main window = new Main();
window.frame.setVisible(true);
button = new JButton("my button");
/*
* set the internet status
*/
button.setVisible(testButtonEnabled);
}
}
}
}
Again, this code:
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
public Void doInBackground()
{
while(true)
{
try {
isConnectedToInternet = Utils.isConnectedToInternet();
if (isConnectedToInternet) {
btn_online2.setEnabled(isConnectedToInternet);
} else {
btn_online2.setEnabled(isConnectedToInternet);
}
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
is dangerous since it makes mutational changes to a Swing component from a background thread. While this code may work 95% of the time, it can fail in unpredicatable ways and at unpredicatable times. Better to only mutate Swing components on the event thread. For instance, even this would be better:
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
#Override
public Void doInBackground() {
while(true) {
try {
isConnectedToInternet = Utils.isConnectedToInternet();
// note that there is no need for the if/else block
SwingUtilities.invokeLater(() -> {
btn_online2.setEnabled(isConnectedToInternet);
});
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
or better still, using SwingWorker's publish/process:
SwingWorker<Void, Boolean> worker = new SwingWorker<Void, Boolean>() {
#Override
public Void doInBackground() {
while(true) {
try {
isConnectedToInternet = Utils.isConnectedToInternet();
// note that there is no need for the if/else block
publish(Utils.isConnectedToInternet());
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
protected void process(List<Boolean> chunks) {
for (Boolean chunk : chunks) {
btn_online2.setEnabled(chunk);
}
}
};
worker.execute();
I was able to resolve using the following method in the initialize() of the frame.
Adding that change part of the swingworker allowed the button to check the flag and assign it to itself whenever it changes.
Now whenever the internet is disconnected the button is disabled and whenever connected the button is enabled.
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
public Void doInBackground()
{
while(true)
{
try {
isConnectedToInternet = Utils.isConnectedToInternet();
if (isConnectedToInternet) {
btn_online2.setEnabled(isConnectedToInternet);
} else {
btn_online2.setEnabled(isConnectedToInternet);
}
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
class class1{
public class1(){//here is my GUI commants}
#Override
public void actionPerformed(ActionEvent evt) //this is my action performed from a jframe window
{
worker = new SwingWorker<Void, Void>(){//ia m creating a worker
protected WaitWindow waitWindow;
#Override
protected Void doInBackground() throws Exception {
waitWindow= new WaitWindow();//i call waitWindow class to pop up my new window with the progressBar
return null;
}
#Override
protected void done(){
waitWindow.CloseWaitWindow();
}
};
try{
String option = (String)serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
if(option.equals("icsd Server"))
{//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost",1080);
icsdserver = (ICSDinterface)registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd",0)==0)
{
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver,"icsd");
}
}
}
}
catch (RemoteException ex) {System.out.println(ex);}
catch (NotBoundException ex) {System.out.println(ex);}
}}
The Wait Window class follows
class WaitWindow extends JFrame //my WaitWindow Class
{
private JProgressBar bar ;
public WaitWindow(){
super("Wait Until Connection Is ready");
setSize(100,200);
bar = new JProgressBar();
bar.setIndeterminate(true);
bar.setPreferredSize(new Dimension(300,330));
add(bar);
getContentPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void CloseWaitWindow()
{
removeNotify();
}
}
What am I doing wrong here? I want the wait Window to shown until server's RequestForEntry method return 0 this might take some time. Also there is no error with RMI connection.
You're blocking the Event Dispathing Thread, with the call to RequestForEntry, which should be within the doInBackground method of the SwingWorker, for example
public void actionPerformed(ActionEvent ev) //this is my action performed from a jframe window
{
try {
final String option = (String) serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
final WaitWindow waitWindow = new WaitWindow();
worker = new SwingWorker<Void, Void>() {//ia m creating a worker
#Override
protected Void doInBackground() throws Exception {
if (option.equals("icsd Server")) {//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost", 1080);
icsdserver = (ICSDinterface) registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd", 0) == 0) {
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver, "icsd");
}
}
return null;
}
#Override
protected void done() {
waitWindow.CloseWaitWindow();
}
};
}
} catch (RemoteException ex) {
System.out.println(ex);
} catch (NotBoundException ex) {
System.out.println(ex);
}
}
Swing is a single threaded framework and isn't thread safe. This means that anything the blocks the Event Dispatching Thread will prevent it from processing new events, including paint requests.
Swing components should also only be updated from within the context of the EDT, which is where SwingWorker comes in.
See Concurrency in Swing and Worker Threads and SwingWorker for more details
I have below SwingWorker;
public class WorkerTrying extends SwingWorker<Void, Void> {
Statement stmt;
Connection con;
ResultSet rs;
String connectionUrl = "jdbc:sqlserver://192.168.131.10;" + "databaseName=SomeDB;" + "user=" + "SomeUser" + ";" + "password=" + "SomeUserPassword" + ";";
public void closeConnection() throws SQLException{
stmt.close();
System.out.println("Closed!!!");
}
protected Void doInBackground() throws Exception {
String query = "Select column1,column2 from Table1"
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
con = DriverManager.getConnection(connectionUrl);
stmt = con.createStatement();
rs = stmt.executeQuery(query);
while (rs.next()){
//Doing something...
}
return null;
}
public void done() {
}
}
As you can see some DB connection and data fetchinbg via While loop in this worker. My problem is DB Queries takes very long time sometimes. I want add STOP button for closing Statements and Connections in SwingWorker and cancel immediatelly itself.
I am trying below stop button but no help;
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
WorkerTrying workerTrying = new WorkerTrying();
workerTrying.cancel(true);
}
Also i have 3-4 SwingWorkers. So i must detect which one is currently running first.
Regards.
==== UPDATE ====
New Stop button like this;
jButtonStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
for(SwingWorker workerTrying : _workers){
if(!workerTrying.isDone()){
try {
((WorkerTrying)workerTrying).closeConnection();
} catch (SQLException ex) {
Logger.getLogger(MainGui.class.getName()).log(Level.SEVERE, null, ex);
}
workerTrying.cancel(true);
}
}
}
}
});
==== SECOND ISSUE UPDATE ====
Start button Action Listener just like this;
startButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if(jTextField1.getText().equals("")){
final SwingWorker workerTrying = new WorkerTrying();
_workers.add(workerTrying);
workerTrying.execute();
}
else{
final SwingWorker workerTrying2 = new WorkerTrying2();
_workers.add(workerTrying2);
workerTrying2.execute();
}
}
});
As you can see some condition for which SwingWorker can be execute.
Than Stop button just like this;
stopButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
for (SwingWorker workerTrying : _workers) {
if(!workerTrying.isDone()){
try {
((WorkerTrying)workerTrying).closeConnection();
} catch (SQLException ex) {
Logger.getLogger(MainGui.class.getName()).log(Level.SEVERE, null, ex);
}
workerTrying.cancel(true);
}
}
for (SwingWorker workerTrying2 : _workers) {
if(!workerTrying2.isDone()){
try {
((WorkerTrying2)workerTrying2).closeConnection();
} catch (SQLException ex) {
Logger.getLogger(MainGui.class.getName()).log(Level.SEVERE, null, ex);
}
workerTrying2.cancel(true);
}
}
}
});
If First SwingWorker (workerTrying) executed and try stopping, everythings looks ok. Statement closed and SwingWorker canceled succesfully.
But when second SwingWorker (workerTrying2) executed and wanted to Stop, below exception throwed;
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: testproject.MainGui$WorkerTrying2 cannot be cast to testproject.MainGui$WorkerTrying
I used List to track all the Workers. And stopped it all. You can try this.
public class SwingT {
private List<SwingWorker> _workers = new ArrayList<>();
public SwingT(){
JFrame frame = new JFrame("Test Worker");
frame.setSize(320, 160);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JButton btn = new JButton("Add Work");
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
SwingWorker workerTrying = new WorkerTrying();
_workers.add(workerTrying);
workerTrying.execute();
}
});
JButton btn2 = new JButton("Stop All");
btn2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
for(SwingWorker workerTrying : _workers){
if(!workerTrying.isDone()){
//Close DB Connections
((WorkerTrying)workerTrying).closeConnection();
workerTrying.cancel(true);
}
}
}
});
frame.add(btn);
frame.add(btn2);
frame.setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new SwingT();
}
}
UPDATE
public class WorkerTrying extends SwingWorker<Void, Void> {
public void closeConnection(){
//Close the connection
System.out.println("closed");
}
..........
}
The purpose of the application is to query a table, and take that information and update a JTable. Right now the ThreadTask() is able to query the table and obtain the information. My question is how do I update the JTable GUI object with the information obtained from the database?
public class AdminManager extends JFrame {
public static void main(String[] args) throws InterruptedException {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
AdminManager frame = new AdminManager();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
// Setup connection pool
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new ThreadTask(connection), 2000, 100, TimeUnit.MILLISECONDS);
}
/**
* Create the frame.
*/
public AdminManager() {
// Setup GUI
DefaultTableModel model = new DefaultTableModel();
model.addColumn("#");
tableQueue = new JTable(model);
tableQueue.getColumnModel().getColumn(0).setPreferredWidth(3);
scrollPane.setViewportView(tableQueue);
}
class updateTable extends SwingWorker<Void, String> {
#Override
protected Void doInBackground() throws Exception {
model.addRow(new Object[]{order_num});
return null;
}
}
}
class grabData implements Runnable {
private Connection connection;
private DefaultTableModel model;
private String order_num;
public grabData(Connection c, DefaultTableModel m) {
connection = c;
model = m;
}
#Override
public void run() {
System.out.println("Working ... ");
String sql = "SELECT * FROM order_queue;";
Statement st;
try {
st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next()) {
order_num = rs.getString("order_num");
System.out.println(order_num);
updateTable.execute()
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
If you are adding rows to a TableModel object that is held by a visualized JTable, then you must do so on the Swing event thread, the EDT. If you're creating a completely new TableModel one that isn't visualized, then I think it is safe to fill it off of the EDT, and then set it as the JTable's model on the EDT.
One consideration, if you want to add rows the JTable as they become available, consider using a SwingWorker<Void, RowObject>, and then pass the RowObject obtained in the while (rs.next()) { via a publish/process method pair.
Edit:
You could just skip the SwingWorker and just queue up adding the table's row on the EDT:
while(rs.next()) {
final String order_num = rs.getString("order_num");
// System.out.println(order_num);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
model.addRow(new Object[]{order_num});
}
});
}
I have implemented a timer to invoke my alert() method. The duration of the timer is retrieved from the database. When I set the duration to 1 minute, the timer invokes alert() every one minute. When I set the duration again for 5 minutes, the 1 minute timer does not stop. So now I have 2 running timers. How can I remove the previous timer? Thanks.
private void getDuration()
{
durationTimer = new javax.swing.Timer(durationDB, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
alert();
}
});
durationTimer.stop();
try
{
// Connection to the database
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/smas","root","root");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM alertduration");
while (rs.next())
{
durationDB = rs.getInt("duration");
}
con.close();
}
catch(Exception ea)
{
JOptionPane.showMessageDialog(watchlist, "Please ensure Internet Connectivity ", "Error!", JOptionPane.ERROR_MESSAGE);
}
durationTimer = new javax.swing.Timer(durationDB, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
alert();
}
});
durationTimer.start();
Call the stop() method when you are finished with the first timer. It may also be worth making your timer global and reusing it rather than creating a new one every time the duration changes. See: http://docs.oracle.com/javase/6/docs/api/javax/swing/Timer.html
Example:
durationTimer = new javax.swing.Timer(duration, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
alert();
}
});
durationTimer.start();
//wait for duration to change
durationTimer.stop();
durationTimer.setDelay(duration);
durationTimer.start();