repaint() not calling paintComponent() in java - java

I am writing what should be a simple piece of code that creates a JFrame object and then paints the background black and draws a blue square. However, the repaint() method is not calling the paintComponent() method.
This is the code:
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Container;
public class Snake extends JPanel{
private Vector xCoords = new Vector();
private Vector yCoords = new Vector();
public Snake(){
xCoords.add(150);
yCoords.add(150);
}
public void startJFrame(){
JFrame window = new JFrame();
window.setSize(300, 300);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = window.getContentPane();
c.setBackground(Color.black);
}
public void paintRequest(){
System.out.println("Request to paint received.");
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println("paintComponent was called");
g.setColor(Color.blue);
int x = (int)xCoords.get(0);
int y = (int)yCoords.get(0);
g.fillRect(x, y, 10, 10);
}
public static void main(String[] args){
Snake mkFrame = new Snake();
mkFrame.startJFrame();
mkFrame.paintRequest();
}
}
I know that paintRequest() is being called properly because it prints "Request to paint received", but "paintComponent was called" is never printed. On the gui side, the JFrame window is created and it has a black background, but there is no blue square. Thank you in advance for the help.

There is no Snake ever added to the frame!
Change:
JFrame window = new JFrame();
To:
JFrame window = new JFrame();
window.add(new Snake());

Related

Java JFrame rectangle in window

