0

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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Phayden
  • 21
  • 1
  • 6
  • Have you debugged it? Where have you set breakpoints? What were values at those breakpoints? Or may be you expect that smb. will debug it for you? – mentallurg Sep 01 '19 at 17:27
  • After every like I output something to the console, and everything seems to work fine. i'll do it again to see if I missed anything but it seems to work perfectly – Phayden Sep 01 '19 at 17:28
  • 1
    Do the calculations in background using Swing worker otherwise your UI will freeze. – Yoshikage Kira Sep 01 '19 at 17:30
  • 1
    You should post a [mcve]. We do not know what items are in your gui, how your fields are defined, whether they are static, volatile, etc., or what `loadingBarLoaded` really does. In an unrelated note, you are violating the coding conventions. Class and Interface names should always start with an uppercase letter, and variable names should not. – RealSkeptic Sep 01 '19 at 17:31
  • I added a minimal reproducible example, and how all the vars are declared and a screen shot of the layout – Phayden Sep 01 '19 at 17:47
  • Writing your code according to the [java coding standards](https://www.oracle.com/technetwork/java/codeconventions-150003.pdf) makes it easier for others to read and understand your code and consequently to help you with your problem. – Abra Sep 01 '19 at 17:53
  • 2
    I think you didn't understand the concept of [mcve]. Basically, it's something we can copy and paste to our IDE, run it, and get the same results that you get. We can then better understand the way it works. This means the definition of the frame, adding the elements to it, displaying it, the classes in full - but without items that are irrelevant like what your Xtra actually does. This may be much to ask from someone who has only been doing Java for a week, but there is no way to do anything but guess at the moment. – RealSkeptic Sep 01 '19 at 17:54
  • _Sorry if I am not following the unwritten coding rules, I only started with java like a week ago._ Makes me wonder how you are learning java, because **all** the tutorials and books that I am familiar with use the java coding standards. – Abra Sep 01 '19 at 17:58
  • I downloaded a IDE that ran java and I started typing, googled "How to output 'hello world' in java" and just went from there – Phayden Sep 01 '19 at 20:48

2 Answers2

1

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.

keuleJ
  • 3,418
  • 4
  • 30
  • 51
0

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.

Phayden
  • 21
  • 1
  • 6