Something seems wrong with the layout, JButton showing unexpected behaviour at resize of the window
java, jbutton, jframe, resize, swing
Solution
Seems like there is something wrong with `BorderLayout.LINE_END` thingy, only when I place the `buttonPanel` on `LINE_END`, I am getting undesirable results. I had tried to use only one `JButton`, instead of three as the latest measure, to sort out thingies. Now the problem that use to come as shown in this pic :
has been sorted out by changing the position of the `JButton` Panel to `LINE_START` or using `JRE version 1.6 update 31`, in the pic as below :
Here is the code used for this example :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BallAnimation
{
private int x;
private int y;
private boolean positiveX;
private boolean positiveY;
private boolean isTimerRunning;
private int speedValue;
private int diameter;
private DrawingArea drawingArea;
private Timer timer;
private int colourCounter;
Color[] colours = {
Color.BLUE.darker(),
Color.MAGENTA.darker(),
Color.BLACK.darker(),
Color.RED.darker(),
Color.PINK.darker(),
Color.CYAN.darker(),
Color.DARK_GRAY.darker(),
Color.YELLOW.darker(),
Color.GREEN.darker()
};
private Color backgroundColour;
private Color foregroundColour;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
x = getX();
y = getY();
drawingArea.setXYColourValues(x, y, backgroundColour
, foregroundColour);
}
};
private JPanel buttonPanel;
private JButton startStopButton;
private JButton speedIncButton;
private JButton speedDecButton;
private JButton resetButton;
private JButton colourButton;
private JButton exitButton;
private ComponentAdapter componentAdapter = new ComponentAdapter()
{
public void componentResized(ComponentEvent ce)
{
timer.restart();
}
};
public BallAnimation()
{
x = y = 0;
positiveX = positiveY = true;
speedValue = 1;
colourCounter = 0;
isTimerRunning = false;
diameter = 50;
backgroundColour = Color.WHITE.brighter();
foregroundColour = colours[colourCounter];
timer = new Timer(10, timerAction);
}
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Ball Animation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
drawingArea = new DrawingArea(x, y
, backgroundColour, foregroundColour, diameter);
drawingArea.addComponentListener(componentAdapter);
frame.add(makeButtonPanel(), BorderLayout.LINE_START);
frame.add(drawingArea, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private JPanel makeButtonPanel()
{
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(0, 1));
buttonPanel.setBorder(BorderFactory.createLineBorder(
Color.DARK_GRAY, 5, true));
colourButton = new JButton("BALL COLOUR");
colourButton.setOpaque(true);
colourButton.setBackground(colours[colourCounter]);
colourButton.setForeground(Color.WHITE);
colourButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
System.out.println("COLOUR JButton Clicked!");
if (timer.isRunning())
timer.stop();
colourCounter++;
if (colourCounter == 9)
colourCounter = 0;
foregroundColour = colours[colourCounter];
drawingArea.setXYColourValues(x, y, backgroundColour
, foregroundColour);
colourButton.setBackground(foregroundColour);
if (!timer.isRunning())
timer.start();
}
});
colourButton.setBorder(BorderFactory.createLineBorder(
Color.WHITE, 2, true));
buttonPanel.add(colourButton);
return buttonPanel;
}
private int getX()
{
if (x < 0)
positiveX = true;
else if (x >= drawingArea.getWidth() - diameter)
positiveX = false;
return (calculateX());
}
private int calculateX()
{
if (positiveX)
return (x += speedValue);
else
return (x -= speedValue);
}
private int getY()
{
if (y < 0)
positiveY = true;
else if (y >= drawingArea.getHeight() - diameter)
positiveY = false;
return (calculateY());
}
private int calculateY()
{
if (positiveY)
return (y += speedValue);
else
return (y -= speedValue);
}
public static void main(String... args)
{
Runnable runnable = new Runnable()
{
public void run()
{
new BallAnimation().createAndDisplayGUI();
}
};
SwingUtilities.invokeLater(runnable);
}
}
class DrawingArea extends JComponent
{
private int x;
private int y;
private int ballDiameter;
private Color backgroundColor;
private Color foregroundColor;
public DrawingArea(int x, int y
, Color bColor, Color fColor, int dia)
{
this.x = x;
this.y = y;
ballDiameter = dia;
backgroundColor = bColor;
foregroundColor = fColor;
setBorder(BorderFactory.createLineBorder(
Color.DARK_GRAY.darker(), 5, true));
}
public void setXYColourValues(int x, int y
, Color bColor, Color fColor)
{
this.x = x;
this.y = y;
backgroundColor = bColor;
foregroundColor = fColor;
repaint();
}
public Dimension getPreferredSize()
{
return (new Dimension(500, 400));
}
public void paintComponent(Graphics g)
{
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(foregroundColor);
g.fillOval(x, y, ballDiameter, ballDiameter);
}
}
Problem
JRE Version 1.7 Update 3 EXPECTED BEHAVIOUR As I run the program, it works as expected, everything works smoothly. As when I click on `STOP` `JButton` the animation stops and the text on the same `JButton` changes to `START`. Now when i click on `BALL COLOUR` `JButton`, the colour of the `BALL` changes, as well as the colour of the `BALL COLOUR` `JBUTTON`, also changes, to that of the `BALL`. This whole behaviour works if I run my application as is without resizing. UNEXPECTED BEHAVIOUR But when i `RESIZE` my `JFrame`, by pulling the `Right Side`, that's when unexpected behaviour of my Application is shown, in the sense that if I press `STOP` `JButton` and then click on `BALL COLOUR` button, the text on the `JButton` clicked earlier whose text changed to `START` will change to `STOP` again when it should not be, as well as the colour of the `BALL COLOUR` `JButton` will remain unchanged or will turn to `BLUE`, when it should be changed to the colour of the ball. I am attaching the pics for more info. But if you will try to resize it back to it's original size or closer to that, then things will come back to normal. Why is this happening ? Any idea or clue will be much appreciated. As My Application Runs with EXPECTED BEHAVIOUR as described above : And here the UNEXPECTED BEHAVIOUR BOTTOM-LINE : Why the Application runs as usual as it should be, at the `BEGINNING` , but not when `RESIZED` by dragging it's `RIGHT SIDE`, but again if you bring it to it's original size or closer to it, things come back to normal, it works as expected ? So considering the scenario, am I doing something wrong, in the program. Or is this exactly the situation, where I should be using the `SwingWorker`, Or Is this an issue with the `Layout`, or something hidden related to `Content Pane`. Please do put some light :-) here is the code I am using, I had brought it down to the minimum, as I think to demonstrate my problem : ``` import java.awt.*; import java.awt.event.*; import javax.swing.*; public class BallAnimation { private int x; private int y; private boolean positiveX; private boolean positiveY; private boolean isTimerRunning; private int speedValue; private int diameter; private DrawingArea drawingArea; private Timer timer; private int colourCounter; Color[] colours = { Color.BLUE.darker(), Color.MAGENTA.darker(), Color.BLACK.darker(), Color.RED.darker(), Color.PINK.darker(), Color.CYAN.darker(), Color.DARK_GRAY.darker(), Color.YELLOW.darker(), Color.GREEN.darker() }; private Color backgroundColour; private Color foregroundColour; private ActionListener timerAction = new ActionListener() { public void actionPerformed(ActionEvent ae) { x = getX(); y = getY(); drawingArea.setXYColourValues(x, y, backgroundColour , foregroundColour); } }; private JPanel buttonPanel; private JButton startStopButton; private JButton speedIncButton; private JButton speedDecButton; private JButton resetButton; private JButton colourButton; private JButton exitButton; private ComponentAdapter componentAdapter = new ComponentAdapter() { public void componentResized(ComponentEvent ce) { timer.restart(); startStopButton.setText("STOP"); isTimerRunning = true; } }; public BallAnimation() { x = y = 0; positiveX = positiveY = true; speedValue = 1; colourCounter = 0; isTimerRunning = false; diameter = 50; backgroundColour = Color.WHITE.brighter(); foregroundColour = colours[colourCounter]; timer = new Timer(10, timerAction); } private void createAndDisplayGUI() { JFrame frame = new JFrame("Ball Animation"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationByPlatform(true); drawingArea = new DrawingArea(x, y , backgroundColour, foregroundColour, diameter); drawingArea.addComponentListener(componentAdapter); frame.add(makeButtonPanel(), BorderLayout.LINE_END); frame.add(drawingArea, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); } private JPanel makeButtonPanel() { buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(0, 1)); buttonPanel.setBorder(BorderFactory.createLineBorder( Color.DARK_GRAY, 5, true)); startStopButton = new JButton("START"); startStopButton.setBackground(Color.GREEN.darker()); startStopButton.setForeground(Color.WHITE.brighter()); startStopButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { System.out.println("START/STOP JButton Clicked!"); if (!isTimerRunning) { startStopButton.setText("STOP"); timer.start(); isTimerRunning = true; buttonPanel.revalidate(); buttonPanel.repaint(); } else if (isTimerRunning) { startStopButton.setText("START"); timer.stop(); isTimerRunning = false; buttonPanel.revalidate(); buttonPanel.repaint(); } } }); startStopButton.setBorder(BorderFactory.createLineBorder( Color.WHITE, 4, true)); buttonPanel.add(startStopButton); colourButton = new JButton("BALL COLOUR"); colourButton.setBackground(colours[colourCounter]); colourButton.setForeground(Color.WHITE); colourButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { System.out.println("COLOUR JButton Clicked!"); //timer.restart(); colourCounter++; if (colourCounter == 9) colourCounter = 0; foregroundColour = colours[colourCounter]; drawingArea.setXYColourValues(x, y, backgroundColour , foregroundColour); //drawingArea.setForegroundForBall(foregroundColour); colourButton.setBackground(foregroundColour); colourButton.revalidate(); colourButton.repaint(); //timer.start(); } }); colourButton.setBorder(BorderFactory.createLineBorder( Color.WHITE, 2, true)); buttonPanel.add(colourButton); exitButton = new JButton("EXIT"); exitButton.setBackground(Color.RED.darker()); exitButton.setForeground(Color.WHITE.brighter()); exitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { System.out.println("EXIT JButton Clicked!"); timer.stop(); System.exit(0); } }); exitButton.setBorder(BorderFactory.createLineBorder( Color.RED.darker().darker(), 4, true)); buttonPanel.add(exitButton); return buttonPanel; } private int getX() { if (x < 0) positiveX = true; else if (x >= drawingArea.getWidth() - diameter) positiveX = false; return (calculateX()); } private int calculateX() { if (positiveX) return (x += speedValue); else return (x -= speedValue); } private int getY() { if (y < 0) positiveY = true; else if (y >= drawingArea.getHeight() - diameter) positiveY = false; return (calculateY()); } private int calculateY() { if (positiveY) return (y += speedValue); else return (y -= speedValue); } public static void main(String... args) { Runnable runnable = new Runnable() { public void run() { new BallAnimation().createAndDisplayGUI(); } }; SwingUtilities.invokeLater(runnable); } } class DrawingArea extends JComponent { private int x; private int y; private int ballDiameter; private Color backgroundColor; private Color foregroundColor; public DrawingArea(int x, int y , Color bColor, Color fColor, int dia) { this.x = x; this.y = y; ballDiameter = dia; backgroundColor = bColor; foregroundColor = fColor; setBorder(BorderFactory.createLineBorder( Color.DARK_GRAY.darker(), 5, true)); } public void setXYColourValues(int x, int y , Color bColor, Color fColor) { this.x = x; this.y = y; backgroundColor = bColor; foregroundColor = fColor; repaint(); } public Dimension getPreferredSize() { return (new Dimension(500, 400)); } public void paintComponent(Graphics g) { g.setColor(backgroundColor); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(foregroundColor); g.fillOval(x, y, ballDiameter, ballDiameter); } } ``` **LATEST EDIT : **