0

I work on a Java development software with Swing and I have a problem with my code, I want to display an image with the LoadingFrame class, its main work but when I call the constructor and the start() method in my main class, the frame opens but the image doesn't display (I have no Exception). Why it doesn't work with my main class?

public class LoadingFrame
{
    private  JFrame frame;

    public LoadingFrame()
    {
        frame = new JFrame();
        frame.setSize(800, 600);
        frame.setLocationRelativeTo(null);               
        frame.setUndecorated(true);

        frame.setContentPane(new Panneau());   
    }
    public void start()
    {
        frame.setVisible(true);
    }

    public void stop()
    {
        frame.setVisible(false);
    }

    public static void main(String[] args)
    {
        LoadingFrame l = new LoadingFrame();
        l.start();
        try
        {
            Thread.sleep(3000);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        l.stop();
    }
}

public class Panneau extends JPanel
{
    public void paintComponent(Graphics g)
    {
        System.out.println("hello");

        try 
        {
          Image img = ImageIO.read(new File("Images/loading.png"));
          //g.drawImage(img, 0, 0, this);
          //Pour une image de fond
          g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
        } 
        catch (IOException e) 
        {
          e.printStackTrace();
        }
    }
}

The App class is my main class :

public class App {
//Attributes used to display the application
    private JFrame frame;

//Attribute which display a waiting frame
    private static LoadingFrame loadingFrame;

/**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    loadingFrame = new LoadingFrame();
                    loadingFrame.start();

                    App window = new App();

                    loadingFrame.stop();

                    window.frame.setVisible(true);
                } 
                catch (Exception e) 
                {
                    e.printStackTrace();
                }
            }
        });
    }

/**
     * Create the application.
     */
    public App() 
    {
        initialize();
        synchronizeScriptReferenceList();
        synchronizeTests();
    }
[...]
}
  • Why do you call `loadingFrame.stop()` almost immediately after calling `loadingFrame.start()`? On top of this, `App window = new App();` will do almost nothing relevant. The `loadingFrame` is static, and run in a static context, so you don't need an `App` object for this example. – Clark Kent May 18 '16 at 12:55
  • Also, you never call `.pack()` on the frame, or something similar – Jerfov2 May 18 '16 at 12:58
  • Hello, it's normal, the constructor App called after start() is long to execute (maybe 2 minutes, it's a synchronize process with many files) – Damien Ramat May 18 '16 at 12:58
  • 1
    1) See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/q/9554636/418556) 2) That paint method is wrong. It thould not be loading images, and should immediately call the super method. – Andrew Thompson May 18 '16 at 12:59
  • 1
    Also, you open an Image everytime you want to draw. That __KILLS__ performance – Jerfov2 May 18 '16 at 12:59
  • Yes, i forgot .pack() but when I add this line, I have the same result – Damien Ramat May 18 '16 at 13:00
  • @DamienRamat Where did you put it? – Jerfov2 May 18 '16 at 13:01
  • I put it, in my start() method, just before setVisible(true). – Damien Ramat May 18 '16 at 13:02
  • @DamienRamat As the very first line in `paintComponent`, call `super.paintComponent`, I think I remeber that being very important – Jerfov2 May 18 '16 at 13:04
  • Also on the `g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);` line, try changing `this` to `null` – Jerfov2 May 18 '16 at 13:06
  • I try to add `super.paintComponent` at the first line in paintComponent, but it dosn't work. It's the same when I change `this` to `null` – Damien Ramat May 18 '16 at 13:11
  • In fact, when I added `.pack()` in the `start()` method, the main of LoadingFrame doesn't display the image, like when I call `start()` in the App class. – Damien Ramat May 18 '16 at 13:14
  • @DamienRamat does the LoadingFrame `main` work? – Jerfov2 May 18 '16 at 13:25
  • 1
    @TheTromboneWilly Actually `this` is correct. Passing `null` is incorrect and should never be done. – VGR May 18 '16 at 13:26
  • When I delete `frame.pack()` yes! – Damien Ramat May 18 '16 at 13:26
  • The print message "Hello" is displayed. So, We passed in the `paintComponent(Graphics g)`method; – Damien Ramat May 18 '16 at 13:28

