Get Width and Height of JPAnel Outside of the Class

get width and height of JPanel outside of the class

So basically what I need is to get new window dimension into the move() method in the Rect class.

Don't know if it is the best design but I pass the "panel" as a parameter to the "move()" method so its width/height can be used.

Here is some old code I have lying around that shows this approach:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

public class BallAnimation4
{
private static void createAndShowUI()
{
BallPanel panel = new BallPanel();

JFrame frame = new JFrame("BallAnimation4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.pack();
frame.setLocationRelativeTo( null );
//frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible( true );

panel.addBalls(5);
panel.startAnimation();
}

public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

class BallPanel extends JPanel implements ActionListener
{
private ArrayList<Ball> balls = new ArrayList<Ball>();

public BallPanel()
{
setLayout( null );
// setBackground( Color.BLACK );
}

public void addBalls(int ballCount)
{
Random random = new Random();

for (int i = 0; i < ballCount; i++)
{
Ball ball = new Ball();
ball.setRandomColor(true);
ball.setLocation(random.nextInt(getWidth()), random.nextInt(getHeight()));
// ball.setMoveRate(32, 32, 1, 1, true);
ball.setMoveRate(16, 16, 1, 1, true);
// ball.setSize(32, 32);
ball.setSize(64, 64);
balls.add( ball );
}
}

@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);

for (Ball ball: balls)
{
ball.draw(g);
}
}

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

public void startAnimation()
{
Timer timer = new Timer(1000/60, this);
timer.start();
}

public void actionPerformed(ActionEvent e)
{
move();
repaint();
}

private void move()
{
for (Ball ball : balls)
{
ball.move(this);
}
}

class Ball
{
public Color color = Color.BLACK;

public int x = 0;
public int y = 0;
public int width = 1;
public int height = 1;

private int moveX = 1;
private int moveY = 1;
private int directionX = 1;
private int directionY = 1;
private int xScale = moveX;
private int yScale = moveY;

private boolean randomMove = false;
private boolean randomColor = false;
private Random myRand = null;

public Ball()
{
myRand = new Random();
setRandomColor(randomColor);
}

public void move(JPanel parent)
{
int iRight = parent.getSize().width;
int iBottom = parent.getSize().height;

x += 5 + (xScale * directionX);
y += 5 + (yScale * directionY);

if (x <= 0)
{
x = 0;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}

if (x >= iRight - width)
{
x = iRight - width;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}

if (y <= 0)
{
y = 0;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}

if (y >= iBottom - height)
{
y = iBottom - height;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
}

public void draw(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, width, height);
}

public void setColor(Color c)
{
color = c;
}

public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}

public void setMoveRate(int xMove, int yMove, int xDir, int yDir, boolean randMove)
{
this.moveX = xMove;
this.moveY = yMove;
directionX = xDir;
directionY = yDir;
randomMove = randMove;
}

public void setRandomColor(boolean randomColor)
{
this.randomColor = randomColor;

switch (myRand.nextInt(3))
{
case 0: color = Color.BLUE;
break;
case 1: color = Color.GREEN;
break;
case 2: color = Color.RED;
break;
default: color = Color.BLACK;
break;
}
}

public void setSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
}

Also, note that for animation you should be using a Swing Timer to schedule the animation. Updates to Swing components should be done on the Event Dispatch Thread (EDT). While not likely to cause a problem with this simple application it is a good habit to make sure this basic rule is followed otherwise you can have random problems and it is never easy to debug a random problem.

How to get JPanel equal width and height

You seem to be under the assumption that the size of frame is the size of the viewable content area.

A frame is made up of the content AND frame decorations. So on my system, a frame of 400x400, results in a content viewable area of 384x362

Frame Size

The first thing you should do is get rid of f.setSize(), it is unreliable as the viewable content area it creates will be different for each system your program runs on. Instead, you should be using f.pack(), which uses the frame contents to determine the size of the window (so that the viewable content area is given precedence).

Next, in you GraphingData class, you will need to override getPreferredSize and return the preferred size of the panel you would like to use.

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

This will allow (some) layout managers to make better decisions about how best to present your component.

set width, height and center JPanel

and the center of the screen.

setSize (700.400); 
setLocationRelativeTo(null);
setVisible(true);
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );

Also, the above statement needs to be executed BEFORE any component is created.

JPanel size is not known on start

Put the calculation into your paintComponent method. In general you want to avoid having code in paintComponent that will slow it down, but these calls shouldn't give too much penalty. Also, if your program is re-sizable, you'll need to be able to re-calculate the sizes of things on the go like this:

public void paintComponent(Graphics g){
super.paintComponent(g);
int x = getWidth() - 50;
int y = getHeight() - 50;
g.fillRect(x, y, 100, 100);
}

but of course in your real program, you will want to avoid "magic" numbers

Another issue: don't call setSize() on your JFrame. Instead, if you want to specify a hard size, do so in the JPanel by overriding its getPreferredSize() method. This will also then give you the suggested parameters that can be used for your calculations.


For example:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

@SuppressWarnings("serial")
public class DrawRect extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private static final int DELTA = 50;
private static final Color RECT_COLOR = Color.red;
private static final int RECT_WIDTH = 100;
private static final int TIMER_DELAY = 15;
private int rectX = PREF_W - DELTA;
private int rectY = PREF_H - DELTA;

public DrawRect() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, RECT_WIDTH, RECT_WIDTH);
}

@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}

private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
rectX--;
rectY--;
repaint();
}
}

