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.
Related
I created a shop cart login JFrame and I added a "shopkeeperToggle" so that when it's pressed the user logs in to the shopkeeper's JFrame and otherwise to a shopper's jframe. the problem is I don't know how to implement it, I tried to set a boolean "pressed" to false whenever the key is released in the "shopkeeperToggle" key listener, and apparently I'm unable to use the value of pressed inside the sign-in button.
Here's the code for the toggle:
shopkeeperToggle = new JToggleButton("Shopkeeper");
shopkeeperToggle.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
pressed = false;
}
});
and this is what I'm trying to do in the sign in button:
signinButton = new JButton("Sign in ");
signinButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3308/shoppingCart","root","");
// select the users that have the inputted credentials from the database
String sql = "SELECT * FROM users WHERE userUsername = ? AND userEmail =?AND userPassword = ? ";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,usernamelogin.getText());
ps.setString(2, emaillogin.getText());
ps.setString(3,passwordlogin.getText());
ResultSet rs = ps.executeQuery();
// if query executed and
if (rs.next()) {
// if login succ show window log succ, and go to home shopping page
JOptionPane.showMessageDialog(null,"Login successful! :)");
/////////////////this is where I fail////////////////////
if (pressed) {
OwnerHomePage ownerhome = new OwnerHomePage();
ownerhome.setVisible(true);
setVisible(false);
} else {
UserHomePage home = new UserHomePage();
home.setVisible(true);
setVisible(false);
}
} else {
JOptionPane.showMessageDialog(null,"Wrong Username or Email or Password :(");
}
} catch (Exception e1) {
JOptionPane.showMessageDialog(null,e1);
}
}
}
This may offer some help in fixing your issue. It is a fully compilable demo. The following changes were made.
Used Actions in lieu of KeyListener. A little more involved to setup but they can be configured to monitor only certain keys.
Used a JButton in lieu of a JToggleButton. No specific reason and can be changed.
Created separate inner classes for the listeners. Tends to reduce clutter and is usually more readable.
Changed the name of the button depending on the mode.
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class ActionMapAndButtons {
JFrame frame = new JFrame("Demo");
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new ActionMapAndButtons().start());
}
public void start() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyClass cls = new MyClass();
frame.add(cls);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyClass extends JPanel {
JButton button = new JButton("Shopper Sign in");
boolean pause = false;
public MyClass() {
setPreferredSize(new Dimension(300, 300));
button.addActionListener(new ButtonListener());
add(button);
InputMap map = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
for (int i = 0; i < 256; i++) {
map.put(KeyStroke.getKeyStroke((char)i), "anyKey");
}
getActionMap().put("anyKey", new MyAction());
setFocusable(true);
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent ae) {
Object obj = ae.getSource();
if (obj instanceof JButton) {
JButton b = (JButton) obj;
pause = !pause;
if (pause) {
b.setText("Shopkeeper Sign in");
} else {
b.setText("Shopper Sign in");
}
}
}
}
private class MyAction extends AbstractAction {
public void actionPerformed(ActionEvent ae) {
String cmd = ae.getActionCommand();
if (pause) {
System.out.println("Shopkeeper - " + cmd);
} else {
System.out.println("Shopper - " + cmd);
}
}
}
}
Inner (or nested) classes and action maps are covered in The Java Tutorials
You can define pressed as a static value;
class c {
static boolean pressed = true;
...
}
and you can access anywhere;
c.pressed; //will return true if you don't change
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.
I am trying to make a function that allows you to navigate to a webpage. I can how to run the function, I just don't know how to write the part of the program that accesses the webpage. Here is the code that I am using to access the function via a JButton. I would like the program to work on multiple platforms. All of the solutions I have found to this, I either don't understand well enough to modify to my needs, or it isn't multi-platform.
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton google = new JButton("Google");
linux.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openURL("http://www.google.com/");
}
} );
JButton stackoverflow = new JButton("Stackoverflow");
JButton blah = new JButton("blah");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(linux);
panel.add(osx);
panel.add(windows);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
Yes I am aware the last two buttons do nothing.
Here is what I have tried so far:
public static void openURL(String url) {
String osName = System.getProperty("os.name");
try {
if (osName.startsWith("Windows"))
Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
else {
String[] browsers = {"firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape", "chrome" };
String browser = null;
for (int count = 0; count < browsers.length && browser == null; count++)
if (Runtime.getRuntime().exec(new String[] {"which", browsers[count]}).waitFor() == 0)
browser = browsers[count];
Runtime.getRuntime().exec(new String[] {browser, url});
}
}
catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error in opening browser" + ":\n" + e.getLocalizedMessage());
}
}
Unfortunately, I don't understand what this does, or how to change it to my needs.
If possible could you explain your solution so that I can understand how it works? Thanks.
You can use Desktop class which allows Java applications to interact with default applications associated with specific file types on the host platform. Here you have a tutorial on How to integrate with the Desktop class.
Remember:
Use the isDesktopSupported() method to determine whether the Desktop
API is available
I made a quick example.
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class DesktopTest {
private JPanel panel;
public DesktopTest() {
panel = new JPanel();
ActionListener listener = new OpenUrLAction();
JButton googleButton = new JButton("google");
googleButton.setActionCommand("http://www.google.com");
googleButton.addActionListener(listener);
JButton stackOverButton = new JButton("stackOverflow");
stackOverButton.setActionCommand("http://www.stackoverflow.com");
stackOverButton.addActionListener(listener);
panel.add(googleButton);
panel.add(stackOverButton);
}
public JPanel getPanel() {
return panel;
}
private class OpenUrLAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (Desktop.isDesktopSupported()) {
try {
Desktop desktop = Desktop.getDesktop();
desktop.browse(new URI(e.getActionCommand()));
} catch (IOException | URISyntaxException e1) {
JOptionPane.showMessageDialog(null,
"An error happen " + e1.getMessage());
}
}
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("DesktopExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(Boolean.TRUE);
frame.add(new DesktopTest().getPanel());
// Display the window.
frame.pack();
frame.setVisible(Boolean.TRUE);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
If you don't find this useful , you can find some workaround in this answer
I am attempting to print to my JTextArea from another class. I have the class ActivityLogger call method Alert inside of my main class Risk_Mgnt_Manager which is where the JTextArea is located. I am able to pass the string into this method and print to counsel but it won't append or setText to the JTextArea. What am I missing?
My goal is to have different classes send messages to the class ActivityLogger which in turn sends it to the JTextArea.
Any examples are appreciated and Thank you in advance.
Main class
package risk_mgnt_manager;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
public class Risk_Mgnt_Manager extends JFrame{
boolean begin = false;
String message = null;
JTextArea text = new JTextArea();
JButton Start = new JButton("Start");//exit program button
JButton End = new JButton("End");//Ok button executes message creation
JButton Exit = new JButton("Exit Program");
public void Alert(String a){
System.out.println(a); // This is printing correctly
text.append(a + "\n"); // why won't this display the string?
}
public Risk_Mgnt_Manager(){
text.setEditable(false);
text.setWrapStyleWord(true);
text.setLineWrap(true);
JScrollPane scroll = new JScrollPane(text);
setLayout(new GridLayout(2, 3, 5, 5)); //LayoutManager Setup
JPanel myPanel = new JPanel(new GridLayout(3,0));
//JPanel myPanel2 = new JPanel(new GridLayout(1, 1));
//JPanel myPanel3 = new JPanel(new GridLayout(1, 1));
JPanel myPanel4 = new JPanel(new GridLayout(1, 1));
myPanel.add(new JLabel("Start Automated Processes: "));
myPanel.add(Start);
myPanel.add(new JLabel("End Automated Processes: "));
myPanel.add(End);
myPanel.add(new JLabel(" "));
myPanel.add(Exit);
myPanel4.add(text);
Start.addActionListener(new startActions());//Listener for button 1
End.addActionListener(new stopActions());//Listener for button 2
Exit.addActionListener(new Quit());//Listener for button 2
add(myPanel);
//add(myPanel2);
//add(myPanel3);
add(myPanel4);
}
public void StartAutomation(boolean start) throws SAXException, ParserConfigurationException, IOException, SQLException{
//calls test class
Test t = new Test();
t.mainTest(begin);
//ignore these classes
// Step one import settlement data from FIX 1 settlement tables
ImportSettles tbl = new ImportSettles();
//tbl.DataTransfer(begin);
// Step two import Real-Time price data from t_span_price on FIX 1
ImportSpanPrice tbl2 = new ImportSpanPrice();
//tbl2.DataTransfer1(begin);
// Step three import from xml file
ImportTradeData tbl3 = new ImportTradeData();
//tbl3.parseXML(begin);
// Step four not used as of 11/26/2013
ImportFirmRpt tbl4 = new ImportFirmRpt();
// Step five import poew.csv file
ImportPOEW tbl5 = new ImportPOEW();
//tbl5.csvImportPOEW(begin);
// Step six import paycollect.csv file
ImportPaycollect tbl6 = new ImportPaycollect();
//tbl6.csvImportPaycollect(begin);
// Step seven import data from RISK 1
ImportSecDeposit tbl7 = new ImportSecDeposit();
//tbl7.DataTransfer2(begin);
// Step 8 import FCM financial info, WinJammer not used as of 11/26/2013
ImportFCM tbl8 = new ImportFCM();
// Step nine import CGM_post.csv file
ImportCGMPost tbl9 = new ImportCGMPost();
//tbl9.csvImportCGMPost(begin);
// Step ten import RM_Intraday_paycollect.csv
ImportIntraday tbl10 = new ImportIntraday();
//tbl10.csvImportIntra(begin);
}
private static void ProjectFrame(){
Risk_Mgnt_Manager projectFrame = new Risk_Mgnt_Manager();
projectFrame.setSize(500, 300); //JFrame size set
projectFrame.setLocationRelativeTo(null); //JFrame centered to center of screen
projectFrame.setTitle("Automation Control"); //JFrame Title
projectFrame.setVisible(true);//JFrame is visible upon start of program
projectFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
ProjectFrame();
}
static class Quit implements ActionListener {
public void actionPerformed (ActionEvent e) {
//Once Exit JButton is pressed the program exits
System.exit(0);
}
}
public class startActions implements ActionListener {
public void actionPerformed (ActionEvent e) {
//Once Exit JButton is pressed the program exits
begin = true;
try {
StartAutomation(begin);
} catch (SAXException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
} catch (ParserConfigurationException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class stopActions implements ActionListener {
public void actionPerformed (ActionEvent e) {
//Once Exit JButton is pressed the program exits
begin = false;
try {
StartAutomation(begin);
} catch (SAXException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
} catch (ParserConfigurationException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
Logger.getLogger(Risk_Mgnt_Manager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Test class
package risk_mgnt_manager;
import java.util.Date;
/**
*
* #author bgilbert
*/
public class Test {
public void mainTest(boolean a){
ActivityLogger act = new ActivityLogger();
act.logger("Testing message reporting " + new Date(), 1, true);
}
}
ActivityLogger class
package risk_mgnt_manager;
/**
*
* #author MLaMeyer
*/
public class ActivityLogger{
private String message;
// this will perform different purposes once I can print to JTextArea
public void logger(String log, int type, boolean execution){
if (execution == true) {
message = log;
}
if (execution == false) {
message = log;
}
print();
}
// calls method Alert in main class and passes the string correctly
public void print(){
Risk_Mgnt_Manager m = new Risk_Mgnt_Manager();
m.Alert(message);
}
}
Your program prints out to the other class, just not in the object displayed:
public void print(){
Risk_Mgnt_Manager m = new Risk_Mgnt_Manager();
m.Alert(message);
}
When you create a new Risk_Mgnt_Manager, you do just that, create a new completely unique Risk_Mgnt_Manager object, one that is not displayed. Printing to it will have no effect on the displayed one.
A the solution is to pass in a reference to your logger class to the actual displayed Risk_Mgnt_Manager object.
public class ActivityLogger{
private String message;
private Risk_Mgnt_Manager m; // ***** added
public ActivityLogger(Risk_Mgnt_Manager m) {
this.m = m; // ****** added
}
// this will perform different purposes once I can print to JTextArea
public void logger(String log, int type, boolean execution){
if (execution == true) {
message = log;
}
if (execution == false) {
message = log;
}
print();
}
// calls method Alert in main class and passes the string correctly
public void print(){
// Risk_Mgnt_Manager m = new Risk_Mgnt_Manager();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
m.Alert(message);
}
});
}
}
Whatever you do, don't attempt to solve this my making anything static as that road will lead to misery.
You need to update the UI in separate Thread, I mean UI related operations should run on the Event dispatch thread. Add constructor in your ActivityLogger class like Hovercraft's solution then try,
SwingUtilities.invokeLater(new Runnable() {
public void run() {
text.append(a+"\n");
}
});
First of all make the frame visible in your constructor.
public Risk_Mgnt_Manager(){
setVisible(true);
}
Then as per solution by Hovercraft pass by reference.
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...