Repaint() not calling paintComponent() Java - java

I'm trying to remake Snake to improve my programming, Ive been reading about other people having the same problem for hours but none of them seem to be similar to my own code. Here is my relevant code:
package snake;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PlayGame extends JPanel implements Runnable{
private JFrame jfr;
private JPanel jpn;
PickupBall b = new PickupBall();
Snake bob = new Snake();
public PlayGame(){
jfr = new JFrame("Snake");
jfr.setSize(640,640);
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jpn = new JPanel();
jpn.setBackground(Color.WHITE);
jfr.add(jpn);
jfr.setVisible(true);
}
#Override
public void run(){
while(true){
repaint();
}
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
b.draw(g);
}
public static void main(String[] args) {
PlayGame p = new PlayGame();
Thread t = new Thread(p);
t.start();
}
}
Everything works, the while(true) loop is initiated, but nothing happens.
package snake;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class PickupBall {
//constructor
public PickupBall(){
xPos = (int) (((Math.random()*31)+1)*20);
yPos = (int) (((Math.random()*31)+1)*20);
}
//constants
public final int balletjeSides = 20;
//variables
public int xPos;
public int yPos;
//methods
public void draw(Graphics g){
g.setColor(Color.RED);
g.fillRoundRect(this.xPos, this.yPos, balletjeSides, balletjeSides, 5, 5);
}
}
What am I missing?

just add jfr.setContentPane(this); within your onstructor, as what #Berger said, you actually have a JPanel, PlayGame instance here, but the JFrame you´re creating doesn´t use this JPanel instance, but instead simply adds an empty JPanel, called jpn in your code, to your jfr which doesn´t have any content.
The new constructor could look like this:
private JFrame jfr;
//private JPanel jpn;
PickupBall b = new PickupBall();
//Snake bob = new Snake();
public PlayGame() {
jfr = new JFrame("Snake");
jfr.setSize(640, 640);
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//jpn = new JPanel();
this.setBackground(Color.WHITE);
//jfr.add(jpn);
jfr.setContentPane(this);
jfr.setVisible(true);
}
As you see, i commented out the jpn variable, as the actual JPanel you´d like to work with (my guess) is the PlayGame class itself, and not an JPanel defined within this class.

Related

shapes won't show up on my GUI JFrame

heres what my code looks like
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
MyDrawPanel shape = new MyDrawPanel();
frame.getContentPane().add(shape);
frame.setSize(500,500);
frame.setVisible(true);
}
}
class MyDrawPanel extends JPanel{
public void paintComponent (Graphics g) {
g.setColor(Color.ORANGE);
g.fillRect(20, 50, 100, 100);
}
}
When I run it, the only thing that shows up is the frame, not the actual shape. Is there something I'm missing?
Note that this answer does not answer your direct question of why your posted code doesn't work, because while your code has problems, it should still display the square. But having said that, this post is meant to offer some suggestions on "better" practices:
Avoid magic values and magic numbers
Use #Override annotations for any method that you think is an override
The paintComponent method is protected, not public
Call the super's method in your override
Best to override getPreferredSize of the JPanel if you need to fix its size
Start the Swing GUI on the Swing event thread for thread-safety
Avoid hard-coding your graphic drawing positions, especially if you're thinking of animating it at a later date
This is a better representation of your code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class Test2 extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color RECT_COLOR = Color.ORANGE;
private static final int RECT_WIDTH = 100;
private static final int INIT_X = 20;
private static final int INIT_Y = 50;
private int rectX = INIT_X;
private int rectY = INIT_Y;
public Test2() {
// TODO any initialization code goes here
}
// override annotation
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// avoid magic values and numbers
g.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, RECT_WIDTH, RECT_WIDTH);
}
// best way to set size safely
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Test2 mainPanel = new Test2();
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
// be sure to start the GUI on the event thread
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Swing Java repaint not working using 2 jpanels

