Null pointer exception when using Graphics in JFrame (Swing) - java

I am slowly learning java, and I have decided to try to build a tic tac toe game. I dove off into trying to draw the board, and I found a simple method to draw lines that everyone said would work. I have this so far:
public void constructBoard() {
JFrame frame = new JFrame("Tic Tac Toe");
frame.setSize(600,600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.toFront();
Graphics lines = new Graphics();
lines = getGraphics();
lines.drawLine(100,100,300,500);
lines.setColor(Color.black);
// JLabel label = new JLabel ("Hello, World!", SwingConstants.CENTER);
// frame.add(label, BorderLayout.CENTER);
}
My JFrame comes up, my title is there, but no line. I have tried multiple things, among which waw a separate method for the line, such as:
public void drawBoard(Graphics lines){
lines = getGraphics();
lines.drawLine(100,100,300,500);
lines.setColor(Color.black);
}
But when I call this in my main class, it tells me I need something between the parentheses to match type Graphics. My compiler (Eclipse) recommends null, but to me, that could be causing the null pointer exception.
I have the construct board method in a Board class, with a constructor Board() with super() inside it.
public Board(){
super();
}
I then have a main class that just makes an object of type Board and calls my methods. I have searched everywhere I know to look, and everywhere says what I have is the way to draw a line. Then others with null pointer exceptions that I found either haven't gotten a solution, or haven't gotten one that works for me. I have tried DebugGraphics, putting it all in the main class, and lines = new Graphics(); but that gives me an error. Thanks for any help.
Full Board class:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Board extends JPanel {
public Board(){
super();
}
public void constructBoard() {
JFrame frame = new JFrame("Tic Tac Toe");
frame.setSize(600,600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.toFront();
Graphics lines = new Graphics();
lines = getGraphics();
lines.drawLine(100,100,300,500);
lines.setColor(Color.black);
// JLabel label = new JLabel ("Hello, World!", SwingConstants.CENTER);
// frame.add(label, BorderLayout.CENTER);
}
}
Full main class:
import java.awt.Color;
import java.awt.Graphics;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Board board = new Board();
board.constructBoard();
}
}

