jdialog box opens but appear to be blank - java

I have written the following code to generate please wait JDialog while generation of decision tree but it opens up and appears to be blank
public JDialog pleasewait()
{
JDialog dialog = new JDialog();
JLabel label = new JLabel("Please wait...");
label.setIcon(new javax.swing.ImageIcon(getClass().getResource("/decision_tree_runner/load.gif"))); // NOI18N
dialog.setBackground(Color.BLACK);
dialog.setLocationRelativeTo(null);
dialog.setTitle("Please Wait...");
dialog.add(label);
dialog.pack();
return dialog;
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
JDialog dialog = pleasewait();
dialog.repaint();
dialog.setVisible(true);
FypProject fyp_project = new FypProject();
try {fyp_project.main_fypproject();} catch (SQLException ex) {}
dialog.setVisible(false);
}

It is likely that fyp_project.main_fypproject() is a long running/blocking call, which when called from within the context of the Event Dispatching Thread, will stop it from been able to process new events, including the repaint request.
Consider using something like a SwingWorker, opening the dialog first, execute the worker and when it's done method is called, close the dialog
Take a look at Concurrency in Swing and Worker Threads and SwingWorker for more details

I think it has to do with where in the dialog the JLabel gets added. The lack of our layout manager makes this difficult.
Try adding this before you add the JLabel:
dialog.setLayout(new GridLayout());
and remove:
dialog.pack();

i did the following steps
created separate form for pleasewait
created thread for fyp_project.main_fypproject()
passed object of form to thread class
in run method setvisible() option of pleasewait to false
public class thread_for_pleasewait implements Runnable{
Thread t ;
please_wait_form pwf;
decision_tree dt;
FypProject fyp_project = new FypProject();
#Override
public void run()
{
String[] args = null;
try {
fyp_project.main_fypproject();
pwf.setVisible(false);
dt.setVisible(true);
} catch (SQLException ex) {
Logger.getLogger(thread_for_pleasewait.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void start(please_wait_form pwf,decision_tree dt)
{
t = new Thread(this);
t.start();
this.pwf=pwf;
this.dt=dt;
}
}

Related

How to run two JOptionPane's with threads

I have to set two Dialogs and i want to Stop the first one and then start the second. Can anyone please help me to fix it
JOptionPane msg = new JOptionPane("your score is: " + getScore(), JOptionPane.INFORMATION_MESSAGE);
final JDialog dlg = msg.createDialog("Game Over");
dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dlg.dispose();
}
}).start();
dlg.setVisible(true);
the second Dialog would be the same like
JOptionPane message = new JOptionPane("Highscore: " + getHighscore(), JOptionPane.INFORMATION_MESSAGE);
final JDialog dialog = message.createDialog("Game Over");
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
now i want to start this Dialog after the first will be closed.
Recommendations:
For the sake of Swing thread safety, use a Swing Timer rather than directly using a background thread.
Make it a non-repeating timer.
Inside the timer's ActionListener, close/dispose of the current dialog and open the 2nd.
e.g., (code not tested)
final JDialog myModalDialog = ....;
final JDialog mySecondDialog = ....;
int timerDelay = 3000;
Timer timer = new Timer(timerDelay, e -> {
myModalDialog.dispose();
mySecondDialog.setVisible(true);
});
timer.setRepeats(false);
timer.start();
myModalDialog.setVisible(true);
Alternatively: use a single dialog and swap views using a CardLayout tutorial

JProgressBar in dialog frame not working properly

