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

前端 未结 4 762
别那么骄傲
别那么骄傲 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: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 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 clut = new LinkedList(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);
        }
    }
    

提交回复
热议问题