As you can see from the code I am expecting to see a rectangle on DrawingPanel but I am not sure why repaint() method is not working. Any help will be much appreciated. I also tried revalidate method but that is not working either.
Here are my Classes:
import javax.swing.*;
import java.awt.*;
public class Designer extends JFrame {
static JFrame f = new Designer();
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
DrawingPanel drawingPanel = new DrawingPanel();
PropertyPanel propertyPanel = new PropertyPanel();
public Designer(){
Rectangle bounds = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getMaximumWindowBounds();
splitPane.setTopComponent(propertyPanel);
splitPane.setBottomComponent(drawingPanel);
add(splitPane, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(bounds);
setVisible(true);
}
public static void main(String[] args) {
System.out.println("App started...");
}
}
Class for first Jpanel: PropertyPanel.Java
import javax.swing.*;
import java.awt.event.*;
public class PropertyPanel extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public PropertyPanel(){
JButton addShapesBtn = new JButton("Add");
addShapesBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
drawingPanel.addRectangle();
}
});
add(addShapesBtn);
}
}
Class for second Jpanel: DrawingPanel.Java
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class DrawingPanel extends JPanel{
private List<Rectangle> squares = new ArrayList<Rectangle>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
System.out.println("painting");
for (Rectangle rect : squares) {
g2.draw(rect);
}
}
public void addRectangle() {
Rectangle rectx = new Rectangle(10, 10, 100, 100);
squares.add(rectx);
repaint(); <-- this is not working
}
}
Your repaint works fine. Your problem is that you're calling addRectangle() to the wrong DrawingPanel instance, not the one that is currently displayed in the GUI. To solve this, pass a reference from the displayed one to the code that needs to call the method.
To see that this is correct, simply search this page for new DrawingPanel(). You should see this only once in your own code (and your code posted). You see it twice meaning you've created two instances of this.
e.g., change this:
public class PropertyPanel extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public PropertyPanel(){
to this:
public class PropertyPanel extends JPanel {
private DrawingPanel drawingPanel; // don't create new
public PropertyPanel(DrawingPanel drawingPanel){
this.drawingPanel = drawingPanel;
and then pass in the true DrawingPanel into this object on creation:
DrawingPanel drawingPanel = new DrawingPanel();
PropertyPanel propertyPanel = new PropertyPanel(drawingPanel);
Better still: structure your code in a M-V-C way, and use dependency injection to make connections -- but this may be overkill for your simple GUI.

Java: having trouble calling a method from one class into another

Still trying to grasp how classes and methods work in Java. To experiment, I tried to create a graphics class, with a void draw box method inside. Then, I try to call that method in the main method to try to draw those boxes. I'm getting "cannot be resolved to variable" errors which I believe means the main class can't see my other class for some reason?
Boxymain.java:
import java.awt.*;
import javax.swing.JFrame;
public class Boxymain extends Canvas {
public static void main(String[] args){
BoxyMethod c = new BoxyMethod();
c.drawBox(window, Color.RED, 200, 300);
JFrame win = new JFrame("Boxy Main");
win.setSize(800,600);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Boxymain canvas = new Boxymain();
win.add(canvas);
win.setVisible(true);
}
}
BoxyMethod.java:
import java.awt.*;
import javax.swing.JFrame;
public class BoxyMethod {
public void drawBox(Graphics window, Color c, int x, int y){
window.setColor(c);
window.fillRect(x, y, 100, 100);
window.setColor(Color.WHITE);
window.fillRect(x+10,y+10,80,80);
}
}
Error text: "window cannot be resolves to a variable."
The error message is telling you exactly what is wrong. You're passing in a window variable into the drawBox method, but you don't declare or initialize such a variable in the main method before doing so, and so this cannot be done in Java.
BoxyMethod c = new BoxyMethod();
// *** window variable below is used but never declared prior to use
c.drawBox(window, Color.RED, 200, 300);
More importantly though, you're not doing Swing drawing correctly.
Instead, you should create a class that extends JPanel, give it a paintComponent(Graphics g) method override, and draw in that method. Then place that JPanel in a JFrame and display the JFrame. Please check out the Performing Custom Painting Swing graphics tutorial for more detail on how to do Swing graphics.
As an aside, do not follow that tutorial that you've linked to as it is 30 years out of date.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class BoxyTest {
private static void createAndShowGui() {
JFrame frame = new JFrame("Boxy Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new BoxyPanel(200, 300));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class BoxyPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private int myX;
private int myY;
public BoxyPanel(int myX, int myY) {
this.myX = myX;
this.myY = myY;
}
#Override // so my JPanel will be big enough to see
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
// call super method so that the JPanel can do housekeeping painting
super.paintComponent(g);
g.fillRect(myX, myY, 100, 100);
g.setColor(Color.WHITE);
g.fillRect(myX + 10, myY + 10, 80, 80);
}
}

AWT graphics, object disappears briefly

I am trying to learn how to make a graphics program, but some of the methods in java AWT are giving me unexpected results.
I have made a window, and I place a rectangle and that works. I want another figure, a circle, to appear after 1 second. I have tried the wait(x) method, which just places the circle immediately, and now I have tried the Thread.sleep(x) method, which does work, however I get the following behaviour:
After one second, the circle is displayed on the screen, but after a split second it disappears again, and another split second later it reappears and stays on the screen. I don't want it to temporarily disappear. What am I doing wrong?
import java.awt.*;
class Example extends Canvas{
public static void main(String[] args){
Example graphicProgram = new Example();
Frame graphics = new Frame();
graphics.setSize(300, 300);
graphics.add(graphicProgram);
graphics.setVisible(true);
}
public Example(){
setSize(200, 200);
setBackground(Color.white);
}
public void paint(Graphics g){
g.fillRect(20, 150, 100, 100);
try{
Thread.sleep(1000);
} catch (Exception ex){
}
g.fillOval(150, 20, 100, 100);
}
}
Never call Thread.sleep from within a paint type of method. Doing this will make your GUI completely unresponsive.
Yes, do call the super painting method from within your painting method (as per muhammad's answer).
You should not call Thread.sleep(...) from the event thread either as this too will freeze your application.
You should skip doing AWT and move to Swing.
When you do so, do your drawing in the paintComponent(Graphics g) method of a JComponent or JPanel object.
Call the super's paintComponent(g) within your paintComponent method override.
Use a Swing Timer to do any delay or animation.
e.g.,
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 java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class DrawFoo extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Stroke BASIC_STROKE = new BasicStroke(3f);
private static final Color RECT_COLOR = Color.blue;
private static final Color OVAL_COLOR = Color.red;
private boolean drawCircle = false;
private int rectX = 20;
private int rectY = 150;
private int rectWidth = 100;
public DrawFoo() {
int delay = 1000;
Timer timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
drawCircle = true;
repaint();
}
});
timer.setRepeats(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(BASIC_STROKE);
g2.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, rectWidth, rectWidth);
if (drawCircle) {
g2.setColor(OVAL_COLOR);
g.fillOval(rectY, rectX, rectWidth, rectWidth);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawFoo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
put this line as the first statment in your paint method super.paint(g);
it will be good to place also Graphics2D g2 = (Graphics2D)g; after above statment to use the improved performance and extra methods offered by Graphics2D

Java2D and Swing Not Outputing Images with JFrames and JPanels

I am working on the basics of a graphics program in swing and java2D to practice. I am having a problem wherein I cannot show my images. I have divided my code into 4 classes so that when the program gets larger it's easier to manage.
The idea is that I have very little in the Main, that Frame initializes my first screen, that the screens can all be subdivided into their own classes, TitleScreen being one of these, and PullImage does all of the work of buffering and printing images which bothered me.
When I run this I get an empty window and no errors, so I cannot figure out where the problem is.
Please and Thank you for your help.
Main
package com.game.pack;
import javax.swing.JFrame;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
public final static void main(String[] args)
{
new Frame().initialize();
new TitleScreen().openScreen();
}
}
Frame
package com.game.pack;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame{
private static final long serialVersionUID = 1L;
public final void initialize()
{
JFrame frame = new JFrame("Game");
JPanel panel = new JPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
panel.setSize(800,600);
frame.setLayout(null);
panel.setLayout(null);
frame.setLocationRelativeTo(null);
this.getContentPane().add(panel);
panel.setVisible(true);
frame.setVisible(true);
}
public final void close()
{
dispose();
}
}
TitleScreen
package com.game.pack;
public class TitleScreen {
public void openScreen()
{
new PullImage().printARGB("icons/titleBG.png",800,600,0,0);
new PullImage().printARGBFromSheet("icons/titleButtons.png",
200, 125, 400, 200, 200, 40, 0, 0);
while (1!=2)
{
}
PullImage
package com.game.pack;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
public class PullImage {
public void printARGB(String source, int sizeX, int sizeY, int locX, int locY)
{
Image Icon = new ImageIcon(source).getImage();
BufferedImage BuffedImage = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = BuffedImage.getGraphics();
graphics.drawImage(Icon,locX,locY,null);
}
public void printARGBFromSheet(String source, int sizeX, int sizeY, int locX, int locY, int width, int height, int sheetLocX, int sheetLocY)
{
Image Icon = new ImageIcon(source).getImage();
BufferedImage BuffedImage = new BufferedImage(sizeX,sizeY,BufferedImage.TYPE_INT_ARGB);
Graphics graphics = BuffedImage.getGraphics();
graphics.drawImage(Icon, locX, locY, locX+width, locY+height, sheetLocX, sheetLocY, sheetLocX+width, sheetLocY+height, null);
}
}
One problem lies here:
public final void initialize()
{
this.getContentPane().add(panel);
}
This is setting the content pane of your frame to the panel, not the JFrame you created. Essentially you're not adding it to the actual visible window. Just replace it with
frame.getContentPane().add(panel);

Categories

Resources