-1

I have a simple animation code that creates a meter type rectangle effect. I would like to create it so that it fills a panel completely. I am so close, but it extends past the frame on the bottom. What am I missing?

public class Main {

public static void main(String[] args) {

    JFrame frame = new JFrame("Pong");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new GridLayout(1,2));
    frame.setSize(500, 500);

    //MouseTest test = new MouseTest();
    Test test2 = new Test(frame.getWidth(), frame.getHeight(), frame.getHeight(), 50);
    //frame.add(test);
    frame.add(test2);

    frame.setVisible(true);

    }
}

public class Test extends JPanel implements ActionListener, MouseListener{

int y = 0, width, height, dy=0, maxHeight;
int BOTTOM;
Timer timer;

public Test(int width, int height, int BOTTOM, int SPEED){
    setBackground(Color.BLUE);
    this.width = width;
    maxHeight = height;
    this.BOTTOM = BOTTOM;

    addMouseListener(this);

    timer = new Timer(1000/SPEED, this);
    timer.start();

   }
 public void move(){

    if(y>=maxHeight){
        dy = -1;
    }
    if(y<=0)
    {
        dy = 1;
    }
    y+=dy;
    height+=dy;
    //System.out.println(y);
    repaint();

}

public void paintComponent(Graphics g){

    super.paintComponent(g);
    if(y<=maxHeight/2) {
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height);
    }
    if(y>=maxHeight/2 && y<(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(maxHeight/2));
    }
    if(y>=(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(9*(maxHeight/10)), width, (4*maxHeight)/10);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(9*(maxHeight)/10));
    }
        for(int i = 1; i<6; i++)
            g.fillRect(0, BOTTOM - (i*(maxHeight/5)), width, 10);

    System.out.println(y);



}
J.Law
  • 3
  • 5

4 Answers4

2

Your panel takes up less room than your JFrame, because your frame has a title bar and window borders. You can just query in your paint method for the correct width and height used by the 'JPanel' with your JPanel's getWidth() and getHeight() (in other words, your JFrame's width and height is not the same as your JPanel's width and height, even though the JPanel takes up all the space within the frame visually between the borders).

Alternatively, if you did have logic where this was not possible, you could query the size of the insets of the frame, and subtract the left and right inset values from the width, and pass that as the width, and do the same for the height with the top and bottom inset values.

NESPowerGlove
  • 5,496
  • 17
  • 28
  • My left and rights adjust fine, the top adjust correctly, its just the bottom of the rectangle that extends past the bottom of the frame. – J.Law Jan 27 '15 at 19:43
  • @J.Law It extends out about 10-20 pixels right? You might not notice it, but it's probably also extending a little bit to the the right side as well. I am not sure what OS you are using or desktop manager, but you are probably also adding to the width and height there within the JPanel the extra width and height that comes from the JFrame's insets. – NESPowerGlove Jan 27 '15 at 19:44
  • added the following code `Inset inset = frame.getInsets();` and then called `inset.right` and `inset.top` and `inset.bottom` and still it overhangs. – J.Law Jan 27 '15 at 19:59
  • @J.Law Your problem is that you are drawing too far, you need to restrict how far you draw, and you want to restrict that to how much space the JPanel actually uses. You can do so by not drawing to the height and width of the JFrame the JPanel is in, but to the JPanel's width and height. You could alternatively do the inset approach but that would be redundant. Also you would need to store those inset values somewhere and modify the height and width you created not just call them. Perhaps your real problem is that you wish to figure out how to make the JPanel use the exact space you desire, – NESPowerGlove Jan 27 '15 at 20:10
  • @J.Law but I'm not sure if that is, I'm just answering the question on why your graphics overhang. – NESPowerGlove Jan 27 '15 at 20:10
  • @J.Law No, Nes is right. Don't rely on "magic" numbers, use the panel's width and height when paintComponent is called – MadProgrammer Jan 27 '15 at 20:37
1
  • Override getPreferredSize of your JPanel, this will helps the layout manager determine the best way to layout your component
  • Use JFrame#pack to wrap the frame borders around the view
  • Use getWidth and getHeight to get the actual size the panel. You should do this whenever you need to know these values, don't store them for long periods, as the values can change
  • You should also have a read through Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

