I have a quick question about Java. I'm sorry if this question is really basic, but I'm a beginner Java programmer :D
I want to render a 2d image in a window, but I can't figure it out. I've looked at the graphics API here:
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Graphics.html
and the only method I could find that might work is drawImage().
It wasn't working for me, though, but maybe it has to do with the ImageObserver Observer parameter? I just put null for that following some tutorial I found somewhere, but I still get a compile error:
Here is my paint method:
public void paint(Graphics g)
{
Image img1 = Toolkit.getDefaultToolkit().getImage("theImage.png");
g.drawImage(img1, 100, 100, null);
} // public void paint(Graphics g)
and here are the methods that call it:
public static void main(String[] args)
{
MyGame game = new MyGame();
game.setVisible(true);
game.play();
} // public static void main(String[] args)
/** The play method is where the main game loop resides.
*/
public void play()
{
boolean playing = true;
//Graphics g = new Graphics();
while (playing)
{
paint();
}
} // public void play()
The thing is when I call paint in the while loop, I get this error:
paints(java.awt.Graphics) in MyGame cannot be applied to ()
What does that mean? How can I fix it so I can successfully render a 2d image?
Thanks in advance :D
Instead of paint(); use repaint();
You should be overriding paintComponent(Graphics g). Also, as #TotalFrickinRockstarFromMars suggested, you should be invoking repaint().
You overrid the paintComponent(Graphics g)
class Game extends JComponent { // Your game class
Image img = null;
public Game() {
img = getImage("/theImage.png");
}
private Image getImage(String imageUrl) {
try {
return ImageIO.read(getClass().getResource(imageUrl));
} catch (IOException exp) {}
return null;
}
paintComponent(Graphics g) {
g.drawImage(img, 100, 100, null);
}
}
Related
I have a function that is drawing an image and then saving it immediately after but the problem is that it seems to be drawing it twice, once for the view on the screen and then once to save it to the disk
public class myFrame {
public static void main(String[] args) {
JFrame lv_frame = new JFrame();
// setup jframe here
lv_frame.add(new image());
lv_frame.setVisible(true);
}
}
class image extends JPanel {
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
draw(graphic);
save();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.fillArc(0, 0, 250, 250, 0, 90);
}
public void save() {
BufferedImage image = new BufferedImage(250, 250, BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D graphic2D = image.createGraphics();
try {
File output = new File("file.png");
// is it possible to use the graphic I've already
// drawn here instead of re-drawing?
draw(graphic2D);
ImageIO.write(image, "png", output);
} catch(IOException log) {
System.out.println(log);
}
}
}
I have a function draw which creates the image on the gui screen and another function save which saves it to the disk but the save function is calling draw as well.
Is it possible to save the image that has already been drawn without re-calling the draw function as it is being done in my code?
I was answering your question on Display to GUI and Save to Disk with a Single Object/Variable, however it was closed probably due to the similar nature of your question.
I think there are several issues which you seemed confused with and I would like to write my solution here which also addresses your question in your duplicated post.
Is it possible to save the image that has already been drawn without re-calling the draw function as it is being done in my code?
Don't be confused between drawing an image on the Panel and saving it. The following shows a working example on saving a drawn image.
class DrawingSpace extends JPanel
{
private BufferedImage buf;
public DrawingSpace(){
setPreferredSize(new Dimension(200, 200));
buf = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
drawOnBuffer();
}
public void drawOnBuffer(){
Graphics g = buf.createGraphics();
g.setColor(Color.BLUE);
g.fillOval(0,0,200,200);
g.setColor(Color.RED);
g.fillOval(50,50,100,100);
g.dispose();
}
public void saveBufferAsImage(String pathname){
String fmt = "";
if(!(pathname == null || pathname.equals(""))){
fmt = pathname.substring(pathname.lastIndexOf(".")+1);
File outputfile = new File(pathname);
try{
ImageIO.write(buf, fmt, outputfile);
}catch(IOException ioe){System.out.println("Unable to save file");}
}
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(buf, 0, 0, 200, 200, null); //Only for user to see
}
}
To save an image, you not necessarily have to draw and display it in the JPanel first. Note that I created a BufferedImage called buf and I am drawing on buf. Once I have drawn onto a BufferedImage, I can simply save that image as a file (I don't have to draw it to the panel first).
Notice that I did the following:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(buf, 0, 0, 200, 200, null); //Only for user to see
}
g.drawImage(buf, 0, 0, 200, 200, null) will draw whatever on buf onto the JPanel. It can be deleted and the saving will still work. When I draw it on the panel, it is only for the user to see the outcome of the drawing.
To test the program:
class SaveImageRunner{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
JFrame frame = new JFrame("Saving a buffered image");
DrawingSpace ds = new DrawingSpace();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(ds);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
ds.saveBufferAsImage("BlueCircle.png");
}
});
}
}
Saved Image:
Some pointers on drawing:
paintComponent(Graphics) shall only contain codes for drawing and nothing else. Do not implement your codes for saving the image to a file inside here.
Try not to create a new BufferedImage in the paintComponent(Graphics). If not, a new instance of a BufferedImage will be created on every repaint.
Change the place where you create the graphics2D object and reuse it.
Try this out.
public class myFrame {
public static void main(String[] args) {
JFrame lv_frame = new JFrame();
// setup jframe here
lv_frame.add(new image());
lv_frame.setVisible(true);
}
}
class image extends JPanel {
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
// Image and graphics are now created here
BufferedImage image = new BufferedImage(250, 250, BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D graphic2D = image.createGraphics();
draw(graphic2D);
save(image);
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.fillArc(0, 0, 250, 250, 0, 90);
}
public void save(BufferedImage image) {
try {
File output = new File("file.png");
ImageIO.write(image, "png", output);
} catch(IOException log) {
System.out.println(log);
}
}
}
EDIT
I have found the answer in another post. It is not a bad idea to make the drawing twice. What you are doing is, like #Hovercraft says in this post, separating the screen drawing from the writing to files so that you don't see your graphics drawing performance hurt.
I have tried to make the drawing only once but you have no easy method to store the drawing Graphics object. Probably, it is implemented to prevent this. If you see the way the method works, you are given the Graphics object with the only purpose to draw on it. Using it in other ways could impact the performance.
I am creating a lightweight client for the game Runescape that has various user features such as custom keybinds/hotkeys. I'm pretty good with java and swing, but AWT and applets I am mediocre at best. I was able to get the applet downloaded and displayed on a JPanel and then in a JFrame and the game runs perfectly so far. However, when adding features I ran into a problem when I tried to implement a screenshot function to the client.
It's hard to post a concise working example so I'll post the methods I was trying based off of some other SO answers I was reading. I tried creating BufferedImage from the Applet, applet Canvas, the JPanel it is handled by, and the JFrame.
Here are some things I tried to create a screenshot from the Applet canvas:
public BufferedImage getScreenShot() {
//getting the applet canvas
Canvas canvas = (Canvas) this.getApplet().getComponent(0);
//bufferedImage to draw to
BufferedImage image = new BufferedImage(canvas.getWidth(), canvas.getHeight(), BufferedImage.TYPE_INT_ARGB);
//Graphics2D g2=(Graphics2D)image.getGraphics();
//test.print(g2);
//g2.dispose();
Graphics g = image.getGraphics();
Image image2 = canvas.createImage(canvas.getWidth(), canvas.getHeight());
canvas.print(g);
System.out.println("Canvas Size: " + canvas.getSize().width + " x " + canvas.getSize().height);
return image;
}
This one I tried in the JPanel class which holds only the Applet:
public BufferedImage getScreenShotFINAL(){
BufferedImage bi = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
applet.paint(bi.createGraphics());
return bi;
}
I understand that the idea here is to create an off-screen BufferedImage, then to create a Graphics2d object and to then call the applet's paint() method to paint to the off-screen image. I tried this solution from here:
public BufferedImage getScreenShotFINAL2() {
Dimension size = applet.getSize();
BufferedImage offScreenImage = (BufferedImage) applet.createImage(size.width, size.height);
Graphics2D g2 = offScreenImage.createGraphics();
g2.setBackground(applet.getBackground());
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.clearRect(0, 0, size.width, size.height);
applet.paint(g2);
return offScreenImage;
}
When saving the BufferedImages these and other methods I tried to a file the images just show up as black, just the default background color. Is there a good way to just get a BufferedImage from the JPanel which would include the Applet so I never have to deal with the Applet directly? Another thing, I had to override the java Canvas class in order to get the game to display (because it is double buffered I believe). I tried following a bunch of solutions from here but had no success. Any suggestions would be greatly appreciated. I also can provide a link to the full project or the custom Canvas project if you would like. Thanks!
EDIT
Here is the Canvas class which overrides the java AWT one. Didn't write it, followed a tutorial for this one and I think this is where the problem is, because the paint() method only calls clearRect():
package java.awt;
import Client.Client;
import java.awt.image.BufferStrategy;
import java.awt.peer.CanvasPeer;
import javax.accessibility.*;
import loaders.ClientPool;
public class Canvas extends Component implements Accessible {
private Client client = null;
private static final String base = "canvas";
private static int nameCounter = 0;
private static final long serialVersionUID = -2284879212465893870L;
public Canvas() {
super();
}
public Canvas(GraphicsConfiguration config) {
this();
setGraphicsConfiguration(config);
}
#Override
void setGraphicsConfiguration(GraphicsConfiguration gc) {
synchronized(getTreeLock()) {
CanvasPeer peer = (CanvasPeer)getPeer();
if (peer != null) {
gc = peer.getAppropriateGraphicsConfiguration(gc);
}
super.setGraphicsConfiguration(gc);
}
}
#Override
public Graphics getGraphics(){
if (this.client == null) {
this.client = ClientPool.getClient(this);
}
if (client != null) {
//call custom draw functions for specific client. for drawing/double buffering
return client.drawGraphics((Graphics2D) super.getGraphics());
}
return super.getGraphics();
}
#Override
String constructComponentName() {
synchronized (Canvas.class) {
return base + nameCounter++;
}
}
#Override
public void addNotify() {
synchronized (getTreeLock()) {
if (peer == null)
peer = getToolkit().createCanvas(this);
super.addNotify();
}
}
#Override
public void paint(Graphics g) {
g.clearRect(0, 0, width, height);
}
#Override
public void update(Graphics g) {
g.clearRect(0, 0, width, height);
super.paint(g);
}
#Override
boolean postsOldMouseEvents() {
return true;
}
#Override
public void createBufferStrategy(int numBuffers) {
super.createBufferStrategy(numBuffers);
}
#Override
public void createBufferStrategy(int numBuffers,
BufferCapabilities caps) throws AWTException {
super.createBufferStrategy(numBuffers, caps);
}
#Override
public BufferStrategy getBufferStrategy() {
return super.getBufferStrategy();
}
#Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleAWTCanvas();
}
return accessibleContext;
}
protected class AccessibleAWTCanvas extends AccessibleAWTComponent
{
private static final long serialVersionUID = -6325592262103146699L;
public AccessibleRole getAccessibleRole() {
return AccessibleRole.CANVAS;
}
}
}
I am learning the template method and delegation now. I do not understand what interface inheritance to the newClass, and then the newClass past its inside method to NextClass.
When I ran it, MouseLintener does not work.
Could you please teach me how to fix my codes?
Thank you!
public class KiteComponent extends JComponent{
private ArrayList<Kite> kites;
private Point mousePoint;
public KiteComponent() {
kites = new ArrayList<Kite>();
ColoredCompoundShape c = new ColoredCompoundShape();
addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e)
{
mousePoint = e.getLocationOnScreen();
for (Kite s: kites){
if (s.contains(mousePoint))
s.setColor(s.getColor());}
repaint();
}
});
}
public void add(Kite k){ kites.add(k);repaint();}
public void paintComponent (Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Kite s : kites){ s.drawInColor(g2); }
}
}
s.setColor(s.getColor())
Isn't this useless, it's setting the same color it already is... If you think that this actually isn't being called, print a line in your mouseClicked method to check if it's actually being called.
Hey I'm trying to create a video game and I'm testing to see if I can make a sprite or image appear on the applet I've asked for help before from my peers and professor, but they don't seem to help. I don't know if I have the image in the wrong location or if my code is bugged, but I would appreciate if someone took a look at it Thanks! Oh! by the way I'm programming in Java and I'm using Eclipse JUNO.
enter code here
package meh;
import java.awt.*;
import javax.swing.JApplet;
import javax.swing.ImageIcon;
public class Draw extends JApplet{
public static void main(String[] args)
{
Draw test = new Draw();
}
private Image exImage;
private boolean imagesLoaded;
public void run()
{
imagesLoaded = false;
try
{
loadImages();
try
{
Thread.sleep(10000);
}
catch(InterruptedException ex){}
}
finally{}
}
public void loadImages()
{
exImage = loadImage("C:/Users/Temp/workspace/From Scratch/bin/Ma_rn_0");
imagesLoaded = true;
repaint();
}
private Image loadImage(String fileName)
{
return new ImageIcon(fileName).getImage();
}
public void paint(Graphics g)
{
if(g instanceof Graphics2D)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
if(imagesLoaded)
{
drawImage(g, exImage,0,0, null);
}
else
{
g.drawString("Loading...", 5, 12);
}
}
public void drawImage(Graphics g, Image image, int x, int y, String caption)
{
g.drawImage(image, x, y, null);
g.drawString(caption, x+5, y + 12 +image.getHeight(null));
}
}
Unless they are signed, applets can only load images from the same location from where they originated. Here you are attempting to load an image from the local disk. All initialisation for applet resources should be done from the init method. Images can be loaded as resources from the same JAR file from which they are deployed. You could do
Image exImage = ImageIO.read(getClass().getResourceAsStream("images/MyImage.jpg"))
1 public static void main(String[] args)
Applets are not supposed to have main(), it uses init, start, stop and destroy.
http://docs.oracle.com/javase/tutorial/deployment/applet/getStarted.html
2 Try to learn about EDT concept
3 Don't override paint method
4 Use ImageIO to load images
I want to display an image inside a panel. So I pass the path of the image to this method, open image file and pass it to the method of a private class dedicated to draw image inside the panel. The problem is the panel remains empty all the time and doesn't display anything.
Here is the code:
JPanel ImagePane; // I want to add image to this
public void getImagePath(String Path)
{
BufferedImage image = null;
try
{
image=ImageIO.read(new File(Path));
}
catch (IOException e)
{
e.printStackTrace();
}
DisplayImage display= new DisplayImage();
display.getImage(image);
}
private class DisplayImage extends JPanel
{
private BufferedImage image=null;
public void getImage(BufferedImage im)
{
image=im;
repaint();
}
public void paintComponents(Graphics g)
{
g.drawImage(image, 0, 0, image.getWidth() /2, image.getHeight()/2,ImagePane);
}
}
What am I missing?
paintComponents is a method of the Container which is used to paint each of the components in the container. Instead you need paintComponent to paint this single component.
Change your
public void paintComponents(Graphics g)
method to
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, image.getWidth() /2, image.getHeight()/2,ImagePane);
}
Notice the use of the #Override annotation to help with method signature checking.
Also calling
super.paintComponent(g);
will update child components.
In your method getImagePath you don't appear to add the DisplayImage to any container. Instead you create a local DisplayImage, but don't use it.
You have to override paintComponent
protected void paintComponent(Graphics g)
But in your code you are creating public void paintComponents(Graphics g) which is not correct
There's the use of #Override annotation. If you make it a practice to use it whenever you're overriding a method, this issue can be resolved at compile-time. You need to use this:
#Override
public void paintComponent(Graphics g)