Sign in to follow this  

[java] Java2D With An Application?

This topic is 3300 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm very confused regarding drawing simple 2D shapes with a JAVA application. In school we learned how to draw with an Applet, but now I am looking to draw with an application. Will I be using paint(Graphics g) or Swing? I've read http://java.sun.com/docs/books/tutorial/2d/overview/index.html and http://java.sun.com/docs/books/tutorial/2d/index.html but I get confused when I see the import JApplet and various commands. Are there any tutorials out there for applications?

Share this post


Link to post
Share on other sites
I just had a quick browse through the tutorials and couldn't identify the part you mentioned.

Could you specify which part of the tutorials that is confusing you (maybe cut and paste the paragraph)?

Depending on what you are trying to do, its possible to use paint(g) to draw in your swing component.

(pseudo code)

class Swingwindow extends JFrame

public void paint(graphics g){

super.paint(g);
g.drawLine(0,0,50,50);
}

Java will display swing components without a draw/paint call, but if you need anything else it must be drawn or painted.

Share this post


Link to post
Share on other sites
That actually was all I needed. I guess I was just under the assumption that 'paint' was for Applets only. Here's what I ended up with, thanks to your pseudo code:


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

public class Swingwindow extends JFrame {

public static void main(String[] args) {
JFrame f = new JFrame("Weather Wizard");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}

public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paint(g2);
g2.drawLine(0,0,50,50);
}
}

Share this post


Link to post
Share on other sites
I'm glad to hear you found your way...

Paint is a method from Component (or maybe its Container), so any class under that will have access to the paint method through inheritance. This includes JApplet, which is a sub-class of Component/Container.

Its a good idea to find some meaning in draw/paint/repaint/drawimage/paintcomponent/update and so on.

Here are a few links:

http://leepoint.net/notes-java/GUI-lowlevel/graphics/15who-calls-paintcomponent.html

http://java.sun.com/products/jfc/tsc/articles/painting/index.html

Share this post


Link to post
Share on other sites
Quote:
Original post by Gallivan
That actually was all I needed. I guess I was just under the assumption that 'paint' was for Applets only.
If you want to do your own painting in Swing it's preferable not to override paint but instead to override paintComponent, for more information see the links above in MONDARIZ's post.

Share this post


Link to post
Share on other sites
I'm having trouble adding a JLabel to a direct position on-screen.

The documentation reads:

add(javax.swing.JLabel jLab, int x, int y, int dx, int dy)
Adds a JLabel at position x;y on the window and with a width/height of dx/dy.


But my code of:

frame.getContentPane().add(unitLabel, x, y, 16, 16);


Gives me an error of:

cannot find symbol - method add(javax.swing.JLabel,int,int,int,int)

This was my reference:

http://ltiwww.epfl.ch/sJava/version2/javadocDir/epfl/lti/Utilities/AFrame.html

Share this post


Link to post
Share on other sites
I've tried this:

unitLabel.setBounds(x, y, unitImage.getIconWidth(), unitImage.getIconHeight());

It compiles, but the image icon remains centered in my frame.

Share this post


Link to post
Share on other sites
I think its because you add to the toplevel container (directly to the JFrame).
JFrame inherits the add() from Container and that add() does not accept the parameter (unitLabel, x, y, 16, 16).

It accepts these:

add(Component comp)
add(Component comp, int index)
add(Component comp, Object constraints)
add(Component comp, Object constraints, int index)
add(String name, Component comp)


You should look at the LayoutManagers, maybe the GridBagLayout can help you.

You can also post your entire code, then it might be easier to explain whats happening.

Share this post


Link to post
Share on other sites

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

public class Display extends JFrame {

public void main(String[] args) {
createGUI();
showUnit(0,0);
showUnit(0,0);
}

protected ImageIcon createImageIcon(String path) {
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}

private void createGUI() {

}

private void showUnit(int x, int y) {
JFrame frame = new JFrame("TopLevelDemo");
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());
frame.getContentPane().add(unitLabel);
frame.pack();
frame.setVisible(true);
}
}

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

This topic is 3300 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this