I am writing a program in Java and I want to add a loading page where it displays a progress bar and a label saying what is loading and the bar showing how far it is to completing, I have everything set up so it should work but it doesn't, I do not know what is wrong (I am new to java so please have mercy)
I have tried having a boolean that is set to false by default and is set to true only after "after-all-set-code" has been executed (I am using netbeans to create the GUI) and when I call the function to update the text/progress bar, if the boolean is still set to false it will wait a second and retry till the "all-set-code" changes it to true, but that doesn't seem to work.
This is inside my main class
public class Xtra {
public static loadingPage LP = new loadingPage();
public static void main(String[] args) {
// Show loading page
LP.main(args);
// Set loading
LP.setLoading(0, "Fetching Config...");
// Get Config
// Durring the "getConfig" function it calls the function "LP.setLoading()" multiple times to update the loading bar & text
Xtra.getConfig();
// Set loading
LP.setLoading(0, "Loading user data...");
}
}
This is my setLoading() class inside of loadingPage:
public void setLoading(int per, String txt) {
if ("".equals(txt)) {
setLoadingValue(per);
} else {
setLoadingText(txt);
setLoadingValue(per);
}
}
This is my setLoadingValue() function:
public void setLoadingValue(int x) {
// This will turn true when the after-all-set code runs
while (!loadingBarLoaded) {
// Try to wait a second,
// Do this so it doesn't take up too much CPU
try {
// Wait a second
TimeUnit.SECONDS.sleep(1);
// Print to console
System.out.println("Loading value not loaded,\nWaiting another second");
// If there is an error waiting
} catch (InterruptedException ex) {
// Alert user
System.out.println("You cannot sleep now, monsters are nearby");
}
}
// After loaded boolean turns true
// Alert user of change
System.out.println("Setting loading value to " + x + "%");
// Change value
loadingBar.setValue(x);
}
This is my setLoadingText() function:
public void setLoadingText(String txt) {
// This will turn true when the after-all-set code runs
while (!loadingTextLoaded) {
// Try to wait a second,
// Do this so it doesn't take up too much CPU
try {
// Wait a second
TimeUnit.SECONDS.sleep(1);
// Print to console
System.out.println("Loading text not loaded,\nWaiting another second");
// If there is an error waiting
} catch (InterruptedException ex) {
// Alert user
System.out.println("You cannot sleep now, monsters are nearby");
}
}
// After loaded boolean turns true
// Alert user of change
System.out.println("Setting loading text to \"" + txt + "\"");
// Change value
loadingText.setText(txt);
}
and my after-all-set-code is loadingTextLoaded = true & loadingBarLoaded = true depening on what is finished
It's supposed to update the text and the value of the progress bar but it isn't, it is outputting the Settings loading text to "..." to the console & the Setting loading value to ...% to the console as well, but not changing the actual value or text of the components.
What am I doing wrong?
Minimalistic problem: (Main file)
// Inside main function
// Show loading page
LP.main(args);
LP.loadingBar.setValue(50);
LP.loadingText.setText("Hello");
// nothing changes. (Both are public so I can call them from different files
This is what the loadingBar & loadingText vars and declared like
public javax.swing.JProgressBar loadingBar;
public javax.swing.JLabel loadingText;
loadingBarLoaded & loadingTextLoaded is declared like this
public boolean loadingTextLoaded = false;
public boolean loadingBarLoaded = false;
loadingTextLoaded & loadingBarLoaded and changed to true after all the generated code puts them into place inside the window after the all-set-code is ran (I am using NetBeans GUI builder so the code is generated)
Inside the loadingPage.java this is how it is laid out.
The main window and there is a panel covering the entire main window and it has three things inside of it, a label at the top that sits in the middle, it has the application name "Xtra" and below it the loadingText subtitle that small and says what is currently loading, below that, a progress bar loadingBar.
Here is a screen shot of the layout
Sorry if I am not following the unwritten coding rules, I only started with java like a week ago.
Learn about threading in swing. You have to use a SwingWorker and do the loading in the doInBackground() method and return progress there.
import javax.swing.*;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class Main {
private JProgressBar prog;
public static void main(String[] args) throws InvocationTargetException, InterruptedException {
SwingUtilities.invokeAndWait(()-> new Main().initGUI());
}
private void initGUI(){
JDialog dialog = new JDialog();
dialog.setTitle("Progress");
prog = new JProgressBar();
prog.setMaximum(100);
dialog.add(prog);
dialog.pack();
dialog.setVisible(true);
BackgroundWorker bw =new BackgroundWorker();
bw.execute();
}
private class BackgroundWorker extends SwingWorker<String, Integer>{
#Override
protected String doInBackground() throws Exception {
try{Thread.sleep(1000);}catch(Exception e){}
publish(10);
try{Thread.sleep(1000);}catch(Exception e){}
publish(20);
try{Thread.sleep(1000);}catch(Exception e){}
publish(30);
try{Thread.sleep(1000);}catch(Exception e){}
publish(70);
try{Thread.sleep(1000);}catch(Exception e){}
publish(100);
return "finished";
}
#Override
protected void process(List<Integer> chunks) {
prog.setValue(chunks.get(chunks.size()-1));
}
}
}
Important is, that you don't access any Swing Component from the doInBackground() method, as this method is not called from the Swing Event Dispatch Thread.
I fixed it, when the GUI builder created the page it used this code
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new loadingPage().setVisible(true);
}
});
I changed it to:
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
LP.setVisible(true);
}
});
and at the begining of the file I put this:
public static loadingPage LP = new loadingPage();
and it seemed to work.
Related
i'm trying to make a poker game for a school project and im having particular difficulty changing this one variable. My code uses a while loop in the main of my class to handle data coming from the server, and as such data cannot be sent back to the server outside this loop. because of this, I need to change the value of the turnOver boolean variable within the ActionListener so that code in the while loop can be executed accordingly. However, when i try to change it, it's almost as if the value it's changed to is immediately disregarded once the ActionListener code is complete, and as such, the code within the loop never gets executed. The ActionListener is defined within the main.
Is there a way to 'retain' the value that the boolean turnOver is changed to so that i can use it again in the main? I've tried to explain this as best as i can and i will attach my code below (i'm pretty new to all this server/socket based stuff). Thank you for reading.
Relevant code for the actionListener:
public class Client {
public static Client bob = new Client();
private static boolean turnOver = false;
public static Table clientTable = new Table();
public static void main(String[] args) throws Exception {
System.out.println("player joining");
Scanner s = new Scanner(System.in);
bob.startConnection("127.0.0.1", 8000);
System.out.println("player joined");
clientTable.betButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
System.out.println("value of turnOver: " + turnOver);
Client.this.turnOver = true;
System.out.println("value of turnOver: " + turnOver);
System.out.println("bet button clicked");
}
catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
Relevant code for the while loop within the same main method:
while (true) {
System.out.println("value of turnOver before check " + turnOver);
if (turnOver == true) {
System.out.println("reached turn over status");
[REST OF METHOD]
}
With this current implementation, i never see the message "reached turn over status", and from that i assume that the value of turnOver is never true, even though i set it to be so in the ActionListener. How may i rectify this? Thank you.
This question already has answers here:
Can a progress bar be used in a class outside main?
(3 answers)
Closed 7 years ago.
It is the first time I have to work with a progress bar and I'm facing a problem, besides I try to call its setValue(x) from everywhere it keeps on 0% and goes straight to 100% after my method routine finishes.
I tried to make an inner class that extends Thread, then after I tried to start a new Thread within my "main" method, then for the last I tried to use the Observer. These ones seems to have worked according to this posts but unfortunately not to me
Update JProgressBar from new Thread
Problem making a JProgressBar update values in Loop (Threaded)
please, could someone help me???
public class MainClass {
private void checkFiles() {
Task task = new Task();
task.start();
//here I have some Files validation...I don't think it is important to solve the progressbar problem
//so it will be ommited
//in this point I tried to call update to test the observer solution I found in another post here
//task.update(null, null);
JOptionPane.showMessageDialog(this, "Done!");
//here the bar jumps from 0% to 100%
}
private class Task extends Thread implements Observer {
public Task() {
}
//Dont bother with the calculum as I haven't finished working on them....
//The relevant thing here is that it starts a new Thread and I can see the progress
//increasing on console using system.out but my progress bar still don't change from 0%.
public void run() {
int maxSize = 100;
final int partsSize = maxSize / listaArquivosSelecionados.size();
while (listFilesValidated.size() != listFilesToValidate.size()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int progress = listFilesValidated.size() * partsSize;
System.out.println("Progress" + progress);
progressBar.setValue(progress);
}
});
try {
Thread.sleep(100);
}
catch (InterruptedException e) {}
}
}
//Just tried to set any value to check if it would update before the files validation thread finishes its work.
#Override
public void update(Observable arg0, Object arg1) {
progressBar.setValue(66);
}
}
You can create another class of ProgressBar (see Oracle tutorial) and use this:
ProgressBar pbFrame = new ProgressBar();
pbFrame.setVisible(true);
Executors.newSingleThreadExecutor().execute(new Runnable() {
#Override
public void run() {
// run background process
}
});
Or you can use SwingWorker, for example:
SwingWorker worker = new SwingWorker<MyReturnType, Void>() {
#Override
public MyReturnType doInBackground() {
// do your calculation and return the result. Change MyReturnType to whatever you need
}
#Override
public void done() {
// do stuff you want to do after calculation is done
}
};
I had the same question some years ago.
I am new at Java Swing.
I have two Java files. One having main() in it and the other is the GUI file.
Client
class Client
{
GUI gui;
public static void main(String args[])
{
//.......... do something.......
gui = new GUI();
// at thin point I want to have value of gui.s1 ....
//but main() actually do not wait for the user input.
}
}
GUI
class GUI extends JFrame implements ActionListener
{
String s1="";
GUI()
{
JTextField t1= new JTextField(20);
JButton j1= new JButton("submit");
j1.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
s1=t1.getText();
}
}
Please guide me, and if it is not appropriate question then please suggest me the article that you think I should read to get the concept.
Right now I'm at phone so I can't help you with code I will try to let you understand the concept: An user input, a button click is something which vould happen after 5 seconds like could happen after 30 minutes. So yes, you could let sleep the main for sometimes and hope for an input, wait until .s1 get a value and etc.
But, I don't see it like the right thing to do here. The best thing which could be used is a callback which is called when the user click the button. It's done using interfaces.
Well, first you declare an interface maybe named OnRequestClick where you implement onRequestClick(String message); method.
Message will be the text of s1.
Now in the GUI class create a new field of type OnRequestClick named listener and take it in your constructor.
Now where you create the GUI object the compiler ask to you to provide a code for OnRequestClick so do it and it willbe the code which will be executed when the user press tbe button.
Well, righr now what I said is false: it doesn't get fired since we didn't have done any call to listener.onRequestClick ()
So in your actionPerformed add listener.onRequestClick (s1.getText ()); so in your main you will get the ebemt and the text.
Replace GUI with a JOptionPane.showInputDialog(..) and not only will the code be a lot shorter, but the problem will be solved. E.G.
import javax.swing.*;
class UserInput {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
String name = JOptionPane.showInputDialog(null, "Name?");
if (name==null) {
System.out.println("Please input a name!");
} else {
System.out.println("Name: " + name);
}
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
You can use a Callback Mechanism.
I have already posted a sample code here JFrame in separate class, what about the ActionListener?. Please have a look.
interface Callback {
void execute(String value);
}
abstract class GUI extends JFrame implements ActionListener, Callback{
...
// do not provide the implementation of `execute` method here
...
public void actionPerformed(ActionEvent e) {
s1 = t1.getText();
// now callback method is called
execute(s1);
}
}
Your main class will look like:
public static void main(String args[]) {
gui = new GUI() {
#Override
public void execute(String value) {
System.out.println("Entered value:" + value);
}
};
}
Hi i got following problem...
I have main jframe started like this:
public static void main (String args[]){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Form3 myF=new Form3();
}
});
};
in the jframe i have Jpanels. On jpanel i want to start 2nd thread.
I tried it like this:
try {
while (DBAccess.haveResult("ASS"+harnessId)==null&&cancelCycle == 0) {
thread1.sleep(3*1000);
System.out.println("+++++++++");
System.out.println(DBAccess.haveResult("ASS"+harnessId));
res = DBAccess.haveResult("ASS"+harnessId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
but I am unable to stop that thread and cant even cancel it, because main window stops reacting
to clarify my problem:
i have "Test" button on JPanel, which is starting test process. Test process consists of loop whiuch is repeating every 3 seconds, this loop checks database status. Problem is I am unable to stop this loop until the status appears in db (while condition), because window is busy after i click on "test". Even implementing runnable and putting test method into "run()" doesnt worked.
testbutton source code:
if (e.getActionCommand().equals("Test")){
run();}
run method:
#Override
public final void run() {
test();
}
test method:
Map result_row = DBAccess.addRow("ASS"+harnessId,htOperList.get(seqNumber-1).getNametestprogram(),"",null);
if(result_row.containsKey("ADDROW")){System.out.println("Record inserted" );}
Database db = null;
Map res = null;
try {
while (DBAccess.haveResult("ASS"+harnessId)==null&&cancelCycle == 0) {
thread1.sleep(3*1000);
System.out.println(DBAccess.haveResult("ASS"+harnessId));
res = DBAccess.haveResult("ASS"+harnessId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
You are blocking the event dispatch thread. Use a SwingWorker for heavy tasks. Put the main DB operation in doInBackround(), and use publish() for the interim results.
If you need to stop it before doInBackround() completes, you can use cancel(). See here for notes about that.
I would like to ask some questions regarding the use of threads. I have looked at a lot of posts and links suggested from those posts but still came up blank.
I have a NetBeans project that has a few classes. One of them is the Gui class that I use to just click a button and some processing gets performed. From the Gui I call an instance of another class that in turn calls other classes. One of these classes submits a Sparql query to a TDB backend database. All output is saved to files for now.
What I would like to do is to somehow make the class called from the Gui to run on another thread and also to be able to update an EditorPane and a TextArea on the Gui from one or more of the called classes. Up to now I have tried calling an instance of the Gui class and use a public method within but this does not work. I am calling the instance Gui with
Gui gui = new Gui();
gui.setEditorPaneText("File name is: " + fn);
and the method in the Gui class is
public void setEditorPaneText(final String string) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setString(string);
EditorPane.setText(getString());
EditorPane.repaint();
}
});
}
I tried running the debugger but the processing skips from the first line of the method to the last curly bracket without processing the code within. My Gui class has the following as a main method. The commented part was a previous version of the event queue that I changed while I was reading through the numerous posts on the issue.
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Gui().setVisible(true);
throw new UnsupportedOperationException("Not supported yet.");
}
});
}
The following is the previous code of the main method that I replaced after reading some of the posts on this issue.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Gui().setVisible(true);
}
});
Any helpful information will be much appreciated. Thank you.
I think your main error is that you create two instances of your Gui class. You have the following snippet twice: new Gui(). Take a look at my example code below to see an example how to pass the Gui to your worker thread.
// This is handwritte-untested-uncompiled code to show you what I mean
public class Main {
public static void main(String[]args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Gui g = new Gui();
g.show(); // show() is equal to setVisible(true)
g.doBackendAction(); // Normally this would be invoked by a button or sthg. I was to lazy
}
});
}
}
public class Gui extends JFrame {
private JTextArea area;
public Gui() {
// Just some code to create the UI. Not sure if this actually does sthg right :P
area = new JTextArea();
setContentPane(area);
pack();
}
public void setTextAreaContent(final String string) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
area.setText(string);
this.repaint(); // Not 100% sure if we need this
}
});
}
public void doBackgroundWork() {
BackgroundWorker w = new BackgroundWorker(this);
new Thread(w).start(); // Start a worker thread
}
}
public class BackgroundWorker implements Runnable {
private Gui gui;
public BackgroundWorker(Gui gui) {
this.gui = gui; // we take the initial instance of Gui here as a parameter and store it for later
}
public void run() {
try { Thread.sleep(10 * 1000); } catch (InterruptedException e) {; }
this.gui.setTextAreaContent("Hello World!"); // calls back to the Gui to set the content
}
}