[java] Java2D With An Application?

Started by
17 comments, last by Gallivan 15 years, 3 months ago
Does that code run for you?

I'm not sure what example you are working from, but here are a few things i would change. I have not made too many changes in the actual design of your class.

Primarily you need to declare the main method static:

public static void main(String[] args)


If this method is not static, you can't access it unless the class is instanciated. Since this method creates the Display class instance, its kind of a chicken and egg thing.

Secondly, as it looks now, you should create your Display object as a variable of the type Display. Then call the two methods in that object.

Display dis = new Display();        dis.createGUI();        dis.showUnit(0,0);


Since the createGUI method is empty, maybe you should remove it to make the code more clear.

In your showUnit method, you create a JFrame. If you think about it, you might see that the Display class already extends JFrame and thus is a JFrame. If you move the "JFrame name" from this call, to the call from main, you will still get a JFrame called "TopLevelDemo". To make this work, you will also need a constructor for the Display class.

public class Display extends JFrame {        public Display(String string) {			}	public static void main(String[] args) {    	    	Display dis = new Display("TopLevelDemo");        dis.createGUI();        dis.showUnit(0,0);            }


A final change to the code is the removal of a few things in the last three calls. You can add the JLabel directly to the Display JFrame. The same goes for pack and setVisible. Java "knows" that Display is a JFrame and will associate the calls with this JFrame.

private void showUnit(int x, int y) {        ImageIcon unitImage = createImageIcon("images/middle.gif");        JLabel unitLabel = new JLabel(unitImage);        unitLabel.setOpaque(true);        unitLabel.setBackground(new Color(248, 213, 131));        unitLabel.setPreferredSize(new Dimension(16, 16));        unitLabel.setBounds(x, y, unitImage.getIconWidth(), unitImage.getIconHeight());               add(unitLabel);        pack();        setVisible(true);    }


To make things a bit clear (in particular with complex classes), I would add this to those 3 calls, to indicate that they are related to this object (the Display JFrame).

this.add(unitLabel);        this.pack();        this.setVisible(true);



To reposition your JLabel, I suggest you use a LayoutManager. These are added to the (in this case) JFrame. Component are added differently that when drawing an image. If you were drawing the image directly to the JFrame, you could use the position as a parameter in the call.

g.drawImage(img, 100, 100, this);


Since you are using the image as a JLabel, you can devide the JFrame into different areas with a layoutmanager. To see the difference I have given your JFrame a size.

this.setPreferredSize(new Dimension(175, 100));        this.add(unitLabel, BorderLayout.NORTH);


Maybe you could give a description of what you expect the application to do, when you are surpriced the image is in the center of the frame.

[Edited by - MONDARIZ on December 30, 2008 5:23:18 AM]
Advertisement
I just realised that your "remains in the center" problem might be caused by the pack() call.

When the JFrame contains only one component, it will be packed around this component and the component will remain centered no matter where you place it.

Try to comment out the setPreferredSize line and use this:

this.setSize(200, 300);


You will find that the JFrame is unaltered, with the component in the center.

If you now comment out the pack() call, you will see that the JFrame is created with the dimensions from setSize.

[Edited by - MONDARIZ on December 30, 2008 5:38:56 AM]
To load and display an image, try using this code:

import java.awt.*;import java.awt.event.*;import java.awt.image.*;import java.io.*;import javax.imageio.*;import javax.swing.*;public class Viewer extends JPanel {              BufferedImage img;    public void paint(Graphics g) {        g.drawImage(img, 50, 50, null);    }    public Viewer() {       try {           img = ImageIO.read(new File("middle.jpg"));       } catch (IOException e) {       }    }    public Dimension getPreferredSize() {        if (img == null) {             return new Dimension(100,100);        } else {           return new Dimension(img.getWidth(null), img.getHeight(null));       }    }    public static void main(String[] args) {        JFrame f = new JFrame("Load Image Sample");                    f.addWindowListener(new WindowAdapter(){                public void windowClosing(WindowEvent e) {                    System.exit(0);                }            });        f.add(new Viewer());        f.setSize(200, 300);        f.setVisible(true);    }}


The image should be located in the application folder. By changing the int values in the drawImage call, you can change the location of the image on the panel.

You might see that the Viewer is a JPanel, which is added to the JFrame. Then the image is drawn on the JPanel. I think this is better than using the JFrame on its own.
Thanks for being incredibly helpful.

My main class was not static because at first I had an instance variable that was the JFrame which I later moved into a method.

I wasn't aware that you could draw an image to a component like that. What I was trying to do is get a basic image on the screen which could be moved by input (the arrow keys).

So my plan was to:

- get the input
- affect the image (xLoc, yLoc)
- draw the background
- draw the image

And repeat that until the program closed.

I understand most of the Viewer class you provided. Is paint always called after main()?

Could I make another method called 'public void drawBackground(Graphics g)' that the main method could call?

Again, thanks for the time you've put into this.
In this case paint() is about drawing the image on the JPanel, so it must naturally be after the JPanel has been created from main (and the image loaded by ImageIO()):

 f.add(new Viewer());


Your paint method should paint everything on the JPanel.

sort of like this:

 public void paint(Graphics g) {        g.drawImage(img, 50, 50, null);        g.drawImage(img, 100, 100, null);    }


This is the more primitive way of doing things, but it will work. The images are drawn in turn, so image 2 will be on top of image 1. Remember you can set an image to have transparency so the "unused" area wont be drawn.

if you need to move things around, its best to use sprites.
It might be helpful to know, that when you create an instance of JPanel (as with class Viewer extends JPanel), there is automatically a call to paint() when it is displayed on screen (otherwise you wouldn't see it at all).

Whats happening in the Viewer class, is that we override the default paint() and make it draw the images.

Strangely the drawImage method does not actually draw the image, but facilitate the loading of the image. An imageObserver is attached (in this case the parent component), which draw the image.

So the fourth parameter in imageDraw() should actually be this

g.drawImage(img, 50, 50, this);


However, the ImageIO read() might work as an ImageObserver (since we can use null in the example), I'm not sure.
Thanks, I wasn't aware that paint was called upon instantiation. I'll probably read through more of the methods in the Graphics class so I don't always have to look them up.
How would I create a method for a class which draws, but isn't auto-called like paint?

For example:

public class StickFigure {    drawStickFigure(Graphics g) {        g.drawImage(...etc);    }}


Then I would:

StickFigure mitch = new StickFigure();mitch.drawStickFigure();


But my problem is when I do mitch.drawStickFigure() it requires a graphical parameter. But I can't send Graphics g, because it's abstract...

I hope that was clear enough.
Figured it out, just going to use repaint().

This topic is closed to new replies.

Advertisement