drawImage() with using BufferedImage doesn't draw - java

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Main
{
JFrame jf;
Main()
{
jf=new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(new MyCanvas());
jf.pack();
jf.setVisible(true);
}
public static void main(String[] args)
{
MyCanvas.img=Toolkit.getDefaultToolkit().createImage("1.jpg");
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new Main();
}
});
}
}
class MyCanvas extends JComponent
{
static Image img;
BufferedImage bi;
MyCanvas()
{
setPreferredSize(new Dimension(200,200));
bi=new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
Graphics g=bi.getGraphics();
for (int i=0;i<10;i++)
for (int j=0;j<10;j++)
g.drawImage(img,i*20,j*20,20,20,this);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(bi,0,0,this);
//g.drawImage(img,0,0,this);
}
}
If I uncomment line g.drawImage(img,0,0,this); I get my image on window. But with this code I see empty window. It is easy to understand that g.drawImage(img,i*20,j*20,20,20,this); in loop doesn't draw but what is problem?

edited out the unrelated stuff I did for future readers to find the answer easier. In java i've always had to use getResource or getResourceAsStream to ensure the file loaded from the right directory correctly.
class MyCanvas extends JComponent
{
public static Image loadImage(String s)
{
try
{
return ImageIO.read(Main.class.getResource(s));
}
catch (Exception ex)
{
ex.printStackTrace();
return null;
}
}
}

1) put BufferedImage as Icon to the JLabel example here
2) your paintComponent in CustomCanvas could be
class MyCanvas extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(150, 150);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bi,0,0,this);
}
}

Related

Java-Image not drawing to screen

I am trying to draw an image to the screen using Java. The problem is that it does not appear and no errors occur.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class GameClass extends JPanel implements ActionListener, KeyListener{
private BufferedImage image;
public GameClass(){
Timer time = new Timer(15, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
}
public void openImage(){
try {
image = ImageIO.read(this.getClass().getResource("spaceship.png"));
} catch (IOException e) {
System.out.println("An error occurred!");
}
}
public void paintComponent(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, Main.WW, Main.WH);
g.drawImage(image,Main.WW/2,Main.WH/2,null);
}
public void actionPerformed(ActionEvent e){
repaint();
}
public void keyPressed(KeyEvent e){
}
public void keyReleased(KeyEvent e){
}
public void keyTyped(KeyEvent e){
}
}
You need to call you openImage() method in your constructor.
I renamed this to loadImages() so that this method can handle loading multiple images. I also created a static image loading function.
Note: If you have not already, create a resources/ folder in your projects' src/ folder. This folder will contain your application's assets i.e. text, image, and other data files.
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*
public class GameClass extends JPanel
implements ActionListener, KeyListener {
private static final long serialVersionUID = -2508183917768834794L;
private Image image;
// Added this, because you did not include it.
private class Main {
static final int WW = 256;
static final int WH = 256;
}
public GameClass() {
Timer time = new Timer(15, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
this.loadImages();
}
// Load all required images into instance variables.
public void loadImages() {
image = loadImage("spaceship.png");
}
// Draw the image to the panel.
public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, Main.WW, Main.WH);
// Dimensions of spaceship
int imgW = image.getWidth(null);
int imgH = image.getHeight(null);
// Dimensions of panel
int pnlW = this.getWidth();
int pnlH = this.getHeight();
// Draw the spaceship in the center of the window.
g.drawImage(image, pnlW/2 - imgW/2, pnlH/2 - imgH/2, null);
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }
// Static image loader method which utilizes the `ClassLoader`.
public static Image loadImage(String filename) {
try {
return ImageIO.read(GameClass.class.getClassLoader().getResource("resources/" + filename));
} catch (IOException e) {
System.out.println("Error loading image: " + filename);
}
return null;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
Container panel = new GameClass();
frame.setSize(Main.WW, Main.WH);
frame.setTitle("Spaceship Game");
frame.setContentPane(panel);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}

How to use command arguments in paintComponent method?

