0

I am creating a GUI, and am fairly new to swing and awt. I am trying to create a gui that, upon launch, sets the background to an image, then uses a method to create a slideshow of sorts. I have attempted it, and I am not attached to the code so I am able to take both revisions and/or whole new concepts.

EDIT(9/15/13): I am having trouble with the slideshow, I cant seem to get it to work.

Here is my current code.

public class MainFrame extends JFrame{

JLabel backgroundL = null;
private JLabel bakckgroundL;
BufferedImage backimg;
Boolean busy;
double width;
double height;

public MainFrame() throws IOException {
    initMainframe();
}



public void initMainframe() throws IOException { 

//misc setup code, loads a default jpg as background

    setTitle("Pemin's Aura");
    busy = true;
    String backgroundDir = "resources/frame/background.jpg";

    backimg = ImageIO.read(new File(backgroundDir));
    backgroundL = new JLabel(new ImageIcon(backimg));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    refreshframe();
    setVisible(true);
    busy = false;
}
public void adjSize() { // the attempted start of a fullscreen mode
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
    width = this.getWidth();
    height = this.getHeight();
    setVisible(true);
}

public void setmastheadText() {//unfinished code
busy = true;

busy = false;
}
public void setbackground() {
    add(backgroundL);
}
public void refreshframe() { //should refresh image?
    setSize(2049, 2049);
    setSize(2048, 2048);
}
public void loadingscreen() throws IOException, InterruptedException {

 //this is the code in question that is faulty.

    if (busy == false) {
    busy = true;

    String backgroundDir1 = "resources/frame/background.jpg";
    String backgroundDir2 = "resources/frame/scr1.jpg";
    String backgroundDir3 = "resources/frame/scr2.jpg";

    BufferedImage backimg1 = ImageIO.read(new File(backgroundDir1));
    BufferedImage backimg2 = ImageIO.read(new File(backgroundDir2));
    BufferedImage backimg3 = ImageIO.read(new File(backgroundDir3));

    backgroundL = new JLabel(new ImageIcon(backimg1));
    Thread.sleep(2000);
    setbackground();
    setVisible(true);
    backgroundL = new JLabel(new ImageIcon(backimg2));
    setbackground();
    setVisible(true);
    Thread.sleep(2000);
    bakckgroundL = new JLabel(new ImageIcon(backimg3));
    setbackground();
    setVisible(true);

    if(backimg != null) {
         backgroundL = new JLabel(new ImageIcon(backimg));;
        }
    }
    busy = false;
}//end of loading screen
CCD
  • 470
  • 1
  • 7
  • 19
  • 1
    where do you have a problem with? Or you want a code review? – nachokk Sep 16 '13 at 02:14
  • Ill clear that up in my question, thanks for alerting me. I would like a code review, but my issue is that I can't seem to get the "slideshow" to work. – CCD Sep 16 '13 at 02:17
  • Follow standard Java naming conventions. Words in method names should be capitalized after the first word. (ie. all you need to do is learn by the method names found in the JDK). The refreshFrame() method is a terrible piece of code. There is no reason to invoke the same method twice with two different values. In fact the normal way to create a frame is to use the pack() method and let each component be displayed at its own size. – camickr Sep 16 '13 at 02:46
  • The best way to better oneself is to recieve a true and blunt piece of advice. @camickr, thanks for that. I realize that pack() is the most common way, and I am familiar with what it does. However, if I want to have blank space, with nothing but the background, I would not use pack(). When I tried it before, it was useless, as the frame became the smallest it could possibly be even though there was a JLable, so if you wish to help me with that, please do so, it would be a great help – CCD Sep 16 '13 at 02:59
  • `the frame became the smallest it could possibly be even though there was a JLable` - Did you read the JLabel API and follow the link to the Swing tutorial on `How to Use Labels`? It has a working example on how to better structure your program and it shows labels with images and the code uses pack() and the frame is the proper size. I can't guess what you might be doing wrong. That is why you should start with a working example and modify it. – camickr Sep 16 '13 at 03:06
  • alright, I realize now that my code is still immature and really must be quite a sore to more experienced coders' eyes, so I will from now on work of existing examples. Thanks – CCD Sep 16 '13 at 03:15

2 Answers2

6

See ImageViewer for a working example of displaying images using a Swing based Timer.

See also How to use Swing Timers.


And while I'm here, another (prettier) example of animating an image. It uses this Mercator map of land masses. The image can be tiled horizontally, and therefore be scrolled left/right as needed.

Mercator Map of Land Masses

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

import java.net.URL;
import javax.imageio.ImageIO;

public class WorldView {