so i'm trying to put Rectangle2D.Float in window using JFrame but when i'm compiling code i'm getting just blank window without rectangle. Can you guys take look on it and tell me what i'm doing wrong?
package zestaw8;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
class Plansza85 extends JPanel
{
Shape figura;
Plansza85(Shape figura)
{
this.figura=figura;
}
}
public class Zestaw8_cw85
{
public static void main(String[] args)
{
Shape obj1;
obj1=new Rectangle2D.Float(100,100,140,140);
zestaw8.Plansza85 p;
p=new zestaw8.Plansza85(obj1);
JFrame jf=new JFrame();
jf.setTitle("Plansza p");
jf.setSize(400,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
jf.add(p);
}
}
You seem to have a misunderstanding of how painting works in Swing.
Start by looking at Performing Custom Painting, Painting in Swing and 2D Graphics. Rectangle2D is a graphics primitive, which needs to be painted through the normal custom painting process
As per the common recommendations of Performing Custom Painting you should override the paintComponent method of the Plansza85 and paint the Shape through the Graphics2D API, something like...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Shape obj1;
obj1 = new Rectangle2D.Float(100, 100, 140, 140);
Plansza85 p;
p = new Plansza85(obj1);
JFrame jf = new JFrame();
jf.setTitle("Plansza p");
jf.add(p);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
}
});
}
class Plansza85 extends JPanel {
Shape figura;
Plansza85(Shape figura) {
this.figura = figura;
}
#Override
public Dimension getPreferredSize() {
if (figura == null) {
return super.getPreferredSize();
}
Rectangle2D bounds = figura.getBounds2D();
double width = bounds.getMaxX();
double height = bounds.getMaxY();
return new Dimension((int)width + 1, (int)height + 1);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getForeground());
g2d.draw(figura);
g2d.dispose();
}
}
}
for example.
I've also overridden the getPreferredSize method to generate an appropriate sizing hint for the component based on the size of the shape, I've done this because I dislike guess work and the window also includes variable sized borders and title bars which will change the size the panel if you only rely on setSize
You need to override the paintComponent method of Plansza85
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
class Plansza85 extends JPanel {
private Shape figura;
Plansza85(Shape figura) {
this.figura = figura;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw(figura);
}
}
public class Zestaw8_cw85 {
public static void main(String[] args) {
Shape obj1;
obj1 = new Rectangle2D.Float(100, 100, 140, 140);
Plansza85 p;
p = new Plansza85(obj1);
JFrame jf = new JFrame();
jf.setTitle("Plansza p");
jf.setSize(400, 400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(p);
jf.setVisible(true);
}
}
Hope it helps!

Painting inside Swing Timer not working

I never worked with Timers before so my problem is probably stupid one really. My program draws a circle which is red and after random seconds the circle should change its color to green. I just made a swing timer as you can see below in the code. And it enters actionPerformed() method but it doesn't change color. Could you help me somehow fix my problem with changing colors?
My code:
package igrica;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ChangingCircle implements ActionListener{
JFrame frame;
Timer timer;
Random r;
public static void main(String[] args) {
ChangingCircle gui = new ChangingCircle();
gui.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillOval(100, 100, 100, 100);
Random r = new Random();
Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
public void actionPerformed(ActionEvent ev) {
System.out.println("Timer out");
g.setColor(Color.green);
g.fillOval(100, 100, 100, 100);
}
});
timer.start();
}
}
}
There's quite the mess in your code. Try this:
public class ChangingCircle {
Color color = Color.RED;
MyPanel panel = new MyPanel();
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
ChangingCircle gui = new ChangingCircle();
gui.go();
});
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
Random r = new Random();
Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
public void actionPerformed(ActionEvent ev) {
System.out.println("Timer");
color = Color.GREEN;
panel.repaint();
}
});
timer.setRepeats(false);
timer.start();
}
class MyPanel extends JPanel {
private int size = 100, loc = 100;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(loc, loc, size, size);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(size + loc, size + loc);
}
}
}
The idea is that the timer only changes the property of the shape to be drawn and then calls repaint() to reflect the change. The paintComponent is called whenever it is needed, even in quick succession and should return quickly.
Specific Notes:
Start Swing from the EDT.
Create and start the timer from outside of paintComponent since it is called many times and that will create and start many timers.
You should probably set the timer not to repeat.
Call super.paintComponent(g); as the first thing inside paintComponent.
You seem to have an ActionListener that does nothing.
General tips:
Use the #Override annotation when applicable.
Call pack() on the frame instead of setting its size manually and #Override the getPreferredSize method of the component you paint on. Return a meaningful size based on what you draw.
Use add(component, location) and not the other way around (deprecated).
Don't use fields when local variables will do (Random r for example).
Use uppercase constant names (Color.RED instead of Color.red).
Don't initiate a Timer from within a paintComponent method. This method should be for painting and painting only. Instead start the Timer in your constructor and within your Timer's actionPerromed and call repaint(), change the state of a field of the class, and use that information within the paintComponent use that field to draw any new information.
e.g.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ChangingCircle {
JFrame frame;
public static void main(String[] args) {
ChangingCircle gui = new ChangingCircle();
gui.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
class MyPanel extends JPanel {
private Random r = new Random();
private boolean draw = false;
public MyPanel() {
Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
public void actionPerformed(ActionEvent ev) {
draw = true;
repaint();
}
});
timer.setRepeats(false);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (draw) {
g.setColor(Color.red);
g.fillOval(100, 100, 100, 100);
}
}
}
}
Also, don't forget to call the super's paintComponent method from within your override.
If you need to change colors, give the JPanel a Color field, say called color and change it's value from within the Timer, and then call repaint(). Again within paintComponent, use the value of that field to draw the oval with. Also in this situation, the Timer should repeat, so get rid of timer.setRepeats(false) in that situation.
The timer works asynchronously and paintComponent finishes before finishing the work of timer.

Drawing to a Panel from separate classes

I have been trying to learn how to draw to a Jpanel for a game. I want to draw to it from different classes (like a class that manages maps and a class that manages player models).
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main
{
public static void main (String[] args)
{
JFrame frame = new JFrame ("Java Game");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (1000, 600);
JPanel panel = new JPanel();
panel.setBackground (Color.WHITE);
Dimension size = new Dimension(1000,500);
panel.add (new Player()); // Class with paintComponent method.
panel.setPreferredSize(size);
panel.setBackground(Color.BLUE);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
}
next class
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
#SuppressWarnings ("serial")
public class Player extends JComponent
{
int x = 50;
int y = 450;
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.setColor (Color.BLACK);
g.fillRect (x, y, 50, 50);
}
}
You probably want to extend JPanel. It's already opaque, and it can handle the background color for you. Also give your panel a size like they do here, then you can do the drawing relative to the size.
Player p = new Player();
p.setBackground(Color.cyan);
frame.add(p);
frame.pack();
frame.setVisible(true);
…
public class Player extends JPanel {
private static final int X = 320;
private static final int Y = 240;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(getWidth() / 2 - 25, getHeight() / 2 - 25, 50, 50);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(X, Y);
}
}

