Вопрос:

Что-то не так с макетом, JButton показывает неожиданное поведение при изменении размера окна

java swing resize jframe jbutton

6105 просмотра

4 ответа

22804 Репутация автора

JRE Версия 1.7 Обновление 3

ОЖИДАЕМОЕ ПОВЕДЕНИЕ

Когда я запускаю программу, она работает как положено, все работает гладко. Как при нажатии на STOP JButtonанимацию останавливается и текст на том же JButtonменяется на START. Теперь, когда я нажимаю BALL COLOUR JButton, цвет BALLизменений, а также цвет BALL COLOUR JBUTTON, также меняется на цвет BALL. Все это работает, если я запускаю свое приложение без изменения размера.

НЕОЖИДАННОЕ ПОВЕДЕНИЕ

Но когда я RESIZEтяну JFrame, потянув Right Side, это, когда проявляется неожиданное поведение моего приложения, в том смысле, что если я нажму, STOP JButtonа затем нажму на BALL COLOURкнопку, текст на нажатой JButtonранее, чей текст изменился на START, изменится на STOPснова, когда он не должен будет, а также цвет BALL COLOUR JButtonостанется неизменным или превратится в BLUE, когда его следует изменить на цвет шара. Я прилагаю фотографии для получения дополнительной информации. Но если вы попытаетесь изменить его размер до первоначального или более близкого к этому, то все вернется на круги своя. Почему это происходит ? Любая идея или подсказка будет высоко ценится.

Как мое приложение работает с ОЖИДАЕМЫМ ПОВЕДЕНИЕМ, как описано выше:

Ожидаемое поведение

И тут НЕОЖИДАННОЕ ПОВЕДЕНИЕ

Неожиданное поведение

НИЖНЯЯ ЛИНИЯ :

Почему приложение работает как обычно, как и раньше BEGINNING, но не тогда, когда RESIZEDего перетаскивают RIGHT SIDE, но, опять же, если вы приведете его к исходному размеру или ближе к нему, все вернется на круги своя, оно будет работать как положено?

Итак, учитывая сценарий, я делаю что-то не так в программе. Или это именно та ситуация, когда я должен использовать SwingWorker, или Это проблема с Layout, или что-то скрытое, связанное с Content Pane. Пожалуйста, поставьте немного света :-)

Вот код, который я использую, я довел его до минимума, чтобы продемонстрировать свою проблему:

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

** ПОСЛЕДНИЕ РЕДАКТИРОВАТЬ: **

ПОСЛЕДНИЙ

Автор: nIcE cOw Источник Размещён: 24.03.2012 07:28

Ответы (4)


5 плюса

105071 Репутация автора

может быть, поможет вам с двумя частями , я думаю, что Graphics / 2D предназначен для использования исключительно Swing Timer ,

Автор: mKorbel Размещён: 24.03.2012 07:45

4 плюса

32357 Репутация автора

Я не уверен, нашел ли я решение для вашей системы, но корректирую код

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

работает в моей системе (OS X с Java 1.7). Обратите внимание на setOpaqueвызов, который необходим для того, чтобы setBackgroundвызов имел какой-либо эффект, как указано в javadoc этого метода:

Устанавливает цвет фона этого компонента. Цвет фона используется, только если компонент непрозрачный

На OS X без этого setOpaqueвызова ваш код даже не работает до изменения размера

Автор: Robin Размещён: 24.03.2012 01:09

12 плюса

190180 Репутация автора

Проблема с вашим очень хорошим примером может зависеть от платформы, но я могу предложить несколько замечаний:

  • Вы не добавляете и не удаляете компоненты, поэтому вам это не нужно revalidate().

  • Поскольку цвет фона является связанным свойством кнопок, вам не нужны последующие вызовы repaint().

  • Вы действительно нуждаетесь repaint()в своем обычае DrawingArea, но вы можете поэкспериментировать с добавлением поддержки изменения свойств, как предлагается здесь .

  • Color.whiteне может быть brighter()и Color.blackне может быть darker(); Color.darkGray.darker()есть Color.black().

  • Вариант ниже использует Queue<Color>для упрощения изменения цвета.

скриншот

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);
    }
}
Автор: trashgod Размещён: 24.03.2012 03:03

7 плюса

22804 Репутация автора

Решение

Похоже , есть что - то не так с BorderLayout.LINE_ENDштуковиной, только тогда , когда я помещаю buttonPanelна LINE_END, я получаю нежелательные результаты. Я пытался использовать только одну JButton, а не три в качестве последней меры, чтобы отсортировать вещи. Теперь проблема, которая используется, чтобы прийти, как показано на этом рисунке:

LINE_END

был отсортирован путем изменения положения JButtonпанели на LINE_STARTили с использованием JRE version 1.6 update 31, как показано ниже:

LINE_START

Вот код, используемый для этого примера:

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);
    }
}
Автор: nIcE cOw Размещён: 25.03.2012 08:54
Вопросы из категории :
32x32