без причины вызывается метод repaint()

414
11 января 2017, 01:05

Создал JPanel на котором есть 3 кнопки, и овал, нарисованный в методе paintComponent(). По задумке, при нажатии на одну из кнопок, она обводится в рамочку, и выбирается ее цвет, которым потом можно будет залить нарисованный овал. При клике на сам овал происходит заливка:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import gui.exercises.a.abs.AExercise;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
public class ImageFiller extends AExercise {// AExercise - класс-наследник JPanel
    private Color color;
    public ImageFiller(JFrame jFrame) {
        super(jFrame);
        color = Color.WHITE;
        init();
    }
    private void init(){
        exerciseTitle = new JLabel("Выбери подходящий цвет и раскрась рисунок.");
        exerciseTitle.setHorizontalAlignment(SwingConstants.CENTER);
        exerciseTitle.setFont(new Font("Tahoma", Font.PLAIN, 34));
        exerciseTitle.setBounds(260, 40, 750, 54);
        add(exerciseTitle);
        smile.setLocation(20, 550);
        JButton color1 = new JButton();
        color1.setBounds(1200, 200, 50, 50);
        color1.setBackground(Color.BLUE);
        Border border = BorderFactory.createMatteBorder(4, 4, 4, 4, Color.BLACK);
        add(color1);
        JButton color2 = new JButton();
        color2.setBounds(1200, 255, 50, 50);
        color2.setBackground(Color.YELLOW);
        add(color2);
        JButton color3 = new JButton();
        color3.setBounds(1200, 310, 50, 50);
        color3.setBackground(Color.GREEN);
        add(color3);        
        color1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(!color1.getBorder().equals(border)){
                    color1.setBorder(border);
      }
                color = color1.getBackground();
            }
        });
        color2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(!color2.getBorder().equals(border)){
                    color2.setBorder(border);}
                color = color2.getBackground();
            }
        });
        color3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(!color3.getBorder().equals(border)){
                    color3.setBorder(border);
                           }
                color = color3.getBackground();
            }
        });
    }
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(color);
        g2d.fillOval(600, 300, 200, 200);
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {                
                repaint();
            }
        });
    }
}

AExercise

public abstract class AExercise extends JPanel {
protected JFrame jFrame;
protected JLabel exerciseTitle;
protected PlaySound playSound;
protected JLabel smile;
protected static final String correctImage = "/img/gif/858131397.gif";
protected static final String correctSound = "/sound/app.wav";
protected static final String incorrectImage = "/img/gif/no.gif";   
protected static final String incorrectSound = "/sound/no.wav";
/**
 * Create the panel.
 */
public AExercise(JFrame jFrame) {
    this.jFrame = jFrame;
    setBounds(0, 0, 1300, 750);
    setBackground(new Color(204, 255, 255));
    setBorder(new EmptyBorder(5, 5, 5, 5));
    playSound = ((ATrain) jFrame).getPlaySound();
    setLayout(null);
    init();
}
private void init(){        
    JButton b = new JButton("Назад");
    b.setBounds(1150, 640, 100, 40);
    add(b);
    b.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            playSound.stopSound();
            jFrame.setContentPane(new AExercises(jFrame));
            repaint();
            revalidate();
        }
    });
    smile = new JLabel();
    smile.setIcon(new ImageIcon(ATrain.class.getResource("/img/gif/230646016.gif")));
    smile.setBounds(0, 0, smile.getIcon().getIconWidth(), smile.getIcon().getIconHeight());
    add(smile);
}
protected void answer(String icon, String sound){
    smile.setIcon(new ImageIcon(ATrain.class.getResource(icon)));
    if(playSound.getClip()!=null){
        playSound.stopSound();
    }
    playSound.playSound(sound);
}

}

Всё в общем то работает, но почему-то при первом нажатии на любую из кнопок с выбором цвета, заливка происходит автоматически (а не при последующем клике на овал). При последующих кликах всё работает нормально. Долго думал что может быть этому причиной. В результате оказалось, что если закомментировать if в actionPerformed кнопок, то всё работает, но тогда я оказываюсь без рамочки для выбранного цвета. Может кто-то объяснить, почему при первом клике вызывается repaint(), или это в другом дело?

UPD

Немного поменял класс. Отдельно создал объект овала. Проблема осталась..

private Ellipse2D oval = new Ellipse2D.Double(600, 300, 200, 200);

Переместил листнер в init()

addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {   
            if(oval.contains(e.getX(), e.getY()))
            repaint();
        }
    });

UPD2. РЕШЕНИЕ ГОТОВО

Отредактировал класс, как посоветовал Regent, пофиксил баг с преждевременным заливкой. Добавил ещё несколько фигур которые можно залить (отдельно от остальных).

