Image not drawn in JPanel.paintComponent - java

I am actually want to load image but only applet dialog open and no error occurred but the image is not loading.the code is below here
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Ball extends JPanel{
Image image;
public Ball(){
super();
image = Toolkit.getDefaultToolkit().getImage("/D:\\lolololo\\tuto\\bin\\sa.jpg");
}
private Image getResource(String string) {
return image;
// TODO Auto-generated method stub
}
public void paintComponent(Graphics g){
// Draw our Image object.
g.drawImage(image,50,10,574,960, this); // at location 50,10
// 200 wide and high
}
public void main(String arg[]){
JFrame frame = new JFrame("ShowImage");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,500);
Ball panel = new Ball();
frame.setContentPane(panel);
frame.setVisible(true);
}
}

The way you are loading the image is wrong. This will never work when you extract as Runnable jar.
Create package ("res") inside inside your src
Now load the image this way
image = ImageIO.read(Ball.class.getResource("/res/sa.jpg"));
This will work.
As indicated by Andrew in his comment main class should be
public static void main(String arg[]) {}

+1 to #AndrewThompsons comments.
1) Below is incorrect, you do not honer the paint chain by calling the supers implementation of super.paintComponent(...):
public void paintComponent(Graphics g) {
// Draw our Image object.
g.drawImage(image,50,10,574,960, this); // at location 50,10
// 200 wide and high
}
As per docs for paintComponent:
Further, if you do not invoker super's implementation you must honor
the opaque property, that is if this component is opaque, you must
completely fill in the background in a non-opaque color. If you do not
honor the opaque property you will likely see visual artifacts.
should be:
public class Ball extends JPanel {
BufferedImage image;
public Ball() {
super();
try {
image=ImageIO.read(new File("c:/test.jpg"));//change to your path of file
}catch(Exception ex) {//file did not load properly
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
// Draw our Image object.
g.drawImage(image,0,0,image.getWidth(),image.getHeight(), this); // at location 50,10
// 200 wide and high
}
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(),image.getHeight());//replace with size of image
}
}
Also notice:
I overrode getPreferredSize() of JPanel and returned Dimensions I wanted (i.e Image size) or the JPanel will only be as big as the components added to it and not the image (so if no components 0,0).
I also chose BufferedImage vs Image and surrounded the statement with a try catch to check if any errors are thrown.
I see you also had g.drawImage(image,50,10...) why 50 and 10 and not 0,0?
2) Also this (as #AndrewThompson has said):
image = Toolkit.getDefaultToolkit().getImage("/D:\\lolololo\\tuto\\bin\\sa.jpg");
No need for the / thats only if its located in your classes package etc not when its on your HDD at a set location.
3) also as said by #AndrewThompson a main method should be:
public static void main(String[] args){}
Notice the static modifer applied other wise its just another method.
4) Also dont use JFrame#setSize(..), rather use LayoutManager and/or override getPreferredSize and than simply call pack() on JFrame instance before setting it visible.
5) Also please have a read on Concurrency in Swing. especially the Event-Dispatch-Thread

Related

Why getScaledInstance() does not work?