I think you started in a wrong way. Please see below a proof of concept showing you how to actually override the paintComponent method of a JPanel in order to be able to display custom drawn graphical stuff inside it. That is the place where you would have to draw the board.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class App {
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.getContentPane().add(new MainPanel());
frame.setBounds(100, 100, 600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class MainPanel extends JPanel {
MainPanel() {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
int width = getWidth();
int height = getHeight();
drawBoard((Graphics2D) g, width, height);
}
private void drawBoard(Graphics2D g2, int width, int height) {
// TODO: this is the place where you actually want to draw your board
g2.drawRect(10, 10, width - 20, height - 20);
}
}

Related

JComponent not appearing

I'm trying to create a super simple component, and it's not appearing.
Component class:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
public class Player extends JComponent{
public Player()
{
}
public void paint(Graphics g)
{
g.setColor(Color.green);
g.fillRect(40,40,150,150);
}
}
Panel Class im adding it to:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class Game extends JPanel{
public Game()
{
this.setBackground(Color.yellow);
this.setPreferredSize(new Dimension(500,500));
Player p = new Player();
this.add(p);
}
}
And the JFrame:
import javax.swing.JFrame;
public class Launcher {
public static void main(String[] args) {
JFrame frame = new JFrame("Key Collector Demo");
frame.add(new Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
}
}
The only thing showing up is the yellow background.
JFrame and JPanel are working fine; this problem consistently happens to me when building jcomponents. What am I missing?
Any help would be greatly appreciated!
Coordinates that you are using to draw a component are defined in the space of that component.
If you do this:
public void paint(Graphics g)
{
g.setColor(Color.green);
System.out.println(getSize());
g.fillRect(40,40,150,150);
}
You will see that at the moment it is attempted to get drawn its size is 1x1. So drawing it from 40,40 obviously takes it out of the visible area of the component.
Now change the method to:
public void paint(Graphics g)
{
g.setColor(Color.green);
System.out.println(getSize());
setSize(45, 45);
g.fillRect(40,40,150,150);
}
Now you can see small filled rectangle. This is because you forced the size to be 45x45 and now there are 5 pixels to show in the space of the component while the remaining part is still out of the area.
Do not assume the Player panel to have a fixed size.
For a first test your paint method could look like this:
public void paint(Graphics g) {
g.setColor(Color.green);
g.fillRect(0,0,getWidth(),getHeight());
}
The next problem is that the component probably has no size or position. Add a LayoutManager to your panel and add the component:
public Game() {
this.setBackground(Color.yellow);
this.setPreferredSize(new Dimension(500,500));
this.setLayout(new BorderLayout());
Player p = new Player();
this.add(p, BorderLayout.CENTER);
}
With that, your player might take the full space and you see green instead of yellow. Play around with the LayoutManager and the player's preferredSize.

Graphics - Use a parameter (getSize()) to draw a line throughout the whole window

I need help here. I want to give a parameter to the drawLine() method which I get from getSize(). I want to draw a line throughout the whole window by using the getSize() method.
package PROG2;
import java.awt.*;
import javax.swing.*;
class MyComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
g.drawLine(100, 100, 200, 200);
}
}
public class Übung1 extends JFrame{
public static void berechnen() {
int height = frame.getHeight(); //Here it says it doesn't know "frame" variable but I don't know how to declare it here.
int width = frame.getWidth();
}
public static void main(String[] args){
JFrame frame = new JFrame("First window");
berechnen();
frame.add(new MyComponent());
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Graphics g = frame.getGraphics();
// int width = frame.getWidth();
// int height = frame.getHeight();
System.out.println("Größe:" + frame.getSize());
//System.out.println(width);
}
}
As Andrew already stated,
you don't want to get the dimensions or size of the JFrame but rather the component that is being displayed within the JFrame's contentPane, here your MyComponent instance.
The best place to get that information is inside of the paintComponent method itself, just prior to drawing the line.
And always call the super's painting method first
I also recommend:
Draw within a JPanel's paintComponent method, not a JComponent, if you want an opaque image
Avoid static methods and fields unless absolutely needed
Note that in the code below, the red line draws through the JPanel's diagonal, and continues to draw the diagonal, even when the JFrame is manually resized:
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.Stroke;
import javax.swing.*;
public class DrawLine extends JPanel {
private static final Stroke LINE_STROKE = new BasicStroke(15f);
private static final Dimension PREF_SIZE = new Dimension(800, 650);
public DrawLine() {
setPreferredSize(PREF_SIZE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// code to make the line smooth (antialias the line to remove jaggies)
// and to make the line thick, using a wider "stroke"
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(LINE_STROKE);
// if we want a red line
g2.setColor(Color.RED);
// this is the key code here:
int width = getWidth();
int height = getHeight();
// draw along the main diagonal:
g2.drawLine(0, 0, width, height);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
DrawLine mainPanel = new DrawLine();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

how to do auto-resizing drawings in JPanel?

what's the easiest way to have a drawing in a JPanel that resizes whenever the user resizes the JFrame?
I know that I can auto resize the panel with a BorderLayout but the drawings are not resized in this case. I am new to java and GUI programming and there are probably numerous solutions.
please give me a hint into the right direction to make e.g. the rectangle in
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawRect(20, 20, 100, 100);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
DrawRect panel = new DrawRect();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(200, 200));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
auto-resizing whenever the frame is resized.
Provide positions and sizes as a proportion of the width and height of the panel. Whenever the panel is resized, the rendering engine will schedule a call to the paintComponent() method and the rectangle will be drawn proportionally. E.G.
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
#Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
g.drawRect(w/10, h/10, w/2, h/2);
}
/* A custom component should give the layout manager hints as to
its preferred size. */
#Override
public Dimension getPreferredSize() {
return new Dimension(200,200);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
DrawRect panel = new DrawRect();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
frame.getContentPane().setLayout(new BorderLayout());
Insert the line before you add the component to the GUI.
You should study layoutmanagers, since it is a unique concept in Java.

Java JFrame not drawing lines in window

package Main;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
I'm using Java's JFrame. So this isn't recognising the paint method and cant figure out why. I've been looking on YouTube videos and having a look to see if anyone has had similar problems, however everything I've found doesn't seem to help the problem.
when i set the background colour in the main part, it works, bit in paint, it doesn't seem to do anything and leaves it blank.
Its a white line over a black background, so i should easily be able to see it.
Admittedly, I don't know much about Swing (I prefer JavaFX). However, it's clear that your Main class is a JFrame, so you should not make a new one within it. All of those methods you call on display are built in your current class. Basically, within your JFrame you made a new JFrame. However, your paint method was being called on the parent JFrame, which you never made visible. This solves your problem (you may have to fullscreen the window):
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
new Main();
}
public Main() {
int width = 800;
int height = 600;
String title = "Test";
setTitle(title);
setSize(width, height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.WHITE);
g.drawLine(100, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
You are creating an instance of JFrame with
JFrame display = new JFrame();
But the JFrame class has no logic to draw a white line on a black background. That logic is in your custom class Main. So instead, you should create an instance of Main:
JFrame display = new Main();
However, that change along still won't fix the problem because you are setting the background color of the "content pane" but trying to draw directly on the JFrame itself. The preferred solution here is to extend JPanel instead of JFrame and override its paintComponent() method. Then create an instance of your new class to use as the content pain:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainPanel extends JPanel{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setContentPane(new MainPanel());
}
public MainPanel() {
setBackground(Color.black);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
}
}
Notes:
I call setBackground() in the constructor because it does not rely on the Graphics instance passed to paintComponent(). This also avoids the overhead of another function call for each render.
In paintComponent(), I call super.panitComponent(). This allows JPanel to clear the area to be painted and any other necessary initialization.

Why does the JPanel not display on the Frame?

i got the following Code, which is a shortened Version of the actual problem i have:
import javax.swing.*;
import java.awt.*;
public class Circle {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame frame = new JFrame();
Painter panel = new Painter();
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
import javax.swing.*;
import java.awt.*;
public class Painter extends JPanel{
/**
*
*/
private static final long serialVersionUID = 5663520834139683160L;
/**
* #param args
*/
Painter()
{
}
public void drawPlayer(Graphics g)
{
g.setColor(Color.GREEN);
g.fillOval(0, 0, 200, 30);
//g.setColor(Color.GREEN);
//g.drawRect(0, 0, 80, 50);
//g.setColor(Color.BLUE);
//g.fillRect(0, 0, 80/2, 50/2);
//g.setColor(Color.BLACK);
//g.drawString("BOB", 10/2+10, 5/2);
}
#Override
public void printComponent(Graphics g)
{
super.paintComponent(g);
this.drawPlayer(g);
}
}
When I execute it, the JPanel doesnt show up and I just can't find the mistake.
Don't know if this is important, but in the actual problem I initialize the JFrame with its JPanels in the constructor but it doesnt work either.
If necessary I can post the original code. The actual task is to provide a GUI for a ConnectFour game where the Frame is divided up into a JPanel drawing the discs and another JPanel providing player information like name etc. . The first part is working fine but the last part just won't work. (Don't get confuse by this code i posted drawing a circle. I wanted to post the structure of the solution i'm considering for the players information Panel.)
Why does the JPanel not display on the Frame?
It should be overridden paintComponent() method instead of printComponent() method
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.drawPlayer(g);
}

Categories

Resources