Рабочий код:

package gui.exercises.a;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
import javax.swing.border.Border;
import gui.exercises.a.abs.AExercise;
public class ImageFiller extends AExercise
{
private Color color;
private Oval oval1 = new Oval(new Ellipse2D.Double(450, 300, 200, 200),     Color.WHITE);
private Oval oval2 = new Oval(new Ellipse2D.Double(600, 300, 200, 200),     Color.WHITE);   
private Oval oval3 = new Oval(new Ellipse2D.Double(750, 300, 200, 200), Color.WHITE);
private Oval [] ovals = {oval1, oval2, oval3};
private JButton [] buttons = new JButton[ovals.length];
private static final Color[] colors = { Color.BLUE, Color.YELLOW,     Color.GREEN };
public ImageFiller(JFrame jFrame)
{
    super(jFrame);
    color = Color.WHITE;
    init();
}
private void init()
{
    exerciseTitle = new JLabel("Выбери подходящий цвет и раскрась рисунок.");
    exerciseTitle.setHorizontalAlignment(SwingConstants.CENTER);
    exerciseTitle.setFont(new Font("Tahoma", Font.PLAIN, 34));
    exerciseTitle.setBounds(260, 40, 750, 54);
    add(exerciseTitle);
    Border border = BorderFactory.createMatteBorder(4, 4, 4, 4, Color.BLACK);
    ActionListener actionListener = new ActionListener()
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            JButton button = (JButton)e.getSource();
            if (!button.getBorder().equals(border))
            {
                button.setBorder(border);
                for(JButton jb: buttons){
                    if(!jb.equals(button))
                            jb.setBorder(BorderFactory.createLineBorder(Color.black));
                }
            }

            color = button.getBackground();
        }
    };
    for (int i = 0; i < colors.length; i++)
    {
       buttons[i] = createAndAddButton(i, actionListener);
    }

    addMouseListener(new MouseAdapter()
    {
        @Override
        public void mouseClicked(MouseEvent e)
        {
            if (oval1.getElips().contains(e.getX(), e.getY()))
            {
                oval1.setColor(color);
                repaint();
            }
            if (oval2.getElips().contains(e.getX(), e.getY()))
            {
                oval2.setColor(color);
                repaint();
            }
            if (oval3.getElips().contains(e.getX(), e.getY()))
            {
                oval3.setColor(color);
                repaint();
            }
        }
    });
}
 @Override
 public void paintComponent(Graphics g)
 {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,     RenderingHints.VALUE_ANTIALIAS_ON);
    for(Oval o:ovals){
        g2d.setColor(o.getColor());
        g2d.fill(o.getElips());
    }
}
private JButton createAndAddButton(int index, ActionListener actionListener)
{
    JButton button = new JButton();
    button.setBounds(1200, 200 + index * 55, 50, 50);
    button.setBackground(colors[index]);
    add(button);
    button.addActionListener(actionListener);
    return button;
}

}

Для этого создал отдельную сущность Oval, в которой инкапсулирована фигура, и ее цвет.

class Oval{
private Ellipse2D elips;
private Color color;
public Oval(Ellipse2D elips, Color color) {
    super();
    this.elips = elips;
    this.color = color;
}
public Ellipse2D getElips() {
    return elips;
}
public void setElips(Ellipse2D elips) {
    this.elips = elips;
}
public Color getColor() {
    return color;
}
public void setColor(Color color) {
    this.color = color;
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((color == null) ? 0 : color.hashCode());
    result = prime * result + ((elips == null) ? 0 : elips.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Oval other = (Oval) obj;
    if (color == null) {
        if (other.color != null)
            return false;
    } else if (!color.equals(other.color))
        return false;
    if (elips == null) {
        if (other.elips != null)
            return false;
    } else if (!elips.equals(other.elips))
        return false;
    return true;
}
@Override
public String toString() {
    return "Oval [elips=" + elips + ", color=" + color + "]";
}
}

PS: Ещё раз огромное спасибо Regent, без его активного участия в комментариях у меня ничего бы не получилось!

READ ALSO
Как передать строку из Activity в Fragment

Как передать строку из Activity в Fragment

Хочу передать строку из Activity в Fragment, помогите исправить ошибку

937
Сортировка чисел и вывод их на экран

Сортировка чисел и вывод их на экран

Я сделал 1 и 2 пунктыКак сделать 3 пункт?

502
Доступ к событиям чужого калентаря

Доступ к событиям чужого калентаря

Необходимо получить список событий чужого Google-календаряПытаюсь сделать так:

324
GridLayout в ScrollView выдает ошибку

GridLayout в ScrollView выдает ошибку

Получил много ошибок, но считаю что основная эта, подскажите пожалуйста, в чем проблема?

318