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

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);
}
}

Related

How to draw shape inside of JPanel that is inside JFrame

I have issue with drawing shapes inside of JPanel that I already added using Netbeans GUI. Now, I have no idea where to add code for drawing a circle inside of that JPanel and how to insert and call it in the JPanel that is sitting empty now, waiting for this shape to be drawn. I already set up destination JPanel to be Flow layout.
Netbeans Designer created a big class in which I have entire frame with this JPanel, and I want to keep it inside of it as I can't really add it any other way because Designer doesn't let me change main initComponents method in which all components are sitting now. I have been reading tutorials and previous posts but noone really encountered this using Netbeans Designer.
SO can someone just help me with adding proper method in this frame class and how to call it from JPanel I want to draw in. JPanel is 50x50 pixels.
So as per #Abra, I changed some code:
so I made a new Circle Class, adjusted it a bit as I don't want to create a new frame but put this in JPanel.
public class Circle extends JPanel {
Color color;
public void circle(Color color) {
this.color = color;
setPreferredSize(new Dimension (30,30));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(0, 0, r, r);
g.setColor(color);
}
private void showGUI() {
JPanel panel = new JPanel();
panel.add(this, FlowLayout.CENTER);
panel.setVisible(true);
}
}
Then I opened JPanel in Designer, and added code to run it, in initComponents method like this:
circlePanel.setPreferredSize(new java.awt.Dimension(40, 40));
new Circle().showGUI();
PanelDS.add(circlePanel);
circlePanel is destination for this drawing and is inside PanelDS itself. It doesn't work this way tho, but Netbeans shows no errors in code. Additionally, how can I forward color to circle class.
In order to draw on a JPanel you need to override the paintComponent() method of JPanel. In order to override the method, you need to create a class that extends JPanel. I don't think that there exists a GUI designer that can generate the required code for you. So you have to write the code of the class that extends JPanel.
Here is a minimal example. It displays a blue circle.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Drawing2 extends JPanel {
private JFrame frame;
public Drawing2() {
setPreferredSize(new Dimension(100, 100));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(25, 25, 50, 50);
}
private void showGui() {
frame = new JFrame("Drawing");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
new Drawing2().showGui();
}
}
Here's what you should see when you run the above code.

JPanel Graphics not drawing anything (Java) [duplicate]

This question already has an answer here:
Can't draw to JPanel with getGraphics
(1 answer)
Closed 4 years ago.
I'm having trouble getting the graphics of my JPanel to work. It refuses to draw anything, regardless of anything I've tried and anything I can find on the internet.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Timer;
import java.util.*;
import java.io.*;
public class Mandelbrot{
public static void main(String[] args){
JFrame win=new JFrame();
JPanel dis=new JPanel();
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setResizable(false);
win.setVisible(true);
win.add(dis);
dis.setPreferredSize(new Dimension(1000,500));
win.pack();
Graphics g=dis.getGraphics();
g.setColor(Color.red);
g.fillRect(0, 0, 100, 100);
}
}
Posting as an answer because I ran out of comment room:
Note:
If you need to be constantly changing things, then a JPanel is probably not your best option. I recommend you rethink what you are trying to do because you should probably use a Canvas or paint to a bunch of different labels/glass panes and overlay them however you want, this will allow you to have moving components/animations in a foreground item, and make different changes to the background item.
Alternatively, you can make the JPanel draw a buffered image, or you can store a list of items to paint, and you can paint them each time. For the buffered image method you can directly edit and draw to the buffered image every time you need to make a change.
Below is an example of how to use the buffered image method.
First create a custom JPanel in a new class:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class DrawPanel extends JPanel{
public BufferedImage canvas = new BufferedImage(panelWidth, panelHeight, BufferedImage.TYPE_INT_ARGB);
#Override
public void paintComponent(Graphics g){
//Draw the canvas
g.drawImage(canvas, 0, 0, this);
}
}
Now in your main method you can replace JPanel dis=new JPanel() with this:
DrawPanel dis = new DrawPanel();
Graphics g=dis.canvas.getGraphics();
g.setColor(Color.red);
g.fillRect(0, 0, 100, 100);
Note how I use dis.canvas to get the graphics of the bufferedImage instead of the graphics of the JPanel.
It's as simple as that.
As per Andrews comment. You should consider extending a JLabel instead of a JPanel, it is much more lightweight, and easier to update using label.repaint();.
public static void main(String... args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
JPanel panel = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.red);
g.fillRect(0, 0, 100, 100);
}
};
panel.setPreferredSize(new Dimension(640, 480));
frame.add(panel);
frame.setVisible(true);
frame.pack();
}
Just an example - you should create a new Class subclassing JPanel, see Painting in AWT and Swing.

How would I draw on a JPanel to then be shown on a JFrame?

I've tried to research how Java's 2D rendering works, but I could never understand it. Here is the code in my main class:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main{
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setSize(new Dimension(500,500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("JFrame testing");
frame.setVisible(true);
Frame panel = new Frame();
frame.add(panel);
}
}
And then here is for the JPanel class:
import java.awt.Graphics;
import javax.swing.JPanel;
public class Frame extends JPanel{
private static final long serialVersionUID = 1L;
public Frame() {
Graphics g = this.getGraphics();
g.drawRect(0, 0, 100, 100);
this.paintComponent(g);
}
}
I am also getting this exception, but I'm not sure what it means:
Exception in thread "main" java.lang.NullPointerException
at Frame.<init>(Frame.java:10)
at Main.main(Main.java:18)
I'm basically just trying to draw a rectangle onto a panel to be shown on the frame I've created. I've heard about the paintComponent method, but I also don't fully understand that.
You should Never use getGraphics() of a Component.
Try below code
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, 100, 100);
//this.paintComponent(g);
}
Edit
"why is super.paintComponent(g); called again inside the method?"
The documentation of paintComponent says it pretty well:
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.

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

Image not drawn in JPanel.paintComponent

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

Categories