Ming Chen
Ming Chen

Reputation: 3

Why there is a same button appear when I click a button?

When I run this code, the Color button will appear on the top left corner. When I drag the window, the button disappeared. The code basically works, but I have no idea this will happen.the button will appear every time when I click it.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TrafficLightPanel extends JPanel implements ActionListener{
private JLabel changeColor;
private Color color;

public TrafficLightPanel(){
    setSize(new Dimension(300,200));    
    setPreferredSize (new Dimension(300, 200));
    color = color.RED;

}
public void paintComponent(Graphics g){
    g.setColor(color);
    g.fillOval(100,100,100,100);
}
public void setColor (Color shade)
{
    color = shade;
}
public void  createButton(){}
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub

}
public static void main(String[] args){
    JFrame frame = new JFrame("Color Circle");
    JButton[] buttons = new JButton[3];
    String[] colors = new String[]{"RED", "GREEN", "BLUE"};
    TrafficLightPanel panel = new TrafficLightPanel()
    {
        @Override
        public void  createButton(){
            for(int i = 0; i < 3; i++)
            {
                // make new button name 

                buttons[i] = new JButton("" + colors[i]);
                if(i == 0)
                    buttons[i].addActionListener(this);
                else if(i == 1)
                    buttons[i].addActionListener(this);
                else if(i == 2)
                    buttons[i].addActionListener(this);

                add(buttons[i]);
                //System.out.println(buttons[i]);
            }
        }
        @Override
        public void actionPerformed(ActionEvent e) {
               if (e.getSource() == buttons[0]) {
                   setColor(Color.RED);
                    repaint();
               } else if (e.getSource() == buttons[1]) {
                   setColor(Color.GREEN);
                    repaint();
               }
               else if (e.getSource() == buttons[2]) {
                   setColor(Color.BLUE);
                    repaint();
                   }
            }

            };
            panel.createButton();   
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


}

}

Upvotes: 0

Views: 35

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285430

Your paintComponent method should call the super's method first thing so that the JPanel will do its housekeeping graphics, which includes removing so-called "dirty" pixels. So:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);  // *** add this ***
    g.setColor(color);
    g.fillOval(100, 100, 100, 100);
}

Myself, I'd do things a bit differently, with some suggestions you can consider or not:

  • Create a JPanel that is just for drawing and nothing else, no buttons, no nothing.
  • Place the JButtons in a different JPanel.
  • Use an enum, perhaps called LightColor, that is for combining a Color with a String, and for using when creating the buttons.
  • In the paintComponent method, cast the Graphics object to a Graphics2D object so we can use RenderingHints to draw smoother circles.
  • Avoid setting any sizes. Instead override setPreferredSize where needed, and let the application's components and the layout managers size themselves by calling pack() on the JFrame after creating it but before displaying it.

For example:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;

import javax.swing.*;

// main GUI JPanel that holds the light drawing JPanel as well as the buttons
@SuppressWarnings("serial")
public class TrafficLightPanel2 extends JPanel {
    private static final int LIGHT_SIZE = 200; // size of the circle
    private static final int GAP = 10; // border gap around the jpanel

    // the Jlight drawing JPanel that draws the circles
    private LightDrawingPanel lightDrawingPanel = new LightDrawingPanel(null, LIGHT_SIZE);

    public TrafficLightPanel2() {
        // JPanel to hold the buttons, 1 row, variable number of columns, gap between buttons
        JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
        for (LightColor lightColor : LightColor.values()) {
            // create each button within the loop, giving it an Action -- an ActionListener "on steroids"
            buttonPanel.add(new JButton(new LightColorAction(lightColor, lightDrawingPanel)));
        }

        setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
        setLayout(new BorderLayout(GAP, GAP));
        add(lightDrawingPanel, BorderLayout.CENTER);  // add the light drawer to the center
        add(buttonPanel, BorderLayout.PAGE_END);  // and the buttons to the bottom
    }

    private static void createAndShowGui() {
        TrafficLightPanel2 mainPanel = new TrafficLightPanel2();

        JFrame frame = new JFrame("Traffic Light");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();  // have layout managers do their thing
        frame.setLocationRelativeTo(null); // center
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

// just acts as a class that connects a Color with a String
enum LightColor {
    RED(Color.RED, "Red"), YELLOW(Color.YELLOW, "Yellow"), GREEN(Color.GREEN, "Green");

    private LightColor(Color color, String text) {
        this.color = color;
        this.text = text;
    }
    private Color color;
    private String text;

    public Color getColor() {
        return color;
    }

    public String getText() {
        return text;
    }

    @Override
    public String toString() {
        return text;
    }
}

// create a class that only draws the circle, and that's it
@SuppressWarnings("serial")
class LightDrawingPanel extends JPanel {
    private Color color;
    private int size;

    public LightDrawingPanel(Color color, int size) {
        this.color = color;
        this.size = size;
    }

    public void setColor(Color color) {
        this.color = color;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);  // again, the super must be called

        // if no color defined, get out of here
        if (color == null) {
            return;
        }

        g.setColor(color);

        // make for smooth rendering 
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // center the circle
        int x = (getWidth() - size) / 2;
        int y = (getHeight() - size) / 2;
        g2.fillOval(x, y, size, size);
    }

    // make our JPanel at least as large as the circle
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(size, size);
    }
}

// AbstractAction for our buttons
// like an ActionListener "on steroids"
@SuppressWarnings("serial")
class LightColorAction extends AbstractAction {
    private LightColor lightColor;
    private LightDrawingPanel lightDrawingPanel;

    public LightColorAction(LightColor lightColor, LightDrawingPanel lightDrawingPanel) {
        super(lightColor.getText());  // text for the button to show

        // initialize our fields
        this.lightColor = lightColor;
        this.lightDrawingPanel = lightDrawingPanel;

        // alt-key mnemonic derived from the text String
        int mnemonic = (int) lightColor.getText().charAt(0);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // set the color of the drawing panel
        lightDrawingPanel.setColor(lightColor.getColor());
    }
}

Upvotes: 3

Related Questions