Search code examples
javaswinggraphicsjframegraphics2d

How to see if a something in Graphics2D is off the frame


I have a paint method that I have draw a rectangle and move it across the screen and what I want it to do I when the rectangle goes off the screen to move it back to the start of the JFrame. I assume it would be something like if(rectangle.isoffthescreen){ put it back on the screen } but I don't know how to do that. Also, I want to know if you can do something to the rect like JFrame frame = new JFrame();, but for obviously for the rectangle. I'm sorry if this is confusing.

@MadProgrammer Here is where I am at so far

public class main extends JPanel {

public static int place = -350;
public Rectangle rect;
public int xDelta;
   public main() {

       rect = new Rectangle(0, 75, 50, 50);
       xDelta = 4;
       Timer timer = new Timer(40, new ActionListener() {
           @Override
           public void actionPerformed(ActionEvent e) {
               rect.x += xDelta;
               if (rect.x + rect.width > getWidth() - 1) {
                   rect.x = getWidth() - rect.width;
                   xDelta *= -1;
               } else if (rect.x < 0) {
                   rect.x = 0;
                   xDelta *= -1;
               }
               repaint();
           }
       });
       timer.start();

   }

public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g.create();
    Random r = new Random();
    int r1;

    r1 = r.nextInt(5);
    if (r1 == 0) {
        g2d.setColor(Color.WHITE);
    } else if (r1 == 1) {
        g2d.setColor(Color.BLUE);
    } else if (r1 == 2) {
        g2d.setColor(Color.RED);
    } else if (r1 == 3) {
        g2d.setColor(Color.GREEN);
    } else if (r1 == 4) {
        g2d.setColor(Color.PINK);
    } else {
        g2d.setColor(Color.CYAN);
    }

    place += 50;

    rect = new Rectangle(place, 100, 300, 200);
    g2d.draw(rect);
    g2d.fill(rect);
    g2d.dispose();

    try {
        Thread.sleep(400);
    } catch (Exception e) {
    }

    repaint();

}
}

and

public class frame {

public static JFrame frame;


public static void main(String args[]){
    frame = new JFrame();   
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //frame.setResizable(false);
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);
    main m = new main();
    m.setBackground(Color.BLACK);
    frame.add(m);
}


}

I still can't get it to work.


Solution

  • First of, you should avoid overriding paint of top level containers and instead use something the extends from JComponent (like JPanel) and override it's paintComponent.

    There are a number of reasons, but in your case, the frame contains a decoration which sits inside the viewable area.

    The basic process would be to check edge cases...

    if (box.x + box.width > getWidth() - 1) {
        // The boxes right edge is beyond the right edge of it's container
    } else if (box.x < 0) {
        // The boxes left edge is beyond the left edge of it's container
    }
    

    This checks to see if the box's right edge is beyond the containers right edge and if the box's left edge is beyond the left edge of the container.

    It would be a simple process to included vertical checking as well.

    Updated with example

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Move {
    
        public static void main(String[] args) {
            new Move();
        }
    
        public Move() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private Rectangle box;
            private int xDelta;
    
            public TestPane() {
    
                box = new Rectangle(0, 75, 50, 50);
                xDelta = 4;
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        box.x += xDelta;
                        if (box.x + box.width > getWidth() - 1) {
                            box.x = getWidth() - box.width;
                            xDelta *= -1;
                        } else if (box.x < 0) {
                            box.x = 0;
                            xDelta *= -1;
                        }
                        repaint();
                    }
                });
                timer.start();
    
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(Color.BLUE);
                g2d.fill(box);
                g2d.dispose();
            }
        }
    
    }
    

    Update from OP's example code

    Immediately, a number of things worry me...

    1. Overriding paint
    2. Calling Thread.sleep in the paint method
    3. Calling repaint from within the paint method
    4. Creating a new Rectangle in the paint method
    5. The reliance on the place variable

    Check out Performing Custom Painting for more details about painting in Swing

    You should never block or perform long running processing the Event Dispatching Thread, this will prevent the EDT from processing (amongst other things) paint requests and new events. By calling Thread.sleep in the paint method, you are preventing Swing from updating the screen.

    Check out Concurrency in Swing for more details.

    Calling repaint (or any method that might call repaint) within a paint method is a sure way to consume you CPU cycle.

    You may want to check out Painting in AWT and Swing for more details about the paint process in Swing

    By creating a new Rectangle in the paint method, you are throwing away any changes that the Timer has made, effectively stopping you rectangle from moving effectively...

    The place method is not required. Animation is the illusion of change over time, hence the use of the Timer and xDelta.

    Updated based on your code example

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Move {
    
        public static void main(String[] args) {
            new Move();
        }
    
        public Move() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new Main());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public static class Main extends JPanel {
    
            public static int place = -350;
            public Rectangle rect;
            public int xDelta;
    
            public Main() {
    
                rect = new Rectangle(0, 75, 50, 50);
                xDelta = 4;
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        rect.x += xDelta;
                        if (rect.x + rect.width > getWidth() - 1) {
                            rect.x = getWidth() - rect.width;
                            xDelta *= -1;
                        } else if (rect.x < 0) {
                            rect.x = 0;
                            xDelta *= -1;
                        }
                        repaint();
                    }
                });
                timer.start();
    
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                Random r = new Random();
                int r1;
    
                r1 = r.nextInt(5);
                if (r1 == 0) {
                    g2d.setColor(Color.WHITE);
                } else if (r1 == 1) {
                    g2d.setColor(Color.BLUE);
                } else if (r1 == 2) {
                    g2d.setColor(Color.RED);
                } else if (r1 == 3) {
                    g2d.setColor(Color.GREEN);
                } else if (r1 == 4) {
                    g2d.setColor(Color.PINK);
                } else {
                    g2d.setColor(Color.CYAN);
                }
    
    //            place += 50;
    
    //            rect = new Rectangle(place, 100, 300, 200);
                g2d.draw(rect);
                g2d.fill(rect);
                g2d.dispose();
    
            }
        }
    }