Something Seems Wrong With the Layout, Jbutton Showing Unexpected Behaviour At Resize of the Window

Something seems wrong with the layout, JButton showing unexpected behaviour at resize of the window

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 :

LINE_END

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 :

LINE_START

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);
}
}

Is this a Swing Java 7 rendering bug?

In case the issue is caused by your graphics driver, setting one of the system properties below could help. Not quite sure if the props are still supported in Java 7.

sun.java2d.d3d=false
sun.java2d.ddoffscreen=false
sun.java2d.noddraw=true

Java Action Listener Issues

Look into using a javax.swing.Timer. Your while loop will block the EDT not allowing the button events to be dispatched.

See How to use Swing Timers.

With the timer, you can just use it's methods stop and start to, well, start and stop the timer. You can see an example here


Here's a runnable example using a Timer with your code. The code in the link above is cleaner, using a Ball object. I just threw this one together really quick

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class BallTask {

public static boolean run = false;
private Timer timer;
private BallPanel ballPanel = new BallPanel();

public BallTask() {
timer = new Timer(30, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (ballPanel.x < 0 || ballPanel.x > ballPanel.getWidth()) {
ballPanel.dx = -ballPanel.dx;
}
if (ballPanel.y < 0 || ballPanel.y > ballPanel.getHeight()) {
ballPanel.dy = -ballPanel.dy;
}
// Adjust ball position
ballPanel.x += ballPanel.dx;
ballPanel.y += ballPanel.dy;
ballPanel.repaint();
}
});
JPanel buttons = new JPanel();
JButton stop = new JButton("STOP");
buttons.add(stop);
stop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.stop();
}
});
JButton go = new JButton("GO");
buttons.add(go);
go.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});

JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(ballPanel);
mainPanel.add(buttons, BorderLayout.SOUTH);

JFrame window = new JFrame();
window.add(mainPanel);
window.pack();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationRelativeTo(null);
window.setVisible(true);

}

private class BallPanel extends JPanel {

private int x;
private int y;
int dx = 4; // Increment on ball's x-coordinate
int dy = 4; // Increment on ball's y-coordinate
int radius = 15; // Ball radius

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 30, 30);
}

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

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
new BallTask();
}
});
}
}

Java graphic not painting properly

There are (possibly) two basic problems...

  1. In getY, you are ignoring the parameter t and using timeStep instead, while, technically, this probably isn't going to make a MASSIVE difference, it is an area of concern
  2. You have an integer division issue. i/200 will result in int result, where you really want a double. Change it to i/200d

For example...

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;

final public class Test {

private int timeStep = 0;
private final int ballYTravel = 100;
private final int BALL_NUM = 24;

public static void main(String... args) {
new Test();
}

public Test() {
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 DrawPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

class DrawPanel extends JPanel {

private static final long serialVersionUID = 1L;

public DrawPanel() {
new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timeStep++;
repaint();
}
}).start();
}

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

public double getY(int i, int t) {
return 100 + ballYTravel / 2 * (Math.sin(t * (i / 200d + 0.08)));
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int k = 0; k < BALL_NUM; k++) {
g.fillRect(10 + 20 * k, (int) getY(k, timeStep), 6, 6);
}

}
}
}

You're also breaking the paint chain, which is going to cause you issues in the long run, make sure you are calling super.paintComponent...

For more details see...

  • Performing Custom Painting
  • Painting in AWT and Swing
  • Concurrency in Swing
  • How to use Swing Timers
  • Initial Threads

Drawing a rectangle on JPanel

The problem is that the y coordinate for your racket is greater then the preferred size height of the panel ScreenPanel:- 250 > 200:

    racket = new Racket(120, 250, 70, 10);
^
setPreferredSize(new Dimension(200, 200));

making the racket draw offscreen.

Ball is not moving like I want

So you have:

private void initBall(Graphics2D graphics2d) {

int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;

in the beginning, so that regardless of which direction the ball is going, booth booleans are set to false every time. Then, you don't have an "Else" when it comes to setting the back option in

    if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;

if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;

What is happening is that the ball is moving in the right direction, until it hits a wall (I'm guessing the top wall). then this is called:

if (y > getHeight() - 50)
backY = true;

So then for that iteration the ball goes back because of

if (!backY)
setPosY(++y);
else
setPosY(--y);

But then you set it back to false right away. I suggest you have

private boolean backX = false; //same for backY

outside your method.

Java Swing button colors

Here is a question and several answers related to flashing a component.

Addendum: You can learn more in the article How to Use Buttons. In particular, you can use setForeground() to change the color of a button's text, but the corresponding setBackground() doesn't read well on some platforms. Using a Border is one alternative; a colored panel, shown below, is another.

Sample Image

package overflow;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ButtonTest extends JPanel implements ActionListener {

private static final int N = 4;
private static final Random rnd = new Random();
private final Timer timer = new Timer(1000, this);
private final List<ButtonPanel> panels = new ArrayList<ButtonPanel>();

public ButtonTest() {
this.setLayout(new GridLayout(N, N, N, N));
for (int i = 0; i < N * N; i++) {
ButtonPanel bp = new ButtonPanel(i);
panels.add(bp);
this.add(bp);
}
}

@Override
public void actionPerformed(ActionEvent e) {
for (JPanel p : panels) {
p.setBackground(new Color(rnd.nextInt()));
}
}

private static class ButtonPanel extends JPanel {

public ButtonPanel(int i) {
this.setBackground(new Color(rnd.nextInt()));
this.add(new JButton("Button " + String.valueOf(i)));
}
}

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

@Override
public void run() {
JFrame f = new JFrame("ButtonTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ButtonTest bt = new ButtonTest();
f.add(bt);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
bt.timer.start();
}
});
}
}


Related Topics



Leave a reply



Submit