1

In addition to my question How can I more quickly render my array?, I made the following class to make a JFrame:

package myprojects;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

class BackgroundImageJFrame extends JFrame {
    public BackgroundImageJFrame(BufferedImage img) {
        setTitle("Background Color for JFrame");
        int h = img.getHeight();
        int w = img.getWidth();
        setSize(w, h);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);

        setLayout(new BorderLayout());
        setContentPane(new JLabel(new ImageIcon(img)));
        setLayout(new FlowLayout());
        // Just for refresh :) Not optional!
        setSize(w-1, h-1);
        setSize(w, h);
    }
}

which I call with new BackgroundImageJFrame(img);. As I want to refresh the contents of this JFrame, this doesn't work optimally, since this creates a new JFrame everytime.

How could I alter this to just have the JFrame refreshed?

Community
  • 1
  • 1
konewka
  • 620
  • 8
  • 21
  • 1
    Hey, I edited the answer, I want to make sure you see it. MadProgrammer made some good points in the comments. – durron597 Aug 28 '15 at 01:16

1 Answers1

2

You can pretty simply do this by storing the JLabel control, and then setting the image with a method. Make sure you set the image on the Event Dispatch Thread!

I have revised the code to do this in a more stable way based on @MadProgrammer's excellent comments.

Brief summary of the issues addressed between this and the previous version:

  1. You don't want the contentPane to be a JLabel, as it makes it more difficult to add other controls later and doesn't have a layout manager. I've added a JPanel in between, and given it BorderLayout.
  2. The caller should be responsible for thread safety. I didn't do it this way originally because you didn't provide any calling code, but here, I do the Event Dispatch Thread delegation. Make sure you switch to the Event Dispatch Thread using EventQueue.invokeLater as I do here in main before calling setBackgroundImage().
  3. I'm using setSize and setPreferredSize on the JLabel so that the layout managers can properly choose good sizes for the controls, and so that frame.pack works as expected.
  4. I create the controls in the initComponents method, outside of the constructor, to make the code easier to follow and to make it easy to add more constructors later if necessary.

Here's the code:

public class NonogramSolutionJFrame extends JFrame {
  private final JLabel label;
  private final JPanel panel;

  public NonogramSolutionJFrame(BufferedImage img) {
    panel = new JPanel();
    label = new JLabel();
    initComponents(img);
  }

  private final void initComponents(BufferedImage img) {
    setTitle("Background Color for JFrame");
    setBackgroundImage(img);
    setContentPane(panel);
    panel.setLayout(new BorderLayout());
    panel.add(label, BorderLayout.CENTER);
    setLocationRelativeTo(null);
    pack();
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public void setBackgroundImage(final BufferedImage img) {
    label.setIcon(new ImageIcon(img));
    label.setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
  }

  public static void main(String... args) throws Exception {
    BufferedImage img = ImageIO.read(NonogramSolutionJFrame.class.getResource("/nonogram.png"));
    NonogramSolutionJFrame frame = new NonogramSolutionJFrame(img);
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        frame.setVisible(true);
      }
    });
  }
}

Using the image from your other answer, this code produces the following (on Linux):

Nonogram in a JFrame

Community
  • 1
  • 1
durron597
  • 31,968
  • 17
  • 99
  • 158
  • 1
    Just beware that using a `JLabel` as a "background" image has two major issues, 1- There's no layout manager by default, so you'll need to set that and 2- The `JLabel` won't take into consideration it's content when determining the preferred size of the label, which can cause issues. IMHO - It's not the responsibility of the `BackgroundImageJFrame` to ensure thread safety, but the caller, otherwise you're just adding possible inefficiencies into your system (and possible race conditions) that may see one updates occur in a order you weren't designing for - but that's me ;) – MadProgrammer Aug 27 '15 at 23:57
  • I have no issue with you not modifying the OPs code, but they should be made aware of any short comings that their approach might have so that they don't fall deeper into problems, just saying ;) – MadProgrammer Aug 28 '15 at 00:02