So, I am trying to create a monopoly game. I am trying to load an image (of the board) onto a JPanel.
I first want to scale the image to a 1024*1024 image.
I already got the image to appear on the JPanel (so the file address works).
But whenever I use the getScaledInstance() method, the image doesn't appear
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.SystemColor;
//a class that represent the board (JFrame) and all of it components
public class Board extends JFrame {
private final int SCALE;
private JPanel panel;
public Board(int scale) {
getContentPane().setBackground(SystemColor.textHighlightText);
// SCALE = scale;
SCALE = 1;
// set up the JFrame
setResizable(false);
setTitle("Monopoly");
// set size to a scale of 1080p
setSize(1920 * SCALE, 1080 * SCALE);
getContentPane().setLayout(null);
panel = new JPanel() {
public void paint(Graphics g) {
Image board = new ImageIcon(
"C:\\Users\\Standard\\Pictures\\Work\\Monopoly 1.jpg")
.getImage();
board = board.getScaledInstance(1022, 1024, java.awt.Image.SCALE_SMOOTH);
g.drawImage(board, 0, 0, null);
}
};
panel.setBounds(592, 0, 1024, 1024);
getContentPane().add(panel);
}
public static void main(String[] args) {
Board board = new Board(1);
board.setVisible(true);
board.panel.repaint();
}
}
Whenever I remove the board.getScaledInstance() line of code, the image appears (though not scaled), but when I add the line of code, the image doesn't appear at all.
Why does this happen?
You're doing several things wrong:
You're overriding paint, not paintComponent. This is dangerous as you're overriding an image that does too much and has too much responsibility. Doing this without care can lead to significant image side effects, and will also lead to slow perceived animation due to paint not double buffering.
You're not calling the super painting method within your override, something that will lead to accumulation of painting artifacts and breaking of the Swing component painting chain.
You're reading in an image potentially multiple times and within a painting method, a method that must be as fast as possible since it's a major determinant in the perceived responsiveness of your application. Read it in once only, and then save it to a variable.
You're using null layouts and setBounds. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
You're scaling the image within the paint method, again doing something that will slow down the perceived responsiveness of the GUI. Instead, scale the image once only, and save that scaled image to a variable.
Importantly, you're using the same variable, board, for both the original image and the scaled image, and this will lead to re-scaling of the image every time that paint is called.
As Mad points out, you should pass in this to your g.drawImage(...) method call, so that you don't draw an image before it's completely read in.
Also, don't read the image in as a File or as an ImageIcon when you're not using it as an ImageIcon. Use ImageIO to read it in as a BufferedImage, and use resources, not Files.
I would also simplify things, for example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyBoard extends JPanel {
private static final String IMG_PATH = "http://ecx.images-amazon.com/"
+ "images/I/81oC5pYhh2L._SL1500_.jpg";
// scaling constants
private static final int IMG_WIDTH = 1024;
private static final int IMG_HEIGHT = IMG_WIDTH;
// original and scaled image variables
private BufferedImage initialImg;
private Image scaledImg;
public MyBoard() throws IOException {
URL url = new URL(IMG_PATH);
initialImg = ImageIO.read(url); // read in original image
// and scale it *once* and store in variable. Can even discard original
// if you wish
scaledImg = initialImg.getScaledInstance(IMG_WIDTH, IMG_HEIGHT,
Image.SCALE_SMOOTH);
}
// override paintComponent, not paint
#Override // and don't forget the #Override annotation
protected void paintComponent(Graphics g) {
super.paintComponent(g); // call the super's painting method
// just to be safe -- check that it's not null first
if (scaledImg != null) {
// use this as a parameter to avoid drawing an image before it's
// ready
g.drawImage(scaledImg, 0, 0, this);
}
}
// so our GUI is sized the same as the image
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || scaledImg == null) {
return super.getPreferredSize();
}
int w = scaledImg.getWidth(this);
int h = scaledImg.getHeight(this);
return new Dimension(w, h);
}
private static void createAndShowGui() {
MyBoard mainPanel = null;
try {
mainPanel = new MyBoard();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("My Board");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java graphics PaintComponent problems. Can't seem to find the mistake

I'm making a program for drawing out an Image and it seems I've made a mistake and my program just doesn't want to draw out the image. Can someone please point out the mistake for mi because i really don't see it.
package basic_game_programing;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Practise extends JPanel {
public Image image;
//#####PAINT__FUNCTION#####
public void PaintComponent(Graphics g){
super.paintComponent(g);
ImageIcon character = new ImageIcon("C:/Documents and Settings/Josip/Desktop/game Šlije/CompletedBlueGuy.PNG");
image = character.getImage();
g.drawImage(image,20,20,null);
g.fillRect(20, 20, 100, 100);
}
//######MAIN__FUCTION#######
public static void main(String[]args){
Practise panel = new Practise();
//SETTING UP THE FRAME
JFrame frame = new JFrame();
//
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.add(panel);
//SETTING UP THE PANEL
//
}
}
You're miscapitalizing paintComponent by using PaintComponent instead (note the first "P").
So Change PaintComponent to paintComponent.
Use the #Override annotation above the method to let the compiler tell you when you're making this kind of mistake.
Never read an image into a painting method since this slows down a method that needs to be fast, and makes the image be read in over and over when one read is enough.
The method should be protected not public.
Use ImageIO.read(...) to read in your image, and use resources and relative path within the jar file, rather than use files or ImageIcons.
Don't call setVisible(true) on the JFrame until after adding all components, else some might not show.
Do read the tutorials as most all of this is well explained there.
e.g.,
public class Practise extends JPanel {
private Image image;
public Practice() {
// read in your image here
image = ImageIO.read(.......); // fill in the ...
}
#Override // use override to have the compiler warn you of mistakes
protected void paintComponent(Graphics g){
super.paintComponent(g);
// never read within a painting method
// ImageIcon character = new ImageIcon("C:/Documents and Settings/Josip/Desktop/game Šlije/CompletedBlueGuy.PNG");
// image = character.getImage();
g.drawImage(image, 20, 20, this);
g.fillRect(20, 20, 100, 100);
}
}

Java Swing adding images code in MigLayout does not seem to be working?

So I have my own custom JFrame, and in it I am trying to create an auto-resizing image to be contained in my JFrame's content JPanel, frameContent. My layout manager for the JPanel is MigLayout, so I figured I would create a child of JPanel again, called ImagePanel. Here is what my ImagePanel class ended up looking like:
class ImagePanel extends JPanel{
private static final long serialVersionUID = -5602032021645365870L;
private BufferedImage image;
public ImagePanel() {
try {
image = ImageIO.read(new File(getClass().getResource("../res/Title.png").toURI()));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, getWidth(), getHeight(), null);
}
}
Now for some reason it doesn't seem like it's actually 'working'. When I am setting up my main JFrame's content, I call:
framecontent.add(new ImagePanel(), "pos 5% 5% 95% 45%");
It's not that it's not adding the component, as with this code I'm able to get the following screen:
Notice how it outlines the area against the gray background, meaning the paintComponent(g) method is being run, and the program also isn't outputting any errors, which is strange, so that means it is finding my image, just not placing it.
Here is what my file hierarchy looks like:
Project Folder >
src >
res >
Title.png (Picture I want to retrieve)
guiwork >
Working.class (Class that is running instructions/ main)
Got it all fixed up, here is the auto-resizing result:
Notice how it outlines the area against the gray background, meaning the paintComponent(g) method is being run, and the program also isn't outputting any errors, which is strange, so that means it is finding my image, just not placing it.
Not so as a null image will throw no errors. To prove this, test your image variable in the paintComponent method and you'll likely find that it is in fact null.
i.e., try this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("image is null: " + (image == null)); // TODO: Delete this
g.drawImage(image, getWidth(), getHeight(), null);
}
Solution: don't change your resource to a file, but instead use the resource as is, and make sure that you're looking for it in the correct location.
Edit
Oh chit, you're drawing your image beyond the bounds of your component:
g.drawImage(image, getWidth(), getHeight(), null);
try:
g.drawImage(image, 0, 0, null);
Edit 2
What if you try a simple test program, something like:
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class TestImage {
public TestImage() throws IOException {
String path = "/res/Title.png";
BufferedImage img = ImageIO.read(getClass().getResource(path));
ImageIcon icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, icon);
}
public static void main(String[] args) {
try {
new TestImage();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and be sure to place this in the same location as your current class. Does it run?
For those who might have trouble understanding HoverCraft's Answer:
Say you have a Panel in which you want to add an image that scales, the following code does that for you
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
public class MasterSlidePanel extends JPanel {
private ImageIcon imageIcon;
private JLabel image;
public MasterSlidePanel() {
super(new MigLayout("", "2% [] 2%", "2% [] 2%"));
}
#Override
protected void paintComponent(Graphics g) {
image.setIcon(new ImageIcon(imageIcon.getImage().getScaledInstance(image.getWidth(), image.getHeight(), Image.SCALE_SMOOTH)));
super.paintComponent(g);
}
public void setImage(SlidePanel panel) {
imageIcon = <Where you get the imageIcon>;
image = new JLabel();
image.setMinimumSize(new Dimension(10, 10));
image.setPreferredSize(new Dimension(10, 10));
this.add(image, "width 96%, height 96%");
}
}
We add 2 new members to the panel, image and imageIcon. The moment when the application needs to paint the panel, a scaled inscance of the imageIcon is loaded and given to image.
To prevent 0 height/width errors, we add a minimumsize to the JLabel.
Hope this helps.
Credits still go to HoverCraft Full Of Eels.

Painting on a JFrame works, but it throws NullPointerException anyway

The window shows up and works as intended, but it still gives me a NullPointerException for some reason. Two in fact. Here's the code:
public class SwagFrame extends JFrame {
public SwagFrame() {super("Swag");}
public void paint(Graphics g) {
Image bg = null;
try {
bg = ImageIO.read(new File("swag.png"));
} catch (IOException e) {
System.out.println("Swag not turned on");
System.exit(-1);
}
g.drawImage(bg, 0, 0, null); // exception here
g.setColor(Color.GREEN);
g.fillOval(250, 250, 100, 100);
}
public static void main(String[] args) {
SwagFrame frame = new SwagFrame();
frame.setVisible(true);
frame.setSize(525, 525);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.paint(null); // exception here
}
}
If paint() requires an object in its parameters, why does it still work anyway but throw the exception after the fact?
Two things I did. I made the SwagFrame a JPanel instead of a JFrame, so I could use the paintComponent method, I deleted the frame.paint(null) and I changed the null in the drawImage to this. The code works fine now.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SwagFrame extends JPanel {
public SwagFrame() {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage bg = null;
try {
bg = ImageIO.read(new File("icons/stacko/stackoverflow1.png"));
} catch (IOException e) {
System.out.println("Swag not turned on");
//System.exit(-1);
}
g.drawImage(bg, 0, 0, this); // exception here
g.setColor(Color.GREEN);
g.fillOval(250, 250, 100, 100);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new SwagFrame());
frame.setSize(525, 525);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//frame.paint(g); // exception here
}
}
Also if you want to set the size of the image, you can pass it as argument to the .drawImage() method
g.drawImage(bg, 0, 0, width, height, this);
And one more thing, make sure the image is in the right file location.
As #MadProgrammer stated in his comments:
" Generally, top level containers aren't double buffered, where as Swing components (extending from JComponent) are. Top level containers have a number of layers placed ontop of them (layered pane, content pane and glass pane), making it very complex surface to safely paint to. Also, generally, when a child component is painted, the parent container doesn't need to be this can lead to dirty paints occurring. Also, generally, extending from JFrame is discouraged as you are never actually adding any additional functionality to it
The reason the OPs code didn't work (as you seem to have duduced) was they were passing a null value to the paint method, when means when they tried to access "g", it threw a NPE, however, the the Repaint Manager schedule it's paint request, the paint method was passed a valid Graphics refernce, meaning it was able to work properly...also, the OP isn't call super.paint, bad on them" - #MadProgrammer

g.drawLine doing nothing

This is my code so far with some print lines just to make sure it was actually even going into the method. For some reason NOTHING is being drawn on the canvas, I have a program similar to this as far as the drawing goes and it works fine. What is wrong with this one?
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.*;
public class gameOfLife implements ActionListener {
private int height;
private int width;
private Graphics g;
private JPanel panel;
private JFrame frame;
int[][] board= new int[40][40];
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
gameOfLife gui = new gameOfLife();
}
public gameOfLife() {
int height=400;
int width=400;
frame= new JFrame("Keegan's Game Of Life");
frame.setSize(new Dimension(height,width));
frame.setLayout(new BorderLayout());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
g=frame.getGraphics();
drawBoard();
}
public void drawBoard() {
g.setColor(Color.BLUE);
g.drawLine(0, 0, 50, 50);
g.fillOval(50,50,10,10);
System.out.println("Done Drawing");
g.drawString("IT WORKED!", 100, 100);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
Let's start with g=frame.getGraphics();
This is a very bad idea and not how custom painting is performed. getGraphics may return null and is generally only a snap shot of the last paint cycle. Anything painted to the Graphics context via this method will be destroyed on the next repaint cycle.
You should never maintain a reference to any Graphics context, they are transient and may not be the same object between paint cycles
Instead, create yourself a custom component (something like JPanel) and override it's paintComponent method
Check out Performing Custom Painting for more details
Updated
You can check out this simple example for an idea...
You can override paint(Graphics g) in your canvas, otherwise the drawing will disappear once the canvas is invalidated (e.g. moved or covered by another windows).
It might be easier to let your class extends JFrame and override the paint methods, otherwise you can use anonymous class e.g.
frame = new JFrame("Keegan's Game Of Life") { //override paint here }
However, if your application aims to create animation for Game Of Life, you should not be doing this in a JFrame, consider using JPanel or Canvas

Categories