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

前端 未结 4 710
别那么骄傲
别那么骄傲 2020-11-22 02:32

JRE Version 1.7 Update 3

EXPECTED BEHAVIOUR

As I run the program, it works as expected, everything works smoothly. As when

相关标签:
4条回答
  • 2020-11-22 03:03

    I am unsure whether I found a solution for your system, but adjusting the code to

    colourButton = new JButton( "BALL COLOUR" );
    colourButton.setOpaque( true );
    colourButton.setBackground( colours[ colourCounter ] );
    colourButton.setForeground( Color.WHITE );
    

    works on my system (OS X with Java 1.7). Note the setOpaque call, which is needed so that the setBackground call has any effect as stated in the javadoc of that method:

    Sets the background color of this component. The background color is used only if the component is opaque

    On OS X, without that setOpaque call your code does not even work before a resize

    0 讨论(0)
  • 2020-11-22 03:06

    maybe will help you with two parts of, I think that Graphics/2D is designated to use Swing Timer exclusively,

    0 讨论(0)
  • 2020-11-22 03:09

    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);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:15

    The problem with your very nice example may be platform dependent, but I can offer a few observations:

    • You're not adding or removing components, so you don't need revalidate().

    • Because the background color is a bound property of the buttons, you don't need the subsequent calls to repaint().

    • You do need repaint() in your custom DrawingArea, but you may want to experiment with adding property change support, as suggested here.

    • Color.white can't be brighter() and Color.black can't be darker(); Color.darkGray.darker() is Color.black().

    • The variation below uses a Queue<Color> to simplify changing colors.

    screen capture

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ComponentAdapter;
    import java.awt.event.ComponentEvent;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.Queue;
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    /** @see https://stackoverflow.com/q/9849950/230513 */
    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 Queue<Color> clut = new LinkedList<Color>(Arrays.asList(
            Color.BLUE.darker(),
            Color.MAGENTA.darker(),
            Color.BLACK,
            Color.RED.darker(),
            Color.PINK,
            Color.CYAN.darker(),
            Color.DARK_GRAY,
            Color.YELLOW.darker(),
            Color.GREEN.darker()));
        private Color backgroundColour;
        private Color foregroundColour;
        private ActionListener timerAction = new ActionListener() {
    
            @Override
            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() {
    
            @Override
            public void componentResized(ComponentEvent ce) {
                timer.restart();
                startStopButton.setText("Stop");
                isTimerRunning = true;
            }
        };
    
        public BallAnimation() {
            x = y = 0;
            positiveX = positiveY = true;
            speedValue = 1;
            isTimerRunning = false;
            diameter = 50;
            backgroundColour = Color.white;
            foregroundColour = clut.peek();
            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(new GridLayout(0, 1));
            buttonPanel.setBorder(BorderFactory.createLineBorder(Color.darkGray, 5));
    
            startStopButton = new JButton("Start");
            startStopButton.setOpaque(true);
            startStopButton.setForeground(Color.white);
            startStopButton.setBackground(Color.green.darker());
            startStopButton.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (!isTimerRunning) {
                        startStopButton.setText("Stop");
                        timer.start();
                        isTimerRunning = true;
                    } else if (isTimerRunning) {
                        startStopButton.setText("Start");
                        timer.stop();
                        isTimerRunning = false;
                    }
                }
            });
            startStopButton.setBorder(BorderFactory.createLineBorder(Color.gray, 4));
            buttonPanel.add(startStopButton);
    
            colourButton = new JButton("Change Color");
            colourButton.setOpaque(true);
            colourButton.setForeground(Color.white);
            colourButton.setBackground(clut.peek());
            colourButton.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent ae) {
                    //timer.restart();
                    clut.add(clut.remove());
                    foregroundColour = clut.peek();
                    drawingArea.setXYColourValues(x, y, backgroundColour, foregroundColour);
                    colourButton.setBackground(foregroundColour);
                }
            });
            colourButton.setBorder(BorderFactory.createLineBorder(Color.gray, 4));
            buttonPanel.add(colourButton);
    
            exitButton = new JButton("Exit");
            exitButton.setBackground(Color.red);
            exitButton.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent ae) {
                    timer.stop();
                    System.exit(0);
                }
            });
            exitButton.setBorder(BorderFactory.createLineBorder(Color.red.darker(), 4));
            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() {
    
                @Override
                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, 5));
        }
    
        public void setXYColourValues(int x, int y, Color bColor, Color fColor) {
            this.x = x;
            this.y = y;
            backgroundColor = bColor;
            foregroundColor = fColor;
            repaint();
        }
    
        @Override
        public Dimension getPreferredSize() {
            return (new Dimension(500, 400));
        }
    
        @Override
        public void paintComponent(Graphics g) {
            g.setColor(backgroundColor);
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(foregroundColor);
            g.fillOval(x, y, ballDiameter, ballDiameter);
        }
    }
    
    0 讨论(0)
提交回复
热议问题