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
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
What Is the Best Approach for Using an Enum as a Singleton in Java
Getting Rsa Private Key from Pem Base64 Encoded Private Key File
Adding Elements to a Collection During Iteration
Get Query from Java.Sql.Preparedstatement
Call "Java -Jar Myfile.Jar" with Additional Classpath Option
Sort a Two Dimensional Array Based on One Column
When to Use Abstract Class or Interface
Javafx "Location Is Required." Even Though It Is in the Same Package
@Autowired Bean Is Null When Referenced in the Constructor of Another Bean
What Does Swingutilities.Invokelater Do
How to Remove Duplicates from a List
What Is the Equivalent Lambda Expression for System.Out::Println
Parsing Iso-8601 Datetime with Offset with Colon in Java
Using Sleep() for a Single Thread