I'm using Netbeans 8.2 on the Raspberry Pi 3 imported with Pi4J libraries.
The issue here is that the Login.java does not execute the written code inside MainForm.java's public static void main(String args[]). However, the code in MainForm.java works whenever I run it directly by right clicking and selecting Run File but when I Run the whole Project, that is when the problem starts.
Here is the code for Login.java:
package Kiosk;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Login extends javax.swing.JFrame {
public Login() {
initComponents();
jLabel_asterisk1.setVisible(false);
jLabel_asterisk2.setVisible(false);
jPanel1.getRootPane().setDefaultButton(jButton_login);
}
#SuppressWarnings("unchecked")
private void jButton_loginActionPerformed(java.awt.event.ActionEvent evt) {
//asterisk required
jLabel_asterisk1.setVisible(false);
jLabel_asterisk2.setVisible(false);
if(jTextField_username.getText().equals("")){
jLabel_asterisk1.setVisible(true);
}
if(String.valueOf(jPasswordField.getPassword()).equals("")){
jLabel_asterisk2.setVisible(true);
}
else{
Connection con = MyConnection.getConnection();
PreparedStatement ps;
try {
ps = con.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?");
ps.setString(1, jTextField_username.getText());
ps.setString(2, String.valueOf(jPasswordField.getPassword()));
ResultSet rs = ps.executeQuery();
if(rs.next()){
MainForm mf = new MainForm();
mf.setVisible(true);
mf.pack();
mf.setLocationRelativeTo(null);
MainForm.jLabel_welcome.setText(jTextField_username.getText());
this.dispose();
}
else{
System.out.println("NO");
}
} catch (SQLException ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Login().setVisible(true);
}
});
}
}
And for the MainForm.java:
package Kiosk;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioInterrupt;
import com.pi4j.wiringpi.GpioInterruptListener;
import com.pi4j.wiringpi.GpioInterruptEvent;
import com.pi4j.wiringpi.GpioUtil;
public class MainForm extends javax.swing.JFrame {
public static volatile int pulses = 0;
public static boolean display = true;
public MainForm() {
initComponents();
}
#SuppressWarnings("unchecked")
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MainForm().setVisible(true);
}
});
//create listener //bill coin pulses
GpioInterrupt.addListener(new GpioInterruptListener() {
#Override
public void pinStateChange(GpioInterruptEvent event) {
if (event.getPin() == 0) {
if (event.getState() == false) {
pulses++;
display = true;
}
}
if (event.getPin() == 7) {
if (event.getState() == false) {
int bpulses = 0;
bpulses++;
pulses += bpulses * 10;
display = true;
}
}
}
});
//setup wiring pi
if (Gpio.wiringPiSetup() == -1) {
System.out.println("Setup Failed!");
return;
}
//pins that will be used
GpioUtil.export(7, GpioUtil.DIRECTION_IN);
GpioUtil.export(0, GpioUtil.DIRECTION_IN);
//edge state whether rising, falling or change
GpioUtil.setEdgeDetection(7, GpioUtil.EDGE_FALLING);
GpioUtil.setEdgeDetection(0, GpioUtil.EDGE_FALLING);
//enabling input as a callback
Gpio.pinMode(7, Gpio.INPUT);
Gpio.pullUpDnControl(7, Gpio.PUD_UP);
GpioInterrupt.enablePinStateChangeCallback(7);
//enabling input as a callback
Gpio.pinMode(0, Gpio.INPUT);
Gpio.pullUpDnControl(0, Gpio.PUD_UP);
GpioInterrupt.enablePinStateChangeCallback(0);
//void loop
for (;;) {
//Thread.sleep(5000);
if (display == true) {
// System.out.println(pulses);
jTextField_pulses.setText(String.valueOf(pulses));
display = false;
}
}
}
}
If I understand you correctly your problem is that your main method in the MainForm.java does not get called when using MainForm from Login.java.
The reason for that is that the main method is the entry point into your program not into your class. Thats why there is usually only one main method in a whole program. If you run Login.java you enter the program in the main method. However when calling MainForm you are already in the program so it does not call the main anymore. Equally when you run MainForm.java alone it needs to enter the program and will run the main.
Suggested solution:
Move your main from MainForm.java in a different method (something called initializePinListening or so) and call it.
Just for the record, there is such a thing as an entry point into a class. Would be the method static{}. But I would consider it bad code style to use that here.
Related
I am pretty new to Java. I have this particular issue that have kept me from moving to the next phase of my project. I want to close a JFrame from my main class from another class and open another jFrame on button click. I have been able to open the second JFrame on button click, but can't close the first JFrame. I am working with Netbeans.
NOTE: I'm trying to have separate codes for views and controller using an MVC design pattern.
Here are my codes.
LoginPage (Main class)
package auth;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoginPage extends javax.swing.JFrame {
public static LoginPage lp = new LoginPage();
public LoginPage() {
initComponents();
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here: Cancel button
System.exit(0);
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here: Login button
String uname = jTextField1.getText();
String pword = jPasswordField1.getText();
try {
LoginController.collectUserData(uname, pword);
} catch (SQLException ex) {
Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new LoginPage().setVisible(true);
}
});
}
and the other class
LoginController
package auth;
import dbconnect.dbconnect;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.swing.*;
public class LoginController extends javax.swing.JFrame {
public static void collectUserData(String uname, String pword) throws SQLException {
Login user = new Login();
user.setUsername(uname);
user.setPass(pword);
checkDatabaseAndLogin(user);
}
public static void checkDatabaseAndLogin(Login test) throws SQLException {
JFrame rootPane;
if (test.getUsername().equals("")||test.getPass().equals("")) {
rootPane = new JFrame();
JOptionPane.showMessageDialog(rootPane, "Some fields are empty", "Error", 1);
} else {
try {
//LoginPage lp = new LoginPage();
Connection con = dbconnect.connect();
PreparedStatement pst = con.prepareStatement("select * from test where username=? and pass=?");
pst.setString(1, test.getUsername());
pst.setString(2, test.getPass());
ResultSet rs = pst.executeQuery();
if (rs.next()) {
String un = rs.getString("username");
//System.out.println(un);
PatronPage pt = new PatronPage(un);
pt.setVisible(true); //Code to open the new window
LoginPage.lp.dispose(); //Code to close the old window
} else {
rootPane = new JFrame();
JOptionPane.showMessageDialog(rootPane, "Username or Password do not match record", "Login error", 1);
}
} catch (Exception ex) {
System.out.println(""+ex);
}
}
}
}
Of course there are other system generated codes in Netbeans I removed, I just provided the chunk of code that I feel are relevant to the solution. Please help out, I'm stuck.
The LoginPage instance that you are "closing" in your LoginController class with the line
LoginPage.lp.dispose();
is not the instance which you initially displayed with
new LoginPage().setVisible(true);
I am afraid your whole approach to creating a Swing UI is wrong. Maybe work through the Swing tutorial first.
I am wanting to set the visibility of a JButton to false in another class. So what I am doing is overriding the boolean function I created in StudentAccount named getWriteBtnVisibility() to change the visibility of the button in the HW class. So basically I want to make the JButton invisible in the StudentAccount. Since I want that button to be visible when a different type of account is logged in.
However, the way I am doing it seems not to be working. I have debugged my code and not understanding why it is not overriding the function. If I can get some guidance, I'd greatly appreciate it.
StudentAccount:
import java.awt.EventQueue;
public class StudentAccount extends AccountTemplate {
/**
* Launch the application.
*/
#Override
public String getHomeworkBtnName() {
return "Submit Assignment";
}
#Override
public boolean getWriteBtnVisibility() {
return false;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
StudentAccount window = new StudentAccount();
window.frmAccountTemplate.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
AccountTemplate:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class AccountTemplate extends HW {
protected JFrame frmAccountTemplate;
/**
* Launch the application.
*/
public String getHomeworkBtnName() {
return "Hw";
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AccountTemplate window = new AccountTemplate();
window.frmAccountTemplate.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public AccountTemplate() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
protected void initialize() {
frmAccountTemplate = new JFrame();
frmAccountTemplate.setTitle(getFrameTitleName());
frmAccountTemplate.setBounds(100, 100, 450, 300);
frmAccountTemplate.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmAccountTemplate.getContentPane().setLayout(null);
JButton btnAssignment = new JButton(getHomeworkBtnName());
btnAssignment.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frmAccountTemplate.dispose();
HW.main(null);
}
});
btnAssignment.setFont(new Font("Tahoma", Font.BOLD, 16));
btnAssignment.setBounds(15, 51, 200, 29);
frmAccountTemplate.getContentPane().add(btnAssignment);
}
}
HW:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.filechooser.FileSystemView;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.awt.event.ActionEvent;
public class HW {
public JFrame frmHw;
/**
* Launch the application.
*/
public boolean getWriteBtnVisibility() {
return true;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HW window = new HW();
window.frmHw.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public HW() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
protected void initialize() {
frmHw = new JFrame();
frmHw.setTitle("HW");
frmHw.setBounds(100, 100, 450, 300);
frmHw.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmHw.getContentPane().setLayout(null);
JTextArea jTextArea1 = new JTextArea();
jTextArea1.setBounds(9, 11, 328, 197);
frmHw.getContentPane().add(jTextArea1);
JScrollPane scrollBar = new JScrollPane(jTextArea1);
scrollBar.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollBar.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
frmHw.getContentPane().add(scrollBar);
scrollBar.setBounds(13, 39, 413, 189);
JButton btnWriteText = new JButton("Write Text");
btnWriteText.setVisible(getWriteBtnVisibility());
btnWriteText.setBounds(154, 11, 115, 24);
frmHw.getContentPane().add(btnWriteText);
}
}
When you made AccountTemplate extend the HW class, every method that was redefined in AccountTemplate overrided the original method from HW. The getWriteBtnVisibility is checked from within the HW's initialize method, but AccountTemplate's initialize method overrides it. Now StudentAccount inherits the overridden method which does not check for the getWriteBtnVisibility boolean and so the visibility is not modified.
If I understand correctly what you're trying to do is to extend the layout using inheritance, however to do that you need to create seperate methods that create and initialize the interface components and call them as required from class. Now you've only created a seperate method for the button name and visibility, but the method that checks for the visibility boolean has been overridden and no longer gets called.
You will have to redesign your architecture so that:
There is only one JFrame field (unless you want multiple interfaces)
There is only one method that creates the JFrame and sets up the title
All generic interface components are created using a seperate (final) method and can be called when required by the class that inherits it
A simple example
class HW {
public JFrame frame;
public String getFrameName() {
return "HW";
}
public boolean getHWBtnVisibility {return true;}
void setupHWComponents() {
JTextField field = new JTextField();
// ...
this.frame.getContentPane().add(field);
JButton button = new JButton("HW");
button.setVisible(getHWBtnVisibility());
// ...
}
void initFrame() {
this.frame = new JFrame(getFrameName());
// ....
}
void initialize() {
initFrame();
setupHWComponents();
}
}
And
class AccountTemplate {
public void setupTemplateComponents() {
JTextField loginField = new JTextField("login");
super.frame.getContentPane().add(loginField);
// ...
}
#Override
public void initialize() {
// Setup Frame and HW components
// If you dont want HW components, replace with initFrame()
super.initialize();
setupTemplateComponents();
}
}
Then the StudentAccount class can likewise choose what components to use and initialize and which ones it doesn't want and then it can add its own components to the frame.
The initialize method that matters, that sets the button's visibility is the one that is called from the HW class, and that method is only called from within AccountTemplate's button's ActionListener here:
public void actionPerformed(ActionEvent e) {
frmAccountTemplate.dispose();
HW.main(null);
}
Notice that it is a call to the HW main method, and so it is a HW instance that is being created when this happens (since that is what HW main creates), not a StudentAccount instance. This is why your inheritance doesn't work -- there is no inheritance happening when the button is created.
Having said that, I have to state that this code is overly complex, much more than it needs to be, and misuses inheritance in a way that only serves to confuse. Don't use inheritance (or absolute positioning and null layouts) since you're just complicating things needlessly. Simply your code and you will thank me.
If this were my project,
I would create distinct JPanels (not JFrames) for each type of GUI
I would use inheritance only for the program's model, the logical non-GUI aspects of the code, and not for the views (the GUI classes), and would use it very cautiously.
I would swap views using a CardLayout and not swap JFrames
In the following java application, I use TwitterStream to gather tweets using sample function. I need to start and stop the stream whenever user wants, but I get the following exception:
java.util.concurrent.RejectedExecutionException: Task twitter4j.StatusStreamBase$1#74e75335 rejected from java.util.concurrent.ThreadPoolExecutor#5117b235[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 2]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
at twitter4j.DispatcherImpl.invokeLater(DispatcherImpl.java:58)
at twitter4j.StatusStreamBase.handleNextElement(StatusStreamBase.java:80)
at twitter4j.StatusStreamImpl.next(StatusStreamImpl.java:56)
at twitter4j.TwitterStreamImpl$TwitterStreamConsumer.run(TwitterStreamImpl.java:568)
When the user presses "Crawl" or "Stop Crawling", the method actionPerformed is correctly called. However, if the user presses Crawl and then presses Stop and then again presses Crawl, I get the error above
I have several classes, but the principal ones are the followings:
The first one creates the interface and comunicates with the crawler class.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
public class StackOv extends JFrame implements ActionListener{
private JTextArea usersSaved;
private boolean alreadyCrawling;
private boolean stopReceived;
private Stream stream;
private JButton Crawl;
private JButton stopCrawl;
private Mongo m;
public StackOv(){
this.stopReceived = false;
this.alreadyCrawling = false;
setLayout(new FlowLayout(FlowLayout.CENTER));
Crawl = new JButton("Crawl");
Crawl.setActionCommand("Crawl");
Crawl.addActionListener(this);
stopCrawl = new JButton("Stop Crawling");
stopCrawl.setActionCommand("Stop Crawling");
stopCrawl.addActionListener(this);
m = new Mongo(); //instance of class that uses MongoDB
/*
*
*bla bla bla create the rest of the interface as you wish
*add(button)
*add(button)
*etc...
*/
}
public void setOut(String out){
usersSaved.setText(out);
}
public void setOffAlreadyCrawling(){
this.alreadyCrawling = false;
}
#Override
public void actionPerformed(ActionEvent e){
if(e.getActionCommand().equals("Stop Crawling") && !this.stopReceived){
this.stopReceived = true;
stream.setStop();
}
else if(e.getActionCommand().equals("Crawl") && !alreadyCrawling){
if(stream != null && stream.isAlive()){
stream.interrupt();
}
alreadyCrawling = true;
stream = new Stream(m, this);
//independently of using one of the following two calls, I get the same exception above
stream.execute1();
//stream.start();
this.stopReceived = false;
}
}
public void main(String[] args){
StackOv so = new StackOv();
so.setSize(800, 800);
so.setVisible(true);
}
}
The following class is the crawler class, that shutdown twitterStream when stopCrawl is true or when twitterStream has sampled a number of tweets over the maximum limit.
import java.awt.TextArea;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import twitter4j.FilterQuery;
import twitter4j.StallWarning;
import twitter4j.Status;
import twitter4j.StatusDeletionNotice;
import twitter4j.StatusListener;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.TwitterStream;
import twitter4j.TwitterStreamFactory;
public class Stream extends Thread{
private Crawler cr;
private TwitterStream twitterStream;
private int maxTweets;
private int usersSaved;
private Mongo database;
private CreateIndex ci;
private TwitterSearch twitterSearch;
private static boolean stopCrawl;
public Stream(Mongo database, TwitterSearch twitterSearch){
Stream.stopCrawl = false;
this.database = database;
this.cr = new Crawler(database);
this.twitterStream = new TwitterStreamFactory(DefaultConfiguration.getConfiguration()).getInstance();
this.maxTweets = 1000;
ci = new CreateIndex(database);
this.twitterSearch = twitterSearch;
}
public void setStop(){
Stream.stopCrawl = true;
}
public void execute() throws TwitterException {
final List<Status> statuses = new ArrayList<Status>();
StatusListener listener = new StatusListener() {
public void onStatus(Status status) {
statuses.add(status);
System.out.println(statuses.size() + ":" + status.getText());
int usersIndexed = cr.retrieve(status.getUser());
usersSaved = database.countDocuments();
twitterSearch.setOut("usersSaved: "+usersSaved);
if(usersIndexed > maxTweets || Stream.stopCrawl){
//ci.load();
ci.load(); //this call creates my index
twitterSearch.setOut("INDEX CREATED");
System.out.println("shutdown...");
twitterSearch.setOffAlreadyCrawling();
twitterStream.shutdown();
}
}
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
}
public void onScrubGeo(long userId, long upToStatusId) {
}
public void onException(Exception ex) {
ex.printStackTrace();
}
#Override
public void onStallWarning(StallWarning arg0) {
// TODO Auto-generated method stub
}
};
twitterStream.addListener(listener);
twitterStream.sample("en");
}
public void execute1(){
try{
this.execute();
}catch(TwitterException e){
e.printStackTrace();
}
}
public void run(){
try {
this.execute();
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
When your thread is shut down/closed, it prevents it from being "restarted", as with other java IO classes. In other words, once you close it, you can't really start it up again. I'm pretty sure somewhere in either the Twitter code or your code, your thread is being stopped. To prevent this from happening, here's a code snippet that may work: http://pastebin.com/APByKuiY
Also, try this stack overflow thingy: What could be the cause of RejectedExecutionException.
I want to have a button that, when clicked, opens the default browser and points to a URI.
I have some code that works in my testing, when run in Netbeans 7.x, but it fails when deployed as a JAR. My Java app runs on Linux only.
Anyone see the problem or know of another solution?
This code is in my main form:
linkBtnTest = new LinkButton(
new URI("http://www.example.com/some-page"),
"Click here for blah blah blah");
linkBtnTest.init();
} catch (Exception ex) {
Logger.log(ex);
}
Accessibility.increaseFontSize(linkBtnTest,
ApplicationContext.get().getFontIncreaseSize());
TestPanel.add(linkBtnTest);
Here's the class. I didn't write this code and I'm open to other suggestions:
package com.example.client;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URI;
import javax.swing.JButton;
public class LinkButton extends JButton
implements ActionListener {
/** The target or href of this link. */
private URI target;
final static private String defaultText = "<HTML>Click the <FONT color=\"#000099\"><U>link</U></FONT>"
+ " to go to the example website.</HTML>";
public LinkButton(URI target, String text) {
super(text);
this.target = target;
//this.setText(text);
this.setToolTipText(target.toString());
}
public LinkButton(URI target) {
this( target, target.toString() );
}
public void init() {
this.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
open(target);
}
class OpenUrlAction implements ActionListener {
#Override public void actionPerformed(ActionEvent e) {
open(target);
}
}
private static void open(URI uri) {
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(uri);
} catch (IOException e) { /* TODO: error handling */ }
} else { /* TODO: error handling */ }
}
}
}
I have a frame which has a button, when it is pressed a JDialog with a progress bar is shown and some data is being fetched using jdbc driver (progress bar is being updated). I needed a cancel button, so I spent some time figuring out how to connect everything. It seems to be working, but I sincerely am not sure if this way is any good. If someone has some spare time please check this code and tell me if anything is wrong with it - mainly with the whole SwingWorker and cancellation stuff.
On my pc (linux) the unsuccessful network connection attempt (someNetworkDataFetching method) takes a whole minute to timeout, do I have to worry about the SwingWorkers which are still working (waiting to connect despite being cancelled) when I try to create new ones?
Note: you need mysql jdbc driver library to run this code.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test extends JFrame {
private JProgressBar progressBar = new JProgressBar();
private JLabel label = new JLabel();
private DataFetcherProgress dfp;
/**
* This class holds retrieved data.
*/
class ImportantData {
ArrayList<String> chunks = new ArrayList<>();
void addChunk(String chunk) {
// Add this data
chunks.add(chunk);
}
}
/**
* This is the JDialog which shows data retrieval progress.
*/
class DataFetcherProgress extends JDialog {
JButton cancelButton = new JButton("Cancel");
DataFetcher df;
/**
* Sets up data fetcher dialog.
*/
public DataFetcherProgress(Test owner) {
super(owner, true);
getContentPane().add(progressBar, BorderLayout.CENTER);
// This button cancels the data fetching worker.
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
df.cancel(true);
}
});
getContentPane().add(cancelButton, BorderLayout.EAST);
setLocationRelativeTo(owner);
setSize(200, 50);
df = new DataFetcher(this);
}
/**
* This executes data fetching worker.
*/
public void fetchData() {
df.execute();
}
}
class DataFetcher extends SwingWorker<ImportantData, Integer> {
DataFetcherProgress progressDialog;
public DataFetcher(DataFetcherProgress progressDialog) {
this.progressDialog = progressDialog;
}
/**
* Update the progress bar.
*/
#Override
protected void process(List<Integer> chunks) {
if (chunks.size() > 0) {
int step = chunks.get(chunks.size() - 1);
progressBar.setValue(step);
}
}
/**
* Called when worker finishes (or is cancelled).
*/
#Override
protected void done() {
System.out.println("done()");
ImportantData data = null;
try {
data = get();
} catch (InterruptedException | ExecutionException | CancellationException ex) {
System.err.println("done() exception: " + ex);
}
label.setText(data != null ? "Retrieved data!" : "Did not retrieve data.");
progressDialog.setVisible(false);
}
/**
* This pretends to do some data fetching.
*/
private String someNetworkDataFetching() throws SQLException {
DriverManager.getConnection("jdbc:mysql://1.1.1.1/db", "user", "pass");
// Retrieve data...
return "data chunk";
}
/**
* This tries to create ImportantData object.
*/
#Override
protected ImportantData doInBackground() throws Exception {
// Show the progress bar dialog.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
dfp.setVisible(true);
}
});
ImportantData data = new ImportantData();
try {
int i = 0;
// There is a network operation here (JDBC data retrieval)
String chunk1 = someNetworkDataFetching();
if (isCancelled()) {
System.out.println("DataFetcher cancelled.");
return null;
}
data.addChunk(chunk1);
publish(++i);
// And another jdbc data operation....
String chunk2 = someNetworkDataFetching();
if (isCancelled()) {
System.out.println("DataFetcher cancelled.");
return null;
}
data.addChunk(chunk2);
publish(++i);
} catch (Exception ex) {
System.err.println("doInBackground() exception: " + ex);
return null;
}
System.out.println("doInBackground() finished");
return data;
}
}
/**
* Set up the main window.
*/
public Test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label.setHorizontalAlignment(SwingConstants.CENTER);
getContentPane().add(label, BorderLayout.CENTER);
// Add a button starting data fetch.
JButton retrieveButton = new JButton("Do it!");
retrieveButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fetchData();
}
});
getContentPane().add(retrieveButton, BorderLayout.EAST);
setSize(400, 75);
setLocationRelativeTo(null);
progressBar.setMaximum(2);
}
// Shows new JDialog with a JProgressBar and calls its fetchData()
public void fetchData() {
label.setText("Retrieving data...");
dfp = new DataFetcherProgress(this);
dfp.fetchData();
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
// Use jdbc mysql driver
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
return;
}
// Show the Frame
new Test().setVisible(true);
}
});
}
}
About the only thing I might do different is not use the SwingUtilities.invokeLater in the doInBackground method to show the dialog, but maybe use a PropertyChangeListener to monitor the changes to the state property worker.
I would also use the PropertyChangeListener to monitor the changes to the progress property of the worker. Instead of using publish to indicate the progression changes I would use the setProgress method (and getProgress in the PropertyChangeListener)
For example...java swingworker thread to update main Gui
I might also consider creating the UI on a JPanel and adding it to the JDialog rather then extending directory from JDialog as it would give the oppurtunity to re-use the panel in other ways, should you wish...