private static void createAndShowGui() {
JFrame frame = new JFrame("DrawRect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawRect());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Also, check out the key bindings animation code from this answer of mine.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

public class GamePanel extends JPanel {
private static final int ANIMATION_DELAY = 15;
private final int HEIGHT = 400;
private final int WIDTH = 600;
private Square square;
private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
private Map<Integer, Direction> keyToDir = new HashMap<>();
// !! private Circle circle;
private Timer animationTimer;

public GamePanel() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
keyToDir.put(KeyEvent.VK_UP, Direction.UP);
keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
// !! addKeyListener(new DirectionListener());
setKeyBindings();
setBackground(Color.white);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
square = new Square();
animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener());
animationTimer.start();
}

private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
final InputMap inputMap = getInputMap(condition);
final ActionMap actionMap = getActionMap();
boolean[] keyPressed = { true, false };
for (Integer keyCode : keyToDir.keySet()) {
Direction dir = keyToDir.get(keyCode);
for (boolean onKeyPress : keyPressed) {
boolean onKeyRelease = !onKeyPress; // to make it clear how bindings work
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0,
onKeyRelease);
Object key = keyStroke.toString();
inputMap.put(keyStroke, key);
actionMap.put(key, new KeyBindingsAction(dir, onKeyPress));
}
}
}

public void paintComponent(Graphics g) {
super.paintComponent(g);
square.display(g);
}

private class AnimationListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent evt) {
boolean repaint = false;
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
square.move(dir);
repaint = true;
}
}
if (repaint) {
repaint();
}
}
}

private class KeyBindingsAction extends AbstractAction {
private Direction dir;
boolean pressed;

public KeyBindingsAction(Direction dir, boolean pressed) {
this.dir = dir;
this.pressed = pressed;
}

@Override
public void actionPerformed(ActionEvent evt) {
dirMap.put(dir, pressed);
}
}

private static void createAndShowGUI() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("GamePanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.requestFocusInWindow();
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

enum Direction {
UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
private int incrX;
private int incrY;

private Direction(int incrX, int incrY) {
this.incrX = incrX;
this.incrY = incrY;
}

public int getIncrX() {
return incrX;
}

public int getIncrY() {
return incrY;
}
}

class Square {
private int x = 0;
private int y = 0;
private int w = 20;
private int h = w;
private int step = 1;
private Color color = Color.red;
private Color fillColor = new Color(255, 150, 150);
private Stroke stroke = new BasicStroke(3f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);

public void display(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(fillColor);
g2d.fillRect(x, y, w, h);
g2d.setStroke(stroke);
g2d.setColor(color);
g2d.drawRect(x, y, w, h);
g2d.dispose();
}

public void setStep(int step) {
this.step = step;
}

public void move(Direction dir) {
x += step * dir.getIncrX();
y += step * dir.getIncrY();
}

}

In Java, what is the default JPanel height and width?

I think the JPanel by itself has a prefered size of 0,0. But if you add some components to it with a higher prefered size, its prefered size will not be 0.

Why can't I access my panel's getWidth() and getHeight() functions?

I cannot tell the reason but:

A way to avoid this is to override your getPreferredSize() function and return your preferred size.

Get the real size of a JFrame content

First get the pixels trimmed out by the frame.

int reqWidth = reqHeight = 750;

// first set the size
frame.setSize(reqWidth, reqHeight);

// This is not the actual-sized frame. get the actual size
Dimension actualSize = frame.getContentPane().getSize();

int extraW = reqWidth - actualSize.width;
int extraH = reqHeight - actualSize.height;

// Now set the size.
frame.setSize(reqWidth + extraW, reqHeight + extraH);

An alternate simpler way. The previous works but this is recommended.

frame.getContentPane().setPreferredSize(750, 750);
frame.pack();

Hope this helps.

EDIT:

Add this in your constructor before adding components to the frame. and to set it in the middle, use

frame.setLocationRelativeTo(null);

This will center the window on the screen.

Maximum component size that will fit in a JPanel

As I say in my question the problem was with the layout manager. In my application this was not the problem because I was using GridBagLayout. I have a series of JComponents one of which was an extension of ImageScrollPane that did not have an empty border.

I found the trick was, similar to this question to set the border on my component to an empty Border.

How to keep JPanel from inheriting the size of its container JFrame

Your code appears to be ignoring how Java Swing layout managers work. When you add a JPanel to a JFrame, the default lay out is BorderLayout, and this will center the panel in the frame and size it to fill the frame. If you wish to have a panel at different size, and its preferredSize needs to be set somehow, and the container that holds the JPanel will need to use a different layout manager. A GridBagLayout used in a "default" way (adding one component, no GridBagConstraints) for instance would center the JPanel if this is what you desire. If these suggestions do not help, then you should create a posterior own MCVE (please read the link).

For example, MY MCVE:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.*;

@SuppressWarnings("serial")
public class DiffSizedPanel extends JPanel {
private static final int PANEL_W = 400;
private static final int PANEL_H = 300;
private static final int FRAME_W = 600;
private static final int FRAME_H = 500;
private static final Color BG_COLOR = Color.PINK;

public DiffSizedPanel() {
setBackground(BG_COLOR);

// set the JPanel the preferred size desired
setPreferredSize(new Dimension(PANEL_W, PANEL_H));
setBorder(BorderFactory.createTitledBorder("This is the JPanel"));
}

private static void createAndShowGui() {
JFrame frame = new JFrame("Different Sized Panel");

// set the JFrame the preferred size desired
frame.setPreferredSize(new Dimension(FRAME_W, FRAME_H));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// change the content pane's layout from default BorderLayout to GridBagLayout
frame.getContentPane().setLayout(new GridBagLayout());
frame.getContentPane().add(new DiffSizedPanel()); // add the JPanel
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}


Related Topics



Leave a reply



Submit