1 Answers1

2

I was able to get this to work from App.java. For some reason, using EventQueue isn't cutting it. I tried to use SwingUtilities as well, but that doesn't work either. Finally I tried just get rid of the Thready-stuff in App.main at just straight up running it in the main thread. For some reason, this works when the other approaches do not! Here is my code:

// In the App class: 

public static void main(String[] args) {
    try {
        loadingFrame = new LoadingFrame();
        loadingFrame.start();

        App window = new App();

        loadingFrame.stop();

        window.frame.setVisible(true);
    } 
    catch (Exception e) 
    {
        e.printStackTrace();
    }
}

When I used this code, I got it to work! (for some reason unknown to me), And here's a bonus rewrite of the Panneau class:

class Panneau extends JPanel
{
    Image img;

    public Panneau() {
        try
        {
            img = ImageIO.read(new File("Images/loading.png"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
    }
}

There are two main difference with this class; problems which I addressed. Here they are:

  1. I call super.paintComponent as the very first method in our own paintComponent
  2. I only load the loading image once, in the constructor, and not every single time I want to draw, which moves everything along much smoother. (you don't want the loading screen to be CPU heavy, do you?)

Hopefully, with these improvements, I hope you can make your program work! It worked with me, so I wish the best of luck to you.

P.S. Don't call frame.pack(), that was a mistake on my part. For some reason, I think it doesn't work well with undecorated windows.

Jerfov2
  • 5,264
  • 5
  • 30
  • 52
  • Thanks for your response, yes it's work with the `main` of `LoadingFrame.java` but it doesn't work with the App class, and that is my problem. – Damien Ramat May 18 '16 at 13:42
  • Thanks a lot, it's work, I don't understand why it's work when we delete `EventQueue.invokeLater(new Runnable(){ public void run() {` but it's cool :D – Damien Ramat May 18 '16 at 14:30
  • @DamienRamat Same here, dude, I'll maybe research later why this happens. It's a complete mystery to me! – Jerfov2 May 18 '16 at 14:56
  • Ok, ahh Java and its mysteries... ^^ – Damien Ramat May 18 '16 at 14:58
  • `g.drawImage(img, 0, 0, getWidth(), getHeight(), null);` as mentioned by @VGR, this **should be** `g.drawImage(img, 0, 0, getWidth(), getHeight(), this);`. In future, please try reading the JavaDocs for these methods and understanding them. It seems the advice you are giving is a loose collection of 'tips' picked up around the internet. Some of the things people commonly say are useful, others are things people ***commonly** get wrong.* – Andrew Thompson May 18 '16 at 16:57
  • @AndrewThompson http://s32.postimg.org/6rsjowtol/Screen_Shot_2016_05_18_at_3_50_15_PM.png look at the bottom – Jerfov2 May 18 '16 at 20:51
  • @TheTromboneWilly Look at the JavaDocs, like I instructed earlier. Tutorial code often takes 'shortcuts'.. – Andrew Thompson May 19 '16 at 00:14
  • @AndrewThompson I understand that `ImageObserver` can be useful in many cases, but here it just isn't necessary for a static loading screen... – Jerfov2 May 19 '16 at 02:22
  • *"but here it just isn't necessary"* And when the programmer expands the class to accept an image in the constructor, and the user passes an image that loads asynchronously, it will fail. Given it is robust using the `ImageObserver`, why code it ***any* other way?** – Andrew Thompson May 19 '16 at 02:25
  • @AndrewThompson I did a little more researching and I figured out more about `ImageObserver`s. I edited my answer, and I think you have converted me to actually using these things! (at least with `Component`s) – Jerfov2 May 19 '16 at 02:36
  • *"(at least with Components)"* Yep. That's what I'm talkin' about. They have all the makings to use asynchronously loaded images, built in. :) – Andrew Thompson May 19 '16 at 02:42