Why is graphics not showing on my JFrame / JPanel?

When I run this code. The result is a window with the name. Fully blank. I tried editing background color and adding graphics (rectangle) etc but the same result keeps occurring .
Question: This ends up as a white screen on a window. No graphics or background color. Even though I added it to panel and added panel. How do I fix this?
Main.java
package ball.tec.main;
import javax.swing.JFrame;
import ball.tec.frame.Frame;
public class Main {
public static void main(String[] args) {
String Version = "0.1.2";
Frame f = new Frame();
f.setVisible(true);
f.add();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.setSize(1500, 1000);
f.setTitle("RedBall V: " + Version);
}
}
Frame.java
package ball.tec.frame;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame{
private static final long serialVersionUID = 1L;
public boolean debug = false;
//Creating panel object
JPanel panel = new JPanel();
//Graphics displayed
public void paintComponent(Graphics g) {
//Firstly Nothing pops up
g.setColor(Color.RED);
g.drawRect(20, 40, 10, 10);
//And this doesn't work.
this.setBackground(Color.RED);
}
//Add everything to 'panel'
public void add() {
add(panel);
//Even if I put it here it doesn't work ;-;
this.setBackground(Color.RED);
this.pack();
}
}
You don't use paintComponent() in a JFrame. What you probably intended to do was create a third class, extending JPanel. Add your paintComponent() there.
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(20, 40, 10, 10);
this.setBackground(Color.RED);
}
}
f.add(new MyPanel());

How to draw Graphics2D on JPanel which is inside another JPanel?

I would like to create 4 JPanels, draw a white rectangular on each
and then put them inside one, big JPanel. Big JPanel is inside the main frame.
However, the following code does not work. Please, tell me, how to fix this problem?
import javax.swing.*;
import java.awt.Graphics;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
public class Main extends JFrame
{
public void GUI () {
setBounds(0, 0, 480, 960);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
setMinimumSize(new Dimension(480, 960));
setResizable(false);
JPanel mainPanel = new JPanel();
GridLayout GL = new GridLayout(4,0);
mainPanel.setLayout(GL);
JPanel panel1 = new MyCanvas();
JPanel panel2 = new MyCanvas();
JPanel panel3 = new MyCanvas();
JPanel panel4 = new MyCanvas();
mainPanel.add(panel1);
mainPanel.add(panel2);
mainPanel.add(panel3);
mainPanel.add(panel4);
add(mainPanel);
setVisible(true);
}
public static void main(String args[]) throws IOException
{
new Main().GUI();
}
class MyCanvas extends JPanel {
public void drawCanvas(Graphics g) {
super.paintComponent( g ); // call superclass's paintComponent
Graphics2D g2 = ( Graphics2D ) g; // cast g to Graphics2D
g2.setColor(Color.WHITE);
double x = 100;
double y = 100;
double width = x + 200;
double height = y + 50;
g2.fillRect(50, 50, 380, 200);
}
}
}
What is this supposed to do?:
public void drawCanvas(Graphics g) {
....
}
This method overrides no JPanel drawing method and so will not routinely get called when the JVM decides to paint your MyCanvas JPanel.
I think that instead you want to override the class's paintComponent(...) method which can easily be done by simply renaming your method to paintComponent(...). If/when you do this, don't forget to use the #Override annotation to be sure that you're overriding the method with the correct signature. You'll also want to change the method's access specifier to protected, not public.
Next you'll want to do something with those double variables that you're creating.

Categories