I am currently working on a project, I get this error Java.lang.NullPointerException, I undrestand that this error happen when you try to refer to a null object instance, but what I do not know, is how I can fix it.
This is my code:
public void paint(Graphics g) {
g.setColor(Color.red);
g.drawOval(150, 150, 10, 10);
}
/** Main Method **/
public static void main(String [] args) {
Run run = new Run();
run.paint(null);
}
Please help me with a solution and also explain it, so that I learn it. Many thanks in advance. Andre
You may not pass null to your paint method! Here is a small example how to do it:
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
class MyCanvas extends JComponent {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval (10, 10, 200, 200);
}
}
public class DrawOval {
public static void main(String[] a) {
JFrame window = new JFrame();
window.setBounds(30, 30, 300, 300);
window.getContentPane().add(new MyCanvas());
window.setVisible(true);
}
}
You almost never call paint methods (including paintComponent) directly as this is what the JVM should be doing.
Don't override the paint(Graphics g) method of a JComponent or JComponent derived class such as a JPanel if you can avoid it. This method, paint, is responsible for not only painting the component but also its borders and its child components, and if not done carefully, overriding this method will not infrequently result in unwanted side effects.
Later when you want to do graphics animation, overriding paint(Graphics g) will result in jerky graphics since it does not do double buffering by default.
By overriding the paintComponent(Graphics g) method instead you fix these issues.
Don't forget to call the super's paintComponent(g) method in your override to erase any unwanted previously drawn images.
Read the Swing Graphics tutorials, both the basic and advanced tutorials. Links at the bottom.
Better code:
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class MyBetterCanvas extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(10, 10, 200, 200);
}
public static void main(String[] a) {
MyBetterCanvas canvas = new MyBetterCanvas();
canvas.setPreferredSize(new Dimension(300, 300));
JFrame window = new JFrame("My Better Canvas");
window.getContentPane().add(canvas);
window.setLocationByPlatform(true);
window.pack();
window.setVisible(true);
}
}
Better Still:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class MyBetterStillCanvas extends JComponent {
private static final int PREF_W = 500;
private static final int PREF_H = 500;
private static final int OVAL_X = 10;
private static final int OVAL_Y = OVAL_X;
private static final Paint BG_PAINT = new GradientPaint(0, 20,
Color.black, 20, 0, Color.darkGray, true);
private static final Paint FILL_PAINT = new GradientPaint(0, 0,
Color.blue, 20, 20, Color.red, true);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// to smooth out graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// let's draw something funky
g2.setPaint(BG_PAINT);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setPaint(FILL_PAINT);
// avoid use of "magic" numbers
g.fillOval(OVAL_X, OVAL_Y, getWidth() - 2 * OVAL_X, getHeight() - 2
* OVAL_Y);
}
// a cleaner way to set the preferred size of a component
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public static void main(String[] a) {
JFrame window = new JFrame("My Better Canvas");
window.getContentPane().add(new MyBetterStillCanvas());
window.setLocationByPlatform(true);
window.pack();
window.setVisible(true);
}
}
Which displays as:
Tutorials:
Java Tutorials, Really Big Index
Java Swing Tutorials
Basic Swing Graphics Tutorial: Lesson: Performing Custom Painting
More Advanced Graphics Article: Painting in AWT and Swing
You are not doing it the right way. In order to use graphics in java you need to build upon Swing/AWT components. Currently you are passing Graphics as null.
run.paint(null);
You need to implement this using JFrame and other swing components.
Since you are sending null to paint, Graphics g contains null (points to nowhere).
Then inside paint(...) you call setColor(...) on g, which is null. null.setColor(...) causes NullPointerException.
Related
For some reason Graphics2D won't generate the background I am trying to set. I think the problem is something to do with renderer sending the information back to Simon the main class. I can't seem to find a solution and have been looking for hours online. If anyone know graphics 2D well or sees the issue with the code and can help that would be greatly appreciated.
package Simon;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
public class TestingSimon implements ActionListener {
//Creating object simon
public static TestingSimon simon;
//Making integers for Width and Height for JFrame
public static final int WIDTH = 800, HEIGHT = 800;
//making a renderer for graphics2D
public Renderer renderer;
public TestingSimon() {
//Creating JFrame
JFrame frame = new JFrame("Simon Says");
//using animation for a timer
Timer timer = new Timer(20,this);
//assigning renderer to the method I create in java class Renderer
renderer = new Renderer();
//setting a size for the JFrame
frame.setSize(WIDTH + 15, HEIGHT + 35);
frame.setVisible(true);
frame.add(renderer);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
timer.start();
}
public static void main(String[] args) {
simon = new TestingSimon();
}
#Override
public void actionPerformed(ActionEvent e) {
//setting it to repaint when action event occurs
renderer.repaint();
}
public void paint(Graphics2D g) {
//trying to set background to grey using Graphics2D
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.GRAY);
}
}
//Java package Renderer
package Simon;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
/**
*
* #author chasepflueger
*/
#SuppressWarnings("serial")
//extending JPanel
public class Renderer extends JPanel
{
/**
*
* #param g
*/
//trying to implement paintComponent to Simon
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(TestingSimon.simon != null)
{
TestingSimon.simon.paint((Graphics2D) g);
}
}
}
//trying to set background to grey using Graphics2D
Painting the background of a component is already support by all Swing components. All you do is set the background Color:
renderer = new Renderer();
renderer.setBackground(Color.GREY); // also try Color.RED to see the difference
Painting is a function of Java components:
public void paint(Graphics2D g) {
//trying to set background to grey using Graphics2D
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.GRAY);
}
You can't just add a method to any class and expect painting to work. Your TestingSimon class is not a Component so that does nothing. Get rid of the code.
Read the section from the Swing tutorial on Custom Painting for more information and working example you can download and play with to learn the basics.
I am currently using the Applet class to create a simple game. Because there is a flickering effect, I've added double-buffering for Graphics components by creating an off-screen buffer like so:
public class AppletTest extends Applet implements Runnable {
Thread thread;
Image img;
Graphics gfx;
public final int WIDTH = 700, HEIGHT = 500;
public void init() {
this.resize(WIDTH, HEIGHT);
thread = new Thread(this);
thread.start();
img = createImage(WIDTH, HEIGHT); // off-screen buffering
gfx = img.getGraphics();
}
public void draw(Graphics g) {
gfx.setColor(Color.BLACK);
gfx.fillRect(0, 0, WIDTH, HEIGHT);
gfx.setColor(Color.WHITE);
gfx.fillRect(50, 50, 100, 100);
gfx.setFont(new Font("Century", Font.BOLD, 30));
gfx.drawString("I feel good sometimes I don't", 200, 200);
g.drawImage(img, 0, 0, this); // draws the off-screen image
}
public void update(Graphics g) {
draw(g);
}
public void run() {
while(true) {
repaint();
try {
Thread.sleep(5);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
If you run the application, all the Graphics (.fillRect, .drawString, etc.) components/methods are drawn on the off-screen buffer. However, my goal is to add a JButton to the applet - and as expected, there's no off-screen loading for the JButton component (which means flickering).
Graphics gfx;
JButton button1;
public void draw(Graphics g) {
setLayout(null);
button1.setBounds(225, 400, 250, 50);
button1.setFont(new Font("Courier", Font.PLAIN, 17));
button1.setForeground(Color.WHITE);
button1.setBackground(Color.DARK_GRAY);
add(button1); // is it possible to draw the JButton on the off-screen buffer?
}
How would you add off-screen loading to a JButton component?
Applet (and JApplet) are officially deprecated, they are no longer supported by Java, Oracle, Browsers (or the community generally)
Swing components are, by default, double buffered. If you work with the painting system correctly, you shouldn't experience any flickering, if you do, it's clear sign that you're doing something wrong.
I would recommend having a look at Performing Custom Painting and Painting in AWT and Swing for more details about how the Swing painting system works.
Swing is single threaded AND not thread safe. This means that you should not perform any long running operations within the context of the Event Dispatching Thread and you should not update the UI from outside the context of the EDT.
Have a look at Concurrency in Swing for more details.
A simple solution to these problems is to make use a Swing Timer, which can be used to schedule regular updates which are executed within the context of the EDT.
See How to Use Swing Timers for more details...
As a basic runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public static final int WIDTH = 700, HEIGHT = 500;
public TestPane() {
setLayout(new GridBagLayout());
add(new JButton("Big fat button"));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, WIDTH, HEIGHT);
g2d.setColor(Color.WHITE);
g2d.fillRect(50, 50, 100, 100);
g2d.setFont(new Font("Century", Font.BOLD, 30));
g2d.drawString("I feel good sometimes I don't", 200, 200);
g2d.dispose();
}
}
}
Okay, "But I absolutely, must, no questions asked, use Applet ... 😓, then I feel sorry for you, but that doesn't change the fact that Swing is already double buffered. The above example could easily be applied to a J/Applet simply by creating an instance of the JPanel and adding to an Applet container
Swing makes use of "passive rendering" algorithm, if you absolutely must be complete control, then you can have a look at BufferStrategy which hands complete control of the painting system over to you, but you won't be able to use Swing components, as they are updated by the Swing sub-system
I have a custom JPanel class and I want it to paint several rectangles and texts in front of it's child components. I have overridden this method:
public void paint(Graphics g){
g = getComponentGraphics(g);
super.paint(g);
//paint my custom content
}
super.paint calls paintChildren whitch draws the child components. But the child components appear in front of my custom content, and they also sometimes Z fight with each other.
I'm absolutely clueless about what might be causing this.
NOTE: I use setComponentZOrder in my code, and my JPanel takes place in a JScrollPane.
EDIT: The components ZFight even if I never call the setComponentZOrder method.
EDIT 2:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleSelection;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JPanel{
private static final long serialVersionUID = 1L;
public static void main(String[] atgs){
JFrame frame = new JFrame("ZFightingExample");
frame.setSize(new Dimension(500,500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ExamplePanel panel = new ExamplePanel();
frame.add(panel);
Example a = new Example(new Rectangle(5,5,50,50)),
b = new Example(new Rectangle(40,40,50,50));
panel.add(a);
panel.add(b);
frame.setVisible(true);
}
public Example(Rectangle bounds){
super();
setBounds(bounds);
}
public void paint(Graphics g){
super.setBackground(Color.GREEN);
g.fillRect(0, 0, getWidth()-1, getHeight()-1);
super.paint(g);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
}
}
class ExamplePanel extends JPanel{
private static final long serialVersionUID = 1L;
public ExamplePanel(){
super(null);
accessibleContext = new Accessiblecontext();
};
protected class Accessiblecontext extends AccessibleJPanel implements AccessibleSelection{
private static final long serialVersionUID = 1L;
public int getAccessibleSelectionCount() {return 2;}
public Accessible getAccessibleSelection(int i) {return (Accessible)getComponent(i);}
public boolean isAccessibleChildSelected(int i) {return true;}
public void addAccessibleSelection(int i) {}
public void removeAccessibleSelection(int i) {}
public void clearAccessibleSelection() {}
public void selectAllAccessibleSelection() {}
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);//Should be in front of the Green boxes...
g.drawRect(10, 10, 75, 75);
}
}
I want it to paint several rectangles and texts in front of it's child components.
Normally you override paintCompnent() to do custom painting.
The question is what does "in front" mean to you? If it means what I think it means then you need to do the painting after the child components have been painted. So you basic approach to override paint() is correct.
public void paint(Graphics g){
g = getComponentGraphics(g);
super.paint(g);
//paint my custom content
}
The problem with the above code is that you don't use the Graphics object passed to the painting method. So your code should be:
public void paint(Graphics g)
{
//g = getComponentGraphics(g);
super.paint(g); // use the Graphics object passed to the method
//paint my custom content
g.drawRect(10, 10, 20, 20);
}
I use setComponentZOrder in my code,
Why are you playing with ZOrder?
Edit:
g.setColor(Color.BLUE);//Should be in front of the Green boxes...
As I first stated in my answer, normally (99% of the time) custom painting is done by overriding the paintComponent() method of the panel.
The problem is with the Example class:
override paintComponent() not paint()
the first statement when you override a painting method should be super.???.
don't set properties of the class in the painting method.
So the code might look something like:
public Example(Rectangle bounds){
super();
setBounds(bounds);
setBackground(Color.GREEN);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth()-1, getHeight()-1);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
}
Note you don't event need to do any custom painting with the Example class. Instead your code could be something like:
ExamplePanel panel = new ExamplePanel();
panel.setLayout( null ); // now you set the size/location of any component you add to the panel
JPanel example1 = new JPanel();
example1.setBackground( Color.GREEN );
example1.setBorder( new LineBorder(Color.BLACK) );
example1.setBounds( new Rectangle(....) );
panel.add(example1);
Also, another solution for the ExamplePanel class might be to use a JLayer. The JLayer class allows you to add all kinds of fancy decorations to a component. Check out the Swing tutorial on How to Decorate Components With The JLayer Class.
I'm just going through some basic tutorials at the moment. The current one wants a graphics program that draws your name in red. I've tried to make a NameComponent Class which extends JComponent, and uses the drawString() method to do this:
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Color;
import javax.swing.JComponent;
public class NameComponent extends JComponent {
public void paintMessage(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.drawString("John", 5, 175);
}
}
and use a NameViewer Class which makes use of JFrame to display the name:
import javax.swing.JFrame;
public class NameViewer {
public static void main (String[] args) {
JFrame myFrame = new JFrame();
myFrame.setSize(400, 200);
myFrame.setTitle("Name Viewer");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
NameComponent myName = new NameComponent();
myFrame.add(myName);
myFrame.setVisible(true);
}
}
...but when I run it, the frame comes up blank! Could anyone let me know what I'm doing wrong here?
Thanks a lot!
You need to override the method paintComponent rather than paintMessage. Adding the #Override annotation over the method will show that paintMessage is not a standard method of JComponent. Also you may want to reduce the y-coordinate in your drawString as the text is currently not visible due to the additional decoration dimensions of the JFrame. Finally remember to call super.paintComponent to repaint the background of the component.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.drawString("John", 5, 100);
}
See: Painting in AWT and Swing
You need to add this line after public void paintMessage(Graphics g){ :
super.paint(g);
This tells Java to use the superclass (JComponent) to paint the message.
You will also need to call your method paintComponents() rather than paintMessage()
package donut;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class Board extends JPanel{
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
RenderingHints rh =
new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHints(rh);
Dimension size = getSize();
double w = size.getWidth();
double h = size.getHeight();
Ellipse2D e = new Ellipse2D.Double(0, 0, 80, 130);
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.gray);
for (double deg = 0; deg < 360; deg += 5) {
AffineTransform at =
AffineTransform.getTranslateInstance(w / 2, h / 2);
at.rotate(Math.toRadians(deg));
g2.draw(at.createTransformedShape(e));
}
}
}
Then The JFrame Extended Class Where Board Object is instantiated
package donut;
import javax.swing.JFrame;
public class Donut extends JFrame {
public Donut() {
add(new Board());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(360, 310);
setLocationRelativeTo(null);
setTitle("Donut");
setVisible(true);
}
public static void main(String[] args) {
new Donut();
}
}
I was expecting to See Line Like this : new Board().paint(graphicsObject) So Where Actually This Line is executed Or in a proper way Where actually paint(Graphics g) function is called ?!
If you want to follow the invocation stack to paint(), simply write new Throwable().printStackTrace() or Thread.dumpStack(), this will allow you to follow the calling-stack.
Otherwise, have a look at RepaintManager.addDirtyRegion(JComponent, int, int, int, int);
Anyway, when you are painting to the screen, you should never call paint/paintComponent/paintXXX methods. Only call repaint().
You cannot rely on "when" your method paintComponent(Graphics) or paint(Graphics) will be invoked.
paint is automatically called by Swing whenever it is needed, for example when the component becomes visible (for the first time, or after a minimize of the window, etc), or when the window is resized, basically whenever the contents of a component need to be painted. You should never explicitly call paint in your code, if you wish to force paint then you should call repaint instead.
This link might be helpful
P.S. The code of paint method that is called by super.paint(g) resides in JComponent class, which is extended by JPanel (which is extended by your Board class).