I have a java program that load a text file as input, read its content, modify some strings and then prints the result to a textarea. Due to several seconds required by this operation i would like to show a JProgressBar during this activity in order to inform the user that the execution is in progress and when the activity is completed close the dialog containing the JprogressBar and print the results.
Here is the code:
JButton btnCaricaFile = new JButton("Load text file");
panel.add(btnCaricaFile);
btnCaricaFile.setIcon(UIManager.getIcon("FileView.directoryIcon"));
btnCaricaFile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//JFileChooser choice = null;
final JFileChooser choice = new JFileChooser(userDir +"/Desktop");
int option = choice.showOpenDialog(GUI.this);
if (option == JFileChooser.APPROVE_OPTION) {
final JDialog dialog = new JDialog(GUI.this, "In progress", true);
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(BorderLayout.CENTER, progressBar);
dialog.getContentPane().add(BorderLayout.NORTH, new JLabel("Elaborating strings..."));
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setSize(300, 75);
dialog.setLocationRelativeTo(GUI.this);
Thread t = new Thread(new Runnable() {
public void run() {
dialog.setVisible(true);
File file = choice.getSelectedFile();
lista.clear();
textArea.setText("");
lista = loadFile.openFile(file);
for(int i=0; i<lista.size(); i++) {
textArea.append(lista.get(i)+"\n");
}
dialog.setVisible(false);
}
});
t.start();
}
}
});
For this purpose i'm using a JDialog as container for the JProgressBar executed by an appropriate thread. The problem is that the progress bar is shown for an infinite time and is not printed anything to the textarea.
Could you help me to solve this?
Thanks
Yes, you're creating a background thread for your file reading, good, but you're also making Swing calls from within this same background thread, not good, and this is likely tying up the Swing event thread inappropriately. The key is to keep your threading separate -- background work goes in the background thread, and Swing work goes only in the Swing thread. Please read Lesson: Concurrency in Swing fore more on this.
Myself, I would create and use a SwingWorker<Void, String>, and use the worker's publish/process method pair to send Strings to the JTextArea safely.
For example, something like...
final JDialog dialog = new JDialog(GUI.this, "In progress", true);
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(BorderLayout.CENTER, progressBar);
dialog.getContentPane().add(BorderLayout.NORTH, new JLabel("Elaborating strings..."));
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setSize(300, 75);
dialog.setLocationRelativeTo(GUI.this);
lista.clear();
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
#Override
public Void doInBackground() throws Exception {
// all called *off* the event thread
lista = loadFile.openFile(file);
for (int i = 0; i < lista.size(); i++) {
publish(lista.get(i));
}
return null;
}
#Override
protected void process(List<String> chunks) {
// called on the event thread
for (String chunk : chunks) {
textArea.append(chunk + "\n");
}
}
// called on the event thread
public void done() {
dialog.setVisible(false);
// should call get() here to catch and handle
// any exceptions that the worker might have thrown
}
};
worker.execute();
dialog.setVisible(true); // call this last since dialog is modal
Note: code not tested nor compiled

Closing A JOptionPane Programmatically

I am working on a project in which I would like to close a generic JOptionPane programmatically (by not physically clicking on any buttons). When a timer expires, I would like to close any possible JOptionPane that may be open and kick the user back to the login screen of my program. I can kick the user back just fine, but the JOptionPane remains unless I physically click a button on it.
I have looked on many sites with no such luck. A doClick() method call on the "Red X" of the JOptionPane does not seem possible, and using JOptionpane.getRootFrame().dispose() does not work.
Technically, you can loop through all windows of the application, check is they are of type JDialog and have a child of type JOptionPane, and dispose the dialog if so:
Action showOptionPane = new AbstractAction("show me pane!") {
#Override
public void actionPerformed(ActionEvent e) {
createCloseTimer(3).start();
JOptionPane.showMessageDialog((Component) e.getSource(), "nothing to do!");
}
private Timer createCloseTimer(int seconds) {
ActionListener close = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
if (dialog.getContentPane().getComponentCount() == 1
&& dialog.getContentPane().getComponent(0) instanceof JOptionPane){
dialog.dispose();
}
}
}
}
};
Timer t = new Timer(seconds * 1000, close);
t.setRepeats(false);
return t;
}
};
This code gotten from
https://amp.reddit.com/r/javahelp/comments/36dv3t/how_to_close_this_joptionpane_using_code/ seems to be the best approach to me. It involves Instantiating the JOptionPane class rather that using the static helper methods to do it for you. The benefit is you have a JOptionPane object that you can dispose when you want to close the dialog.
JOptionPane jop = new JOptionPane();
jop.setMessageType(JOptionPane.PLAIN_MESSAGE);
jop.setMessage("Hello World");
JDialog dialog = jop.createDialog(null, "Message");
// Set a 2 second timer
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (Exception e) {
}
dialog.dispose();
}
}).start();
dialog.setVisible(true);

Am I updating Swing component outside of EDT?