This is basic example based on you code...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
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 Test1 {

    public static void main(String[] args) {
        new Test1();
    }

    public Test1() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int yPos;
        private int dy = 1;
        private int bottom = 50;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    move();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(500, 500);
        }

        public void move() {

            if (yPos >= getHeight()) {
                dy = -1;
            }
            if (yPos <= 0) {
                dy = 1;
            }
            yPos += dy;
            repaint();

        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int maxHeight = getHeight();
            int width = getWidth();
            int height = maxHeight;
            if (yPos <= maxHeight / 2) {
                g.setColor(Color.green);
                g.fillRect(0, bottom - yPos, width, height);
            }
            if (yPos >= maxHeight / 2 && yPos < (maxHeight / 10) * 9) {
                g.setColor(Color.green);
                g.fillRect(0, bottom - (maxHeight / 2), width, maxHeight / 2);
                g.setColor(Color.green);
                g.fillRect(0, bottom - yPos, width, height - (maxHeight / 2));
            }
            if (yPos >= (maxHeight / 10) * 9) {
                g.setColor(Color.green);
                g.fillRect(0, bottom - (maxHeight / 2), width, maxHeight / 2);
                g.setColor(Color.green);
                g.fillRect(0, bottom - (9 * (maxHeight / 10)), width, (4 * maxHeight) / 10);
                g.setColor(Color.green);
                g.fillRect(0, bottom - yPos, width, height - (9 * (maxHeight) / 10));
            }
            for (int i = 1; i < 6; i++) {
                g.fillRect(0, bottom - (i * (maxHeight / 5)), width, 10);
            }

        }
    }

}
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

Another way to go is to use pack(). It sets the size of the frame to be the size of the frame's contents. In your code it would look like this:

frame.add(test2);
frame.pack();

If you do it this way, you don't need the frame.setSize() call. You can add the panel either with .add() as you've done or with:

frame.setContentPane(test2);
redeagle47
  • 1,355
  • 4
  • 14
  • 26
  • did you set the size of the panel in the constructor (or through some other method) ? If not, that would cause problems. – redeagle47 Jan 27 '15 at 20:28
-1

So I combined both your comments and got it to work correctly. Here is the code that works.

public class Main {

public static void main(String[] args) {

    JFrame frame = new JFrame("Pong");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new GridLayout(1,2));
    Insets inset = frame.getInsets();


    Test test2 = new Test(200-(inset.right + inset.left), 200 -(inset.top + inset.bottom), 200, 50);
    frame.setContentPane(test2);
    frame.pack();

    frame.setVisible(true);

}
}

public class Test extends JPanel implements ActionListener, MouseListener{

int y = 0, width, height, dy=0, maxHeight;
int BOTTOM;
Timer timer;
Dimension size;
Insets inset;

public Test(int width, int height, int BOTTOM, int SPEED){
    size = new Dimension(width, height);
    setBackground(Color.BLUE);
    setPreferredSize(size);
    inset = this.getInsets();
    this.width = width-(inset.right+inset.left);
    maxHeight = height;
    this.BOTTOM = BOTTOM - (inset.bottom+inset.top);

    addMouseListener(this);

    timer = new Timer(1000/SPEED, this);
    timer.start();

   }
public void move(){

    if(y>=maxHeight){
        dy = -1;
    }
    if(y<=0)
    {
        dy = 1;
    }
    y+=dy;
    height+=dy;
    //System.out.println(y);
    repaint();

}

public void paintComponent(Graphics g){

    super.paintComponent(g);
    if(y<=maxHeight/2) {
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height);
    }
    if(y>=maxHeight/2 && y<(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - (maxHeight / 2), width, maxHeight / 2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(maxHeight/2));
    }
    if(y>=(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(9*(maxHeight/10)), width, (4*maxHeight)/10);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(9*(maxHeight)/10));
    }

    g.setColor(Color.white);
        for(int i = 1; i<6; i++)
            g.fillRect(0, BOTTOM - (i*(maxHeight/5)), width, 5);

    }
J.Law
  • 3
  • 5
  • No, don't rely on magic numbers. When paintComponent is called, use the panel's getWidth and getHeight methods to determine the panel's current size. There are a a umber of things that could effect the size of your panel, frame borders, menus and the current size of the frame. You should be overriding getPreferredSize so as to prevent the component size from been changed, this will allow pack to do its job properly – MadProgrammer Jan 27 '15 at 20:40
  • @MadProgrammer could you show what you mean? I'm interested to see what you're talking about, but not sure I understand. – redeagle47 Jan 27 '15 at 20:45