This question already has answers here:
java thread.sleep puts swing ui to sleep too
(3 answers)
Blank Java Swing Frame
(1 answer)
How to run method with JProgressBar
(1 answer)
Issues with SwingWorker and JProgressBar
(1 answer)
Closed 9 months ago.
This post was edited and submitted for review 9 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I am currently writing an app where the user sometimes needs to wait for longer periods of times. Therefore, i have created a progressbar that shows how far along it is. This seemed to work great at first, but now that i have switched from a commandline app to a GUI, the progressbar does not show any of its components.
I have tried to convert the progressbar from a JFrame to a JDialog, but that didn't make the difference. Since my project is quite big i cannot post all of my code, but here is the ProgressBar.java:
public ProgressBar(String operationName, String operationDescription, int operationsMax) {
this.operationsMax = operationsMax;
this.operationName = operationName;
this.operationDescription = operationDescription;
init();
}
private void init(){
this.progress = 0.0;
TextEditor textEditor = TextEditor.getInstance();
if(textEditor == null) {
this.dialog = new JDialog();
dialog.setTitle(operationName);
} else {
this.dialog = new JDialog(textEditor.getFrame(), operationName);
}
this.panel = new JPanel();
this.progressBar = new JProgressBar((int) progress);
this.label = new JLabel(operationDescription);
progressBar.setPreferredSize(new Dimension(650,60));
progressBar.setStringPainted(true);
label.setFont(new Font("Dialog",Font.BOLD, 20));
label.setLabelFor(progressBar);
panel.add(label);
panel.add(progressBar);
dialog.add(panel);
Image img = new ImageIcon(DocHandler.getInstance().getLogoLocation()).getImage();
dialog.setIconImage(img);
dialog.setSize(700, 190);
dialog.setLocationRelativeTo(null);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.setResizable(false);
dialog.requestFocus();
dialog.setVisible(true);
}
/**
* Sets the progress of the bar to the specified percent level
* #param percent
*/
public void updateProgress(double percent) {
this.progress = percent*100;
int progressInt = (int) progress;
progressBar.setValue(progressInt);
progressBar.setVisible(true);
label.setVisible(true);
System.out.println("WHY NOT SHOWING :((");
dialog.invalidate();
dialog.validate();
dialog.repaint();
}
public void close() {
//removed the sleep statement
dialog.dispose();
}
}
I hope you can help me out with this one :)
Here you can find a screenshot of how it looks at first before the main frame is created and how it looks afterwards. https://i.stack.imgur.com/laUxo.png
Edit:
I have received some helping saying I should use a SwingWOrker, I have tried this in the specific location:
SwingWorker<NGram,Void> modelCreatorTask
= new SwingWorker<NGram, Void>() {
#Override
protected NGram doInBackground() throws Exception {
NGram model = ModelCreator.createModel(N);
return model;
}
};
modelCreatorTask.execute();
try {
model = modelCreatorTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
System.err.println("Failed to create model.");
System.exit(0);
}
But still the dialog remains empty.
Related
I'm trying to code a primitive spammer. Is it okay to use thread.sleep() when coding a bot?
I'm a novice programmer. If there is any place in my code to fix it, I would appreciate it if you let me know. I may have used JComponents improperly. If it catches your eye, you can specify. Thank you.
Note: "It looks like your post is mostly code; please add some more details." I'm writing this note because I can't find any more details to add. Sorry
public class Spammer extends JFrame implements Runnable{
private boolean running = false;
private JButton jButton1;
private JLabel jLabel1, jLabel2;
private JScrollPane jScrollPane1;
private JSpinner jSpinner1;
private JTextArea jTextArea1;
public Spammer() {
setLayout(null);
jLabel1 = new JLabel("Text: ");
jTextArea1 = new JTextArea(10,28);
jLabel2 = new JLabel("Interval: ");
jSpinner1 = new JSpinner();
jScrollPane1 = new JScrollPane();
jButton1 = new JButton("Spam");
jButton1.setSize(350, 60);
jButton1.setLocation(100, 220);
jLabel1.setSize(50, 150);
jLabel1.setLocation(15, 10);
jLabel1.setFont(new Font("Verdana" , Font.BOLD , 14));
jTextArea1.setSize(350, 150);
jTextArea1.setLocation(100, 10);
jLabel2.setSize(80, 25);
jLabel2.setLocation(15, 180);
jLabel2.setFont(new Font("Verdana" , Font.BOLD , 12));
jSpinner1.setSize(350, 25);
jSpinner1.setLocation(100, 180);
getContentPane().add(jLabel1);
getContentPane().add(jTextArea1);
getContentPane().add(jLabel2);
getContentPane().add(jSpinner1);
getContentPane().add(jScrollPane1);
getContentPane().add(jButton1);
setTitle("Spammer by Me");
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(500, 340));
pack();
jButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1ActionPerformed();
}
} );
}
private void jButton1ActionPerformed() {
if(!running) {
jTextArea1.setEnabled(false);
jSpinner1.setEnabled(false);
jButton1.setText("Spamming in 3 seconds...");
jButton1.setEnabled(false);
running = true;
new Thread(this).start();
}else {
jTextArea1.setEnabled(true);
jSpinner1.setEnabled(true);
jButton1.setText("Spam");
running = false;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Spammer().setVisible(true);
}
});
}
public void run() {
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
int[] keys = new int[jTextArea1.getText().length()];
if((int) jSpinner1.getValue() < 0) {
jSpinner1.setValue((int) 0);
}
int interval = (int) jSpinner1.getValue();
for(int i = 0 ; i < keys.length; i++) {
keys[i] = KeyEvent.getExtendedKeyCodeForChar(jTextArea1.getText().charAt(i));
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jButton1.setEnabled(true);
jButton1.setText("Stop");
while(running) {
for(int i = 0 ; i < keys.length; i++) {
robot.keyPress(keys[i]);
robot.keyRelease(keys[i]);
}
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The key principle at work here is primarily the 'EDT' - the Event Dispatch Thread. This is a thread that does GUI stuff - if for example you drag the titlebar of a completely different app's window across the screen, and this moves that app's window over yours, the EDT is hard at work redrawing everything. The EDT is the thread that sees you press your mouse down on a button, and will render the button in the 'pressed in' view.
The EDT is the only thread from which you can do GUI stuff, whether it is to retrieve info, such as getText(), or whether it is to change things, such as updating the text of a label or whatnot.
The EDT is also the thread you're in when your code runs that you registered as a handler for events, such as the code that responds to a button click or whatnot.
You therefore must not sleep on the EDT (Because then your app looks non-responsive; the thread that responds to button clicks or repaints what needs repainting is not actively running), but you can only fetch GUI data / set GUI stuff from the EDT.
The rules:
Do not interact with any GUI elements unless you are in the EDT
Never sleep in the EDT
Your code is broken, not because you sleep (that's fine - that run() method is not in the EDT), but because you do GUI stuff from this non-EDT thread.
You need to do a careful dance here: You want to sleep (not allowed on the EDT), but interact with GUI elements, such as the interval box, to know how long to sleep, which can only be done on the EDT.
To do this, you can 'send' code to run in the EDT via SwingWorkers, or simply via:
SwingUtilities.invokeAndWait(() -> {
// code that will run in the EDT goes here
});
You can't set any variables from within this code, but you can use AtomicReference and friends to create objects you can change. So, instead of:
int[] keys = new int[jTextArea1.getText().length()];
if (jSpinner1.getValue() < 0) {
jSpinner1.setValue(0);
}
int interval = (int) jSpinner1.getValue();
which is doing GUI stuff, do:
AtomicInteger interval = new AtomicInteger();
SwingUtilities.invokeAndWait(() -> {
int[] keys = new int[jTextArea1.getText().length()];
if (jSpinner1.getValue() < 0) {
jSpinner1.setValue(0);
}
interval.set((int) jSpinner1.getValue());
};
I have a 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
I am trying to show a progress bar while I do some tasks on a database. The Progress bar, however, freezes and the Things I want to do on the database aren't executed. I understand that, in order to guarantee proper concurrency in Swing I need to do the database tasks on a secondary thread. I also understand that somehow my bug has to do with JOptionPane. But I can't come up with a solution to fix it. Here is the Code for my Progress Dialog:
public class ProgressDialog extends JDialog {
/**
*
*/
private static final long serialVersionUID = 1L;
public ProgressDialog() {
setModal(true);
setTitle("Fortschritt");
setSize(200, 100);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JProgressBar pb = new JProgressBar();
pb.setIndeterminate(true);
pb.setValue(0);
add(pb);
setVisible(true);
}
}
And here is the Code where I call this constructor:
int result = JOptionPane.showConfirmDialog(GUIAutoTest.jtable,
"Schaden mit Testkonfig = " + index + " anlegen ?", "Bestätigen",
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
new SwingWorker<Void, Void>() {
final ProgressDialog pd = new ProgressDialog();
#Override
protected Void doInBackground() throws Exception {
InitTestLauf itl;
try {
itl = new InitTestLauf(index);
StartTestLauf stl = new StartTestLauf(itl.getIdTstLauf());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void done() {
System.out.println("done");
pd.setVisible(false);
}
}.execute();
JOptionPane.showMessageDialog(GUIAutoTest.jtable,
"Schaden angelegt. " + "Schadennummer: " + StartTestLauf.getSchadenNr(),
"Schaden angelegt", JOptionPane.PLAIN_MESSAGE);
It doesn't matter, what happens inside the doInBackground()-block , not even System.out.println("print something") does work. Where is my mistake ?
Thanks in advance!
I made an example that uses a progress bar with a dialog and a swingworker.
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import java.util.List;
/**
* Created on 13.06.17.
*/
public class DialogJunker {
static class ProgressDialog extends JDialog {
JProgressBar bar;
ProgressDialog(){
setModal(true);
bar = new JProgressBar();
add(bar);
pack();
}
void setProgress(int i){
bar.setValue(i);
}
}
public static void main(String[] args){
JFrame frame = new JFrame("diddly dialog");
JButton button = new JButton("start");
button.addActionListener(evt->{
ProgressDialog log = new ProgressDialog();
new SwingWorker<Void, Integer>(){
#Override
public Void doInBackground(){
for(int i = 0; i<100; i++){
try{
Thread.sleep(10);
publish(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
public void done(){
log.setVisible(false);
log.dispose();
}
#Override
protected void process(List<Integer> ints){
log.setProgress(ints.get(0));
}
}.execute();
log.setVisible(true);
});
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
This example will show a dialog with a progress bar that gets updated, then close the dialog when finished.
After reviewing you code a little more, I do see the problem. You are constructing the ProgressDialog in the SwingWorker class, but you set your progress dialog to visible, which blocks. Take note that I have solved quite a few issues.
I call set visible after starting the swing worker.
I publish the results so that the dialog actually gets updated.
I keep a reference to the progress bar, so it actually can be updated.
This question already has an answer here:
Closing a runnable JOptionPane
(1 answer)
Closed 7 years ago.
I want to close a JOptionPane after passed some time, i have tried with dispose(), hide(), and using the command getRootPane().dispose() with no results.
I want to close it after 3 seconds or more so the user don't need to press the button at any time the JOptionPane emerges.
You can use one of these statements to hide/close the JFrame.
Frame.setVisible(false);
or
jFrame.dispose();
i.e.
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setContentPane(new JOptionPane());
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
Thread.sleep(5000); //sleep 5 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
frame.setVisible(false);
}
You can loop over the active windows creating this method on the class you want to do it:
private Timer createTimerClose(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;
}
And after it you call the metod createTimerClose(secondsyouwanttoclose).start(); before calling your JOptionPane.
This question already has an answer here:
While loop with delay makes JFrame unresponsive
(1 answer)
Closed 9 years ago.
I am making a simple PopUp game where the code below calls a new instance of a class called PopUp. PopUp is a Jframe with a button on it. When the constructor is called inside the loop the button is not displayed. However when the loop is removed the button is displayed just fine. Please help me. Thank you.
public void game() {
PopUp p1;
while(!gameover) {
try {
//If block to set the difficulty of the game
if(diff==0)
TimeUnit.MILLISECONDS.sleep(1000);
else if(diff==1)
TimeUnit.MILLISECONDS.sleep(750);
else if(diff==2)
TimeUnit.MILLISECONDS.sleep(500);
else if(diff==3)
TimeUnit.MILLISECONDS.sleep(250);
else if(diff==4)
TimeUnit.MILLISECONDS.sleep(100);
p1 = new PopUp(); //keep
p1.setLocation(((int)(Math.random()*2000)), ((int)(Math.random()*1000)));
popUpsOpen++;
} catch (InterruptedException ex) {
Logger.getLogger(PopUpGame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Try to call Game constructor with different Thread.
Thread queryThread = new Thread() {
public void run() {
new game();
}
};
queryThread.start();
and in Game constructor show the popup with UI thread
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
p1 = new PopUp(); //keep
p1.setLocation(((int)(Math.random()*2000)), ((int)(Math.random()*1000)));
popUpsOpen++;
}
});
i think the button is not displaying because the UI thread busy with looping,so the button doesnt get chance to rendered by UI thread
place the these statements after the try-catch block, and also check the value of the variable gameover.
p1 = new PopUp(); //keep
p1.setLocation(((int)(Math.random()*2000)), ((int)(Math.random()*1000)));
popUpsOpen++;