I've been reading a lot about Swing, threading, invokeLater(), SwingWorker, etc., but I just can't seem to get my head around it all, so I was trying to create a really simple program to illustrate. I've looked at a lot of examples, but none of them seem to show just what I'm trying to do.
Here's what I'm trying to do in my example. I have a button and a label, and when I click the button, I want the program to pause for 3 seconds before appending a period to the text of the label. During that 3 seconds, I want the GUI to appear as normal and to continue responding to additional clicks. Here's what I wrote:
import javax.swing.SwingWorker;
public class NewJFrame extends javax.swing.JFrame
{
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
public NewJFrame()
{
initComponents();
}
private void initComponents()
{
jButton1 = new javax.swing.JButton();
jLabel1 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jButton1.setText("Button");
jButton1.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
jButton1ActionPerformed(evt);
}
});
getContentPane().add(jButton1, java.awt.BorderLayout.CENTER);
jLabel1.setText("Text");
getContentPane().add(jLabel1, java.awt.BorderLayout.PAGE_END);
pack();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
SwingWorker worker=new SwingWorker()
{
protected Object doInBackground()
{
try{Thread.sleep(3000);}
catch (InterruptedException ex){}
return null;
}
};
worker.execute();
jLabel1.setText(jLabel1.getText()+".");
}
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run(){ new NewJFrame().setVisible(true); }
});
}
}
with this code, if I click the button, the period is immediately appended to the label, which makes sense to me, because I am creating and sleeping a background thread, leaving the EDT available to update the label immediately. So I tried this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
Thread thread = new Thread();
try{ thread.sleep(3000);}
catch (InterruptedException ex){}
jLabel1.setText(jLabel1.getText()+".");
}
This almost works except that it blocks the EDT causing the button to turn blue for three seconds before appending the period to the label's text. I don't want the button to look like it's being pressed for the whole three seconds when it was really just clicked quickly, so I tried this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
SwingWorker worker=new SwingWorker()
{
protected Object doInBackground()
{
try{Thread.sleep(3000);}
catch (InterruptedException ex){}
jLabel1.setText(jLabel1.getText()+".");
return null;
}
};
worker.execute();
}
This appears to work, but aren't I calling jLabel1.setText(...) from the background thread and not the EDT, and therefore breaking the "Swing Single Threading Rule?" If so, is there a better way to achieve the desired effect? If not, can you please explain why?
You're really close...
Try something like this instead.
SwingWorker worker=new SwingWorker()
{
protected Object doInBackground()
{
try{
Thread.sleep(3000);
}catch (InterruptedException ex){}
return null;
}
// This is executed within the context of the EDT AFTER the worker has completed...
public void done() {
jLabel1.setText(jLabel1.getText()+".");
}
};
worker.execute();
You can check to see if you're running in the EDT through the use of EventQueue.isDispatchingThread()
Updated
You could also use a javax.swing.Timer which might be easier...
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jLabel1.setText(jLabel1.getText()+".");
}
});
timer.setRepeats(false);
timer.start();

Updating the JPanel in a JFrame

I have a JFrame with a CardLayout component. I am using the CardLayout to switch between different JPanel's at different moments of the application execution. At some point I am using a SwingWorker Object to generate some XML files. In this time I want to display another JPanel in my window to tell the user to wait. On this JPanel I want to switch between 3 labels.
JLabel 1 would be : "Please wait."
JLabel 2 would be : "Please wait.."
JLabel 3 would be : "Please wait..."
Right now the code looks like this:
ConvertersWorker.execute();
CLayout.show(Cards, WAIT_PANEL);
Timer t =new Timer(500, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e) {
WaitPanel.SwitchLabels();
}
});
t.start();
while (!this.finishedConverting)
{
}
//After this im am executing other methods based on the generated XML files
The SwingWorker code:
SwingWorker<Boolean, Void> ConvertersWorker = new SwingWorker<Boolean, Void>() {
public Boolean doInBackground() {
Boolean result = RunConverters();
return result;
}
public void done() {
try {
finishedConverting = get();
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
} ;
The second JPanel is not even displayed because the JFrame blocks. It blocks because of the while loop but I don't know how to implement it differently. And also the method done() from the SwingWorker is never executed. If it were executed then the finishedConverting variable would have been set to true and the while loop would have stopped. Can anyone help me to find a better solution?
I know you solved this but that's happening because you are using just one thread, and it blocked because of the While, so you need to create a new thread to handle this
new Thread(){
public void run() {
//code here
}
}.start();
and to refresh the content of a JPanel you can use
myJpanel.doLayout();
or
myJpanel.repaint();
I removed the while loop and moved the code which was after the loop in another method which is executed in the done() method of the SwingWorker so now it works.

Categories