    public static void main(String[] args) throws Exception {
        URL url = new URL("https://i.stack.imgur.com/P59NF.png");
        final BufferedImage bi = ImageIO.read(url);
        Runnable r = new Runnable() {

            @Override
            public void run() {
                int width = 640;
                int height = 316;
                Graphics2D g = bi.createGraphics();

                float[] floats = new float[]{0f, .4f, .55f, 1f};
                Color[] colors = new Color[]{
                    new Color(20, 20, 20, 0),
                    new Color(0, 10, 20, 41),
                    new Color(0, 10, 20, 207),
                    new Color(0, 10, 20, 230),};
                final LinearGradientPaint gp2 = new LinearGradientPaint(
                        new Point2D.Double(320f, 0f),
                        new Point2D.Double(0f, 0f),
                        floats,
                        colors,
                        MultipleGradientPaint.CycleMethod.REFLECT);

                final BufferedImage canvas = new BufferedImage(
                        bi.getWidth(), bi.getHeight() + 60,
                        BufferedImage.TYPE_INT_RGB);

                final JLabel animationLabel = new JLabel(new ImageIcon(canvas));
                ActionListener animator = new ActionListener() {

                    int x = 0;
                    int y = 30;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Graphics2D g = canvas.createGraphics();
                        g.setColor(new Color(55, 75, 125));

                        g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

                        int offset = (x % bi.getWidth());
                        g.drawImage(bi, offset, y, null);
                        g.drawImage(bi, offset - bi.getWidth(), y, null);

                        g.setPaint(gp2);
                        g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

                        g.dispose();

                        animationLabel.repaint();

                        x++;
                    }
                };
                Timer timer = new Timer(40, animator);
                timer.start();
                JOptionPane.showMessageDialog(null, animationLabel);
                timer.stop();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

Here is a version of that image with the equator added (it is 44 pixels 'south' of the center of the image).

enter image description here

Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • You're welcome. I added another (cuter, but more complicated) example. ..Mostly because I am building up a set of images that example code can hot-link to (just like the code above does), and that image will become one of them. ;) – Andrew Thompson Sep 16 '13 at 14:39
5

You're calling Thread.sleep(...) and likely on the EDT or Swing event thread (full name is the Event Dispatch Thread). This thread is responsible for all Swing painting/drawing and user interactions, and so sleeping it will only serve to freeze your entire GUI. Instead you should use a Swing Timer to allow you to swap a JLabel's ImageIcon.

So, briefly:

  • Don't call Thread.sleep(...) on the Swing event thread (Event Dispatch Thread or EDT).
  • Do use a Swing Timer to do your repeating delayed actions.
  • Don't make and add many JLabels. Just make and add one.
  • Do Swap the ImageIcon that the JLabel displays by calling setIcon(...) on the label.
  • Better (cleaner) to write if (busy == false) { as if (!busy) {

e.g.,

ImageIcon[] icons = {...}; // filled up with your ImageIcons

if (!busy) {
  int timerDelay = 2000;
  new Timer(timerDelay, new ActionListener() {
    private int i = 0;
    public void actionPerfomed(ActionEvent e) {
      myLabel.setIcon(icons(i));
      i++;
      if (i == icons.length) {
        ((Timer)e.getSource).stop();
      } 
    };
  }).start();
}
kiheru
  • 6,588
  • 25
  • 31
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Since I am unfamiliar with the majority of what you wrote, may I ask what the .start() method does? Also, what purpose do ActionListener and actionPerformed have respectively in this code? PS: Thanks for the tips – CCD Sep 16 '13 at 02:46
  • 2
    Read the Swing tutorial on [How to Use Timers](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) for the basics. The tutorial also has a section on `Concurrency` which you should read about (it explains more about the EDT). And you should be downloading examples from the tutorial to improve your program structure (ie GUI code should execute on the EDT). You should not be extending JFrame. – camickr Sep 16 '13 at 02:49
  • @Hovercraft Full Of Eels When I try to write your code, I revieve an error on `new Swing(timerDelay` that Swing 'cannot be resolved to a type' . Do you know what to make of this? – CCD Sep 16 '13 at 03:20
  • 1
    @Aaron he may want to say `new javax.swing.Timer(..)` or if you import it just `new Timer(..)` – nachokk Sep 16 '13 at 03:28
  • @Aaron: don't copy my code (for one, I didn't test it but instead just typed it on the fly), but use it's ideas. And yes, you must import any but the most basic classes that you use. – Hovercraft Full Of Eels Sep 16 '13 at 10:50
  • I imported what was suggested to me by my IDE (yes I have that concept down) But alright, point taken – CCD Sep 16 '13 at 14:19