I am currently trying to create a Java GUI program that generates images based on the arguments given in the terminal. If I get the argument in the command line java Draw Image1 for example, I want to draw my image 1 and etc. for the others. How can one take a command argument and use it in paintComponent? Here's a sample of what I am trying to do below:
import javax.swing.*;
import java.awt.*;
public class Draw extends JPanel
{
public Draw()
{
this.setSize(800,800);
JPanel drawing = new JPanel();
this.add(drawing);
this.setVisible(true);
}
protected void paintComponent(Graphics g)
{
if (args[0].equals("Image1")) // won't work
{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("image/myimage.jpg");
g.drawImage(myImage, 0, 0, this);
}
else
{
// draw image 2
}
}
public static void main(String[] args)
{
// create new Jframe
JFrame frame = new JFrame("Draw");
frame.add(new Draw());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.setVisible(true);
}
}
Change this:
frame.add(new Draw());
to this:
frame.add(new Draw(args));
And then have your constructor accept a String array parameter and use it to set a class field.
public class Draw extends JPanel
{
private String[] params
public Draw(String params)
{
this.params = params;
this.setSize(800,800); // this generally should be avoided
JPanel drawing = new JPanel();
this.add(drawing);
this.setVisible(true);
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g); // this should be out of the if block
if (params != null && params.length > 0 && params[0].equals("Image1")) {
// ..... etc
Edit: Andrew is right and I did not read your code carefully. Read your image in the constructor and use it in the image in the paintCompnent method
e.g.,
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
#SuppressWarnings("serial")
public class Draw extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private BufferedImage image;
public Draw(String[] params) throws IOException {
if (params != null && params.length > 0) {
image = ImageIO.read(new File(params[0]));
}
// this.setSize(800,800);
JPanel drawing = new JPanel();
drawing.setOpaque(false); // may need this
this.add(drawing);
this.setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
} else {
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
// not sure if you want to size it to the image or not
if (image != null) {
int w = image.getWidth();
int h = image.getHeight();
return new Dimension(w, h);
} else {
return new Dimension(PREF_W, PREF_H);
}
}
public static void main(String[] args) {
// create new Jframe
JFrame frame = new JFrame("Draw");
try {
frame.add(new Draw(args));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setSize(500,500);
frame.pack();
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Wrap xuggler inside a JPanel

I am unable to find any post that clearly demonstrates how to wrap Xuggler within a JPanel. I can see some posts for JFrame though, but the solution doesn't easily translate to JPanel. (Or maybe I am too naive!)
To be more specific, the following method does not work for JPanel as it does for JFrame -
private class MyVideoFrame extends JFrame
{
....
public void paint(Graphics g)
{
if (image != null)
{
g.drawImage(image, 0, 0, null);
}
}
}
Thanks!
The VideoImage source actually uses JComponent, which is not the best choice, but is the parent to JPanel.
The fact they've overridden paint and failed to call super.paint is a really bad example.
Instead, they should have used a JPanel (it's not transparent by default), overridden paintComponent and called super.paintComponent before rendering the frame.
So based on DecodeAndPlayAudioAndVideo or DecodeAndPlayVideo
You should be able to replace the reference to com.xuggle.xuggler.demos.VideoImage with the one below, which uses a JPanel as the main container for the vide frame container for displaing...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class VideoImage extends JFrame {
private final ImagePane mOnscreenPicture;
public VideoImage() {
super();
mOnscreenPicture = new ImagePane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(mOnscreenPicture);
this.setVisible(true);
this.pack();
}
public void setImage(final BufferedImage aImage) {
mOnscreenPicture.setImage(aImage);
}
//....Inner class here....//
public class ImagePane extends JPanel {
private BufferedImage mImage;
public void setImage(BufferedImage image) {
SwingUtilities.invokeLater(new ImageRunnable(image));
}
#Override
public Dimension getPreferredSize() {
return mImage == null ? new Dimension(200, 200) : new Dimension(mImage.getWidth(), mImage.getHeight());
}
private class ImageRunnable implements Runnable {
private final BufferedImage newImage;
public ImageRunnable(BufferedImage newImage) {
super();
this.newImage = newImage;
}
#Override
public void run() {
ImagePane.this.mImage = newImage;
Dimension size = getPreferredSize();
final Dimension newSize = new Dimension(mImage.getWidth(), mImage.getHeight());
if (!newSize.equals(size)) {
VideoImage.this.invalidate();
VideoImage.this.revalidate();
VideoImage.this.pack();
repaint();
}
repaint();
}
}
public ImagePane() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mImage != null) {
g.drawImage(mImage, 0, 0, this);
}
}
}
}

How to load two extended JPanel class to one JFrame?

I'm going to make a game with Java, my game will have a menu. the menu is having a background, and 2 JLabel objects. I've make them on separate class, which is passed to one JFrame. And my problem is, I've load 2 of them on a single frame, but one of them always hidden by another.
this is the code:
JFrame class
#SuppressWarnings("serial")
public class Sistem extends JFrame{
private final int lebar=954;
private final int tinggi=540;
private Image bg;
File gbr=new File("res/a.jpg");
public Sistem(){
this.setTitle("Unknown man Unkown power");
this.setSize(new Dimension(lebar,tinggi));
this.setFocusable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setContentPane(new Ngrep());
//this.setContentPane(new Menu());
this.setVisible(true);
//loadfont();
//loadbg();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
new Sistem();
}
});
}
}
background class
#SuppressWarnings("serial")
public class Ngrep extends JPanel{
private int l=954;
private int t=540;
private BufferedImage bg;
File gbr=new File("res/a.jpg");
public Ngrep(){
loadbg();
}
private void loadbg() {
// TODO Auto-generated method stub
try {
bg=ImageIO.read(gbr);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(bg, 0, 0, l, t, null);
}
}
menu class
#SuppressWarnings("serial")
public class Menu extends JPanel implements Runnable,KeyListener{
private int l=954;
private int t=540;
JLabel menu1=new JLabel("MULAI BARU");
JLabel menu2=new JLabel("KELUARRR");
private File fo=new File("res/Mawns.ttf");
JLayeredPane p=new JLayeredPane();
public Menu(){
loadfont();
this.add(menu1);
this.add(menu2);
}
public void loadfont(){
try {
FileInputStream fi=new FileInputStream(fo);
Font f=Font.createFont(Font.TRUETYPE_FONT, fi).deriveFont(Font.TRUETYPE_FONT, 30);
GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(f);
menu1.setFont(f);
menu2.setFont(f);
} catch (Exception ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
p.setLayout(new GridLayout(2, 3));
menu1.setBounds(0, 0, getWidth(), getHeight());
menu2.setBounds(0, 0+menu1.getHeight(), getWidth(), getHeight());
p.add(menu1, 2);
p.add(menu2, 2);
}
}
What I want is the menu is in front of background but background still can be seen. and how to arrange the JLabel that I've created to center down of the screen.
How can I achieve the required layout?
public class Ngrep extends JPanel{
Note that since Ngrep is a JPanel you can add components directly to it, making the Menu class redundant.
Something like seen in this SSCCE.
Note that I ended up making so many changes so fast I could not be bothered explicitly documenting most of them. Look over the code carefully, check it against your original code, check the Java Docs, and if there is any change you do not understand, ask me.
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.URL;
import javax.imageio.ImageIO;
#SuppressWarnings("serial")
public class Sistem extends JFrame {
public Sistem() {
this.setTitle("Unknown man Unkown power");
this.setFocusable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(new Ngrep());
this.setResizable(false);
this.pack();
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Sistem();
}
});
}
}
#SuppressWarnings("serial")
class Ngrep extends JPanel {
private int l = 375;
private int t = 150;
private BufferedImage bg;
JLabel menu1 = new JLabel("MULAI BARU");
JLabel menu2 = new JLabel("KELUARRR");
public Ngrep() {
this.add(menu1);
this.add(menu2);
try {
Font f = new Font(Font.MONOSPACED, Font.ITALIC, 30);
menu1.setFont(f);
menu1.setForeground(Color.RED);
menu2.setFont(f);
menu2.setForeground(Color.RED);
URL url = new URL("http://i.stack.imgur.com/OVOg3.jpg");
bg = ImageIO.read(url);
} catch (Exception ex) {
ex.printStackTrace();
}
setLayout(new GridLayout(2, 3));
add(menu1);
add(menu2);
}
public Dimension getPreferredSize() {
return new Dimension(l, t);
}
/*
* For a JComponent, override paintComponent rather than paint
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// a JPanel IS AN ImageObserver
g.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
}
}
Start by using JFrame#add instead of JFrame#setContentPane, unless you intend to add more components to that (content) pane.
By default JFrame uses a BorderLayout for its LayoutManager. You will need to either change it to something you prefer to use OR add each component to an appropriate position within the BorderLayout
See Laying Out Components Within a Container for more details
solved, because I've found that i use paint() instead of paintComponent().
like this:
#Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(bg, 0, 0, l, t, this);
}
to this :
#Override
public void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
g.drawImage(bg, 0, 0, l, t, this);
}

JButton isn't in the right place when a BufferedImage is used in it's container

I'm trying to create a simple game using AWT but I want to have some JButtons aswell to exit/reset the game. The problem is, I want the BufferedImage to be drawn inside the visible frame like so in my container I have this at the end:
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
My problem is, when I add a JButton to that frame, it only detects rollover in space that doesn't take into account the offsetting, but is drawn in a space that does. This is the relevant code (con is the container).
private void addButtons()
{
reset = new JButton("reset");
reset.setBounds(180,460, 75,30);
reset.addActionListener( this );
con.add(reset);
exit = new JButton("exit");
exit.setBounds(290,460, 60,30);
exit.addActionListener( this );
con.add(exit);
con.repaint();
}
The paint method in the Container
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
b.setColor(Color.GRAY);
b.fillRect(0, 0, this.getWidth(), this.getHeight());
b.setColor(Color.BLACK);
b.drawRect(0,0,420,420);
super.paint(b);
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}
How can I make the button be drawn and detected in the same spot?
here is a screenshot of the problem
As requested:
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class Draw implements ActionListener{
private SnakeFrame frame;
private SnakeCon con;
JButton reset, exit;
private boolean res;
public Draw()
{
frame = new SnakeFrame("Snake");
frame.setResizable(false);
frame.setLayout(null);
frame.setSize(600,600);
frame.setVisible(true);
con = new SnakeCon();
con.setBounds(0,0,600,600);
frame.add(con);
}
private void addButtons()
{
reset = new JButton("reset");
reset.setBounds(180,460, 75,30);
reset.addActionListener( this );
con.add(reset);
exit = new JButton("exit");
exit.setBounds(290,460, 60,30);
exit.addActionListener( this );
con.add(exit);
con.repaint();
}
public void run()
{
addButtons();
res = false;
boolean dead = false;
while(!dead)
{
if( (res) )
dead = true;
if (!dead)
{
try{
Thread.sleep(100);
}
catch (Exception e)
{}
frame.repaint();
}
}
con.removeAll();
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == reset)
res = true;
else if (e.getSource() == exit)
System.exit(0);
}
}
--
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeCon extends Container{
private BufferedImage bf;
public SnakeCon()
{
super();
setBounds(0,0,600,600);
}
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
b.setColor(Color.GRAY);
b.fillRect(0, 0, this.getWidth(), this.getHeight());
b.setColor(Color.BLACK);
b.drawRect(0,0,420,420);
super.paint(b);
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}
public void update(Graphics g)
{
paint(g);
}
}
--
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeFrame extends Frame implements WindowListener{
private BufferedImage bf;
public SnakeFrame(String s)
{
super(s);
addWindowListener( this );
}
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
super.paint(b);
g.drawImage(bf,0,0,null);
}
public void update(Graphics g)
{
paint(g);
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
public void windowClosed(WindowEvent e) { }
public void windowOpened(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowActivated(WindowEvent e) { }
public void windowDeactivated(WindowEvent e) { }
}
--
public class Main {
public static void main(String[] args)
{
boolean never = false;
Draw d = new Draw();
while(!never)
{
d.run();
}
System.exit(0);
}
}
Im not sure exactly what is wrong/what you want (why do you have a loop to constantly drawing buttons and invoking removeAll()? etc but i cant shake the feeling it might be implemented in a more readable/efficient way)...
But here are some suggestions that can only help your code get better:
Dont use null/Absolute Layout choose an appropriate LayoutManager.
Do not override JFrame paint(..), rather add JPanel to JFrame and override paintComponent(Graphics g) of JPanel and do drawing there.(Do not forget to have super.paintComponent(..) as 1st call in overriden paintComponent method. See here for more: Performing Custom Painting
Do not set JFrame visible before adding all components to JFrame
Always create and manipulate Swing components on Event Dispatch Thread like so:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create Swing components
}
});
Do not do long running tasks on Event Dispatch Thread rather use Swing Timer/Swing Worker
Do not call setSize(..) on JFrame rather override getPreferredSize() of JPanel and return Dimensions which fit all components (see here for reasoning), than call pack() on JFrame before setting it visible
Dont extend JFrame unnecessarily or Container!
Adding WindowListener for detecting JFrame exit is not worth the lines rather use:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
to exit Swing application when X is pressed.

Categories