Java:Graphics2D - JPopupMenu - 变色

时间:2017-05-12 19:27:02

标签: java graphics2d

我正在编写一个简单的图形编辑器,到目前为止我可以绘制一些数字,移动和放大它们。我试图让用户改变图形的颜色。在我右键单击一个形状后,会出现一个带有颜色的弹出菜单供选择。但无论我做什么 - 形状的颜色都不会改变。 :/我希望得到帮助,我花了很多时间在上面,但不知道如何解决它。 :/

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

import java.util.ArrayList;

public class PaintPanel extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener
{
    public RadioMenu radio = new RadioMenu();
    private ArrayList <Point2D.Double> points = new ArrayList<>();
    private ArrayList <Shape> figures = new ArrayList<>();

    private Color mainColor = Color.blue;
    private Color bgColor = Color.white;
    private Color special = Color.red;
    private double scrollSpeed = 5;
    private int pointsize = 4;
    private int near = 15;

    private int index;
    private ColorMenu colorMenu = new ColorMenu();

    public PaintPanel()
    {
        super();
        addMouseListener(this);
        addMouseMotionListener(this);
        addMouseWheelListener(this);
        setLayout(new BorderLayout());
        setBackground(bgColor);
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        drawGraphics(g2d);
    }

    private void drawGraphics(Graphics2D g2d)
    {
        int i = 0;
        for (Shape s : figures)
        {

            g2d.setColor(mainColor);
            if (s instanceof MyEllipse2D)
            {
                g2d.setColor(((MyEllipse2D) s).color);
                System.out.println(g2d.getColor());
            }
            else if (s instanceof MyRectangle2D)
            {
                g2d.setColor(((MyRectangle2D) s).color);
                System.out.println(g2d.getColor());
            }
            else if (s instanceof MyPolygon2D)
            {
                g2d.setColor(((MyPolygon2D) s).color);
                System.out.println(g2d.getColor());
            }

            if (g2d.getColor() != bgColor)
            {
                g2d.setColor(mainColor);
            } else
            {
                g2d.setColor(mainColor);
                g2d.draw(s);
            }


            ++i;
        }

            i = 0;
            for (Point2D.Double p : points)
            {
                if (i == 0)
                {
                    g2d.setColor(special);
                    g2d.fillOval((int) p.getX(), (int) p.getY(), pointsize, pointsize);
                    g2d.setColor(mainColor);
                } else
                {
                    g2d.fillOval((int) p.getX(), (int) p.getY(), pointsize, pointsize);
                }
                ++i;
            }
        }

    @Override
    public void mousePressed(MouseEvent e)
    {
        if(e.getButton()==MouseEvent.BUTTON1)
            switch (radio.getChoice())
            {
                case "Okrag":
                    points.clear();
                    points.add(new Point2D.Double(e.getX(),e.getY()));
                    repaint();
                    break;

                case "Prostokat":
                    points.clear();
                    points.add(new Point2D.Double(e.getX(),e.getY()));
                    repaint();
                    break;

                case "Edycja":
                    index = isSelected(e);
                    break;
            }
        else if(e.getButton()==MouseEvent.BUTTON3 && radio.getChoice().equals("Edycja"))
            {
                index = isSelected(e);
                if(index >= 0)
                {
                    colorMenu.doPop(e);
                }

            }

    }

    @Override
    public void mouseReleased(MouseEvent e)
    {
        if(e.getButton()==MouseEvent.BUTTON1)
            switch (radio.getChoice())
            {
                case "Okrag":
                    points.add(new Point2D.Double(e.getX(),e.getY()));
                    figures.add(new MyEllipse2D(points.get(0),points.get(1),bgColor));
                    points.clear();
                    break;

                case "Prostokat":
                    points.add(new Point2D.Double(e.getX(),e.getY()));
                    figures.add(new MyRectangle2D(points.get(0),points.get(1),bgColor));
                    points.clear();
                    break;

                case "Wielokat":
                    if(points.size() != 0 && points.get(0).distance(e.getX(),e.getY())<=near)
                    {
                        figures.add(new MyPolygon2D(points,bgColor));
                        points.clear();
                    }
                    else
                    {
                        points.add(new Point2D.Double(e.getX(),e.getY()));
                    }
                    break;
                case "Edycja":
                    points.clear();
            }
        repaint();
    }

    @Override
    public void mouseDragged(MouseEvent e)
    {
        if(index>=0 && radio.getChoice().equals("Edycja"))
        {
            if (figures.get(index) instanceof MyEllipse2D)
            {
                ((MyEllipse2D) figures.get(index)).move(new Point2D.Double(e.getX(),e.getY()));
            }
            else if (figures.get(index) instanceof MyRectangle2D)
            {
                ((MyRectangle2D) figures.get(index)).move(new Point2D.Double(e.getX(),e.getY()));
            }
            else if(figures.get(index) instanceof MyPolygon2D)
            {
                ((MyPolygon2D) figures.get(index)).move(new Point2D.Double(e.getX(),e.getY()));
            }
            repaint();
        }
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e)
    {
        index = isSelected(e);
        if(radio.getChoice().equals("Edycja"))
        {
            if (index>=0)
            {
                if (figures.get(index) instanceof MyEllipse2D)
                {
                    ((MyEllipse2D) figures.get(index)).scale(e.getPreciseWheelRotation(), scrollSpeed);
                }
                else if (figures.get(index) instanceof MyRectangle2D)
                {
                    ((MyRectangle2D) figures.get(index)).scale(e.getPreciseWheelRotation(), scrollSpeed);
                }
                else if(figures.get(index) instanceof MyPolygon2D)
                {
                    ((MyPolygon2D) figures.get(index)).scale(e.getPreciseWheelRotation(), scrollSpeed);
                }
                repaint();
            }
        }
    }

    private int isSelected(MouseEvent e)
    {
        int i;
        for(i=figures.size()-1;i>=0;--i)
        {
            if(figures.get(i).contains(e.getPoint()))
            {
                return i;
            }
        }
        return -1;
    }

    @Override
    public void mouseClicked(MouseEvent e)
    {
        index = isSelected(e);
        if(index >= 0 )
        {
            colorMenu.doPop(e);
            if(e.getButton()==MouseEvent.BUTTON3 && radio.getChoice().equals("Edycja"))
            {
                colorMenu.doPop(e);
                if(figures.get(index) instanceof MyEllipse2D)
                    ((MyEllipse2D) figures.get(index)).color = colorMenu.color;
                else if(figures.get(index) instanceof MyRectangle2D)
                    ((MyRectangle2D) figures.get(index)).color = colorMenu.color;
                else if(figures.get(index) instanceof MyPolygon2D)
                    ((MyPolygon2D) figures.get(index)).color = colorMenu.color;
                System.out.println(colorMenu.color);
                //colorMenu.color = bgColor;
            }
            repaint();
        }



    }

    @Override
    public void mouseEntered(MouseEvent e)
    {
    }

    @Override
    public void mouseExited(MouseEvent e)
    {
    }

    @Override
    public void mouseMoved(MouseEvent e)
    {
    }
}

ColorMenu

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

public class ColorMenu extends JPopupMenu implements ActionListener
{
    private ArrayList<JMenuItem> items = new ArrayList<JMenuItem>();
    private ArrayList<Color> colors = new ArrayList<Color>();

    public Color color;

    public ColorMenu()
    {
        super();
        colors.add(Color.black);
        colors.add(Color.blue);
        colors.add(Color.cyan);
        colors.add(Color.gray);
        colors.add(Color.green);
        colors.add(Color.magenta);
        colors.add(Color.orange);
        colors.add(Color.red);
        colors.add(Color.yellow);
        colors.add(Color.white);

        for (Color c : colors)
        {
            items.add(new JMenuItem(c.toString()));
        }

        for(JMenuItem i: items)
        {
            i.addActionListener(this);
            add(i);
        }

    }

    public void doPop(MouseEvent e)
    {
        show(e.getComponent(), e.getX(), e.getY());
    }


    @Override
    public void actionPerformed(ActionEvent e)
    {
        Object source = e.getSource();
        int j=0;
        for(JMenuItem i: items)
        {
            if(i == source)
            {
                break;
            }
            ++j;
        }
        this.color = colors.get(j);
    }
}

MyRectangle2D

import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

public class MyRectangle2D extends Rectangle2D.Double implements Shape
{
    private Point2D.Double center;
    private double width,hight;
    public Color color;

    public MyRectangle2D()
    {}

    public MyRectangle2D(Point2D.Double p1, Point2D.Double p2, Color color)
    {
        super();
        this.color = color;

        double x1 = p1.getX();
        double y1 = p1.getY();
        double x2 = p2.getX();
        double y2 = p2.getY();

        if(x1<=x2 && y1>=y2)
        {
            width=x2-x1;
            hight=y1-y2;
            setRect(x1,y2,width,hight);
        }
        else if(x1<=x2 && y1<=y2)
        {
            width=x2-x1;
            hight=y2-y1;
            setRect(x1,y1,width,hight);
        }
        else if (x1>=x2 && y1<=y2)
        {
            width=x1-x2;
            hight=y2-y1;
            setRect(x2,y1,width,hight);
        }
        else if(x1>=x2 && y1>=y2)
        {
            width=x1-x2;
            hight=y1-y2;
            setRect(x2,y2,width,hight);
        }

        center = new Point2D.Double(x1 + (x2-x1)/2,y1+(y2-y1)/2);
    }

    public void scale(double amount, double scale)
    {
        double change = -1*amount*scale;
        width += change;
        hight += change;
        setRect(center.getX()-width/2,center.getY()-hight/2,width,hight);
    }

    public void move (Point2D.Double p)
    {
        center = p;
        setRect();
    }

    private void setRect()
    {
        setRect(center.getX()-width/2,center.getY()-hight/2,width,hight);
    }
}

MyPolygon2D

import java.awt.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;

public class MyPolygon2D extends Polygon implements Shape
{
    private ArrayList<MyVector> vectors = new ArrayList<>();
    private Point2D.Double center;
    private int size;
    public Color color;

    public MyPolygon2D()
    {}

    public MyPolygon2D(ArrayList<Point2D.Double> points, Color color)
    {
        super();

        this.color = color;

        size = points.size();

        for(int i=0; i<size;++i)
        {
            addPoint((int)points.get(i).getX(),(int)points.get(i).getY());
        }

        center();
        setVectors();
    }

    public void scale(double amount, double scale)
    {
        double change = -1*amount*scale;

        for (int i=0;i<size;++i)
        {
            vectors.get(i).x *= (100.0+change)/100.0;
            vectors.get(i).y *= (100.0+change)/100.0;

            Point2D.Double curr = new Point2D.Double(center.getX()+vectors.get(i).x,center.getY()+vectors.get(i).y);

            xpoints[i] = (int)curr.getX();
            ypoints[i] = (int)curr.getY();
        }
        invalidate();
    }

    public void move (Point2D.Double p)
    {
        MyVector change = new MyVector(center,p);
        center = p;

        for(int i=0;i<size;++i)
        {
            xpoints[i] += (int)change.x;
            ypoints[i] += (int)change.y;
        }
        invalidate();
    }

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

    public Color getColor()
    {
        return this.color;
    }

    @Override
    public boolean contains(Point p)
    {
        int maxx=0, maxy=0, minx=Integer.MAX_VALUE, miny=Integer.MAX_VALUE;

        for (int i=0;i<size;++i)
        {
            if(xpoints[i]>=maxx)
                maxx = xpoints[i];
            if(xpoints[i]<=minx)
                minx = xpoints[i];
            if(ypoints[i]>=maxy)
                maxy = ypoints[i];
            if(ypoints[i]<=miny)
                miny = ypoints[i];
        }
        if(p.getX() <= maxx && p.getX() >= minx && p.getY() <= maxy && p.getY() >=miny)
            return true;
        else
            return false;
    }
    private void setVectors()
    {
        for(int i=0; i<size;++i)
        {
            vectors.add(new MyVector(center,new Point2D.Double(xpoints[i],ypoints[i])));
        }
    }

    private void center()
    {
        center = new Point2D.Double(getBounds2D().getX()+getBounds2D().getWidth()/2,getBounds2D().getY()+getBounds2D().getHeight()/2);
    }

    private class MyVector
    {
        public double x, y;

        public MyVector(Point2D.Double p1, Point2D.Double p2)
        {
            x=p2.getX()-p1.getX();
            y=p2.getY() - p1.getY();
        }
    }
}

MyEllipse2D

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;

public class MyEllipse2D extends Ellipse2D.Double implements Shape
{
    private double radius;
    private Point2D.Double center;
    public Color color;


    public MyEllipse2D(Point2D.Double p1, Point2D.Double p2, Color color)
    {
        super();
        this.color = color;
        center = p1;
        radius = (p1.distance(p2));
        setFrame();
    }

    public void scale(double amount, double scale)
    {
        double change = -1*amount*scale;
        radius += change;
        setFrame();
    }

    public void move (Point2D.Double p)
    {
        center = p;
        setFrame();
    }

    public void setColor(Color color)
    {
        this.color = color;
        System.out.println(this.color);
    }

    public Color getColor()
    {
        return this.color;
    }

    private void setFrame()
    {
        setFrame(center.getX()-radius,center.getY()-radius,2*radius,2*radius);
    }
}

RadioMenu

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

public class RadioMenu extends JPanel
{
    private int amount = 4;

    private JRadioButton[] options = new JRadioButton[amount];
    private ButtonGroup group = new ButtonGroup();

    private String[] names = {"Okrag","Prostokat","Wielokat","Edycja"};


    private Font font = new Font("Times New Roman",Font.BOLD,16);

    public RadioMenu()
    {
        super();
        setLayout(new GridLayout(1,amount));

        for(int i=0;i<amount;++i)
        {
            if(i!=0)
                options[i] = new JRadioButton(names[i],false);
            else
                options[i] = new JRadioButton(names[i],true);

            group.add(options[i]);
            add(options[i]);
            options[i].setFont(font);
        }
    }

    public String getChoice()
    {
        for(int i=0; i<amount; ++i)
        {
            if(options[i].isSelected())
                return options[i].getText();
        }
        return "";
    }
}

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

public class Frame extends JFrame
{
    private Dimension prefsize = new Dimension(800,600);
    private Dimension minSize = new Dimension(400,200);
    private Menu menu = new Menu();
    private PaintPanel panel = new PaintPanel();


    public Frame()
    {
        super();
        setVisible(true);
        setPreferredSize(prefsize);
        setMinimumSize(minSize);
        setLayout(new BorderLayout());
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        add(panel,BorderLayout.CENTER);

        JPanel upper = new JPanel();
        upper.setLayout(new GridLayout(2,1));
        upper.add(menu);
        upper.add(panel.radio);

        add(upper,BorderLayout.NORTH);
        pack();

    }
}

MyAplet

import javax.swing.*;

    public class MyAplet extends JApplet
    {
        public void init()
        {
            Frame main = new Frame();
        }
    }

菜单

import javax.swing.*;

public class Menu extends JMenuBar
{
    private JMenu info;
    //private JMenuItem x;
    public Menu()
    {
        super();
        info = new JMenu("info");
        //info.add(x);
        add(info);
    }
}

2 个答案:

答案 0 :(得分:0)

首先,您应该显示JPopupMenu以仅响应一种类型的事件。您当前正在mousePressed方法中调用colorMenu.doPop(e),在mouseClicked方法中调用两次。

为了确保只在你应该的时候显示JPopupMenu,你应该使用JPopupMenu.isPopupTrigger方法。这样,菜单将显示在mousePress mouseClick上,但不会同时显示。您不希望多次显示JPopupMenu以响应单个鼠标操作!

private int selectedIndex = -1;

// ...

@Override
public void mousePressed(MouseEvent e)
{
    selectedIndex = isSelected(e);
    if (colorMenu.isPopupTrigger(e)) {
        colorMenu.doPop(e);
    } else if (e.getButton() == MouseEvent.BUTTON1) {

// ...

@Override
public void mouseClicked(MouseEvent e)
{
    if (selectedIndex >= 0 && colorMenu.isPopupTrigger(e) && radio.getChoice().equals("Edycja"))
    {
        colorMenu.doPop(e);

下一个问题是您在用户进行颜色选择之前尝试阅读colorMenu.color。当您致电colorMenu.doPopup(e)时,会显示菜单并立即返回该方法。它不等待用户进行选择并关闭菜单。您的代码正在尝试立即使用colorMenu.color,但尚未设置。

了解用户何时选择颜色的唯一方法是使用ActionListener。您的ColorMenu类有一个ActionListener,但是目前PaintPanel类无法知道ActionListener何时被触发。

您可以使用继承的listenerList对象为ColorMenu类提供通知其他类中的侦听器的功能:

public void addChangeListener(ChangeListener listener) {
    listenerList.add(ChangeListener.class, listener);
}

public void removeChangeListener(ChangeListener listener) {
    listenerList.remove(ChangeListener.class, listener);
}

public ChangeListener[] getChangeListeners() {
    return listenerList.getListeners(ChangeListener.class);
}

protected void fireChangeListeners() {
    ChangeEvent event = new ChangeEvent(this);
    for (ChangeListener listener : getChangeListeners()) {
        listener.stateChanged(event);
    }
}

(ChangeListener和ChangeEvent位于javax.swing.event包中。)

这允许其他类监听用户选择。您想要更改ColorMenu以实际通知这些侦听器:

@Override
public void actionPerformed(ActionEvent e)
{
    // (other code) ...

    this.color = colors.get(j);
    fireChangeListeners();
}

现在,您可以让PaintPanel监听用户选择:

public PaintPanel()
{
    super();
    addMouseListener(this);
    addMouseMotionListener(this);
    addMouseWheelListener(this);
    setLayout(new BorderLayout());
    setBackground(bgColor);

    colorMenu.addChangeListener(new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent event) {
            if (selectedIndex >= 0)
            {
                Shape figure = figures.get(selectedIndex);
                if (figure instanceof MyEllipse2D)
                    ((MyEllipse2D) figure).color = colorMenu.color;
                else if (figure instanceof MyRectangle2D)
                    ((MyRectangle2D) figure).color = colorMenu.color;
                else if (figure instanceof MyPolygon2D)
                    ((MyPolygon2D) figure).color = colorMenu.color;
            }
        }
    });
}

您应该从mouseClicked删除该换色代码,因为在那里调用它永远无效,因为用户尚未选择颜色:

@Override
public void mouseClicked(MouseEvent e)
{
    if (selectedIndex >= 0 && colorMenu.isPopupTrigger(e) && radio.getChoice().equals("Edycja"))
    {
        colorMenu.doPop(e);
        // Nothing else to do here, since the user has not selected a color yet.
    }
}

答案 1 :(得分:0)

基本问题是,您需要知道何时从菜单中选择颜色。可以通过多种不同方式解决问题。

您可以继续使用MouseListener来监控mousePressedmouseReleasedmouseClicked事件,但您应该使用MouseEvent#isPopupTrigger属性确定何时应显示弹出窗口,因为不同平台的触发器不同。

另一种解决方案是使用JComponent#setComponentPopupMenu所有组件来处理动作本身。然而,这需要稍微改变设计。

这种方法将责任重新放回到组件上,而不是分成不同的类,就像你现在拥有ColorMenu一样。

首先,我们需要知道所选的形状,因此,对于PaintPanel,我们需要添加一个新属性

private Shape selectedShape;

所有这一切都决定了用户选择了哪种形状。

接下来我们需要更新形状颜色。这可以通过简单地向paintPanel方法添加新方法来实现,该方法在要更改颜色时调用。

public void setShapeColor(Color color) {
    //...
}

接下来,我们利用Action API创建一个简单的ColorAction

这是一个独立的工作单元,其中包含需要在菜单(或按钮)上显示的信息,并确定触发时要采取的操作。

public class ColorAction extends AbstractAction {

    private Color color;

    public ColorAction(String name, Color color) {
        super(name);
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    @Override
    public boolean isEnabled() {
        return getSelectedShape() != null;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        setShapeColor(color);
    }

}

在这种情况下,PaintPanel这个简单的内部类会在触发时调用setShapeColor

“但是等等”,我听到你说:“只有选择了一个形状才能选择颜色!”啊,我们可以通过Action方法控制isEnabled,只有在实际选择了形状时才会返回true。

这可能看起来有点违反直觉,但是当没有显示任何内容时不显示弹出菜单,它会让用户认为永远不会显示任何弹出菜单,至少这样,我们可以显示带有选项的弹出菜单禁用。

下一个技巧是尝试确定所选内容。不幸的是,在我的测试过程中,操作系统消耗了mousePressed事件,这对于做出这个决定是最有用的,但是并不是全部都会丢失。

JComponent会在弹出窗口显示之前调用getPopupLocation,传入触发它的MouseEvent,我们可以利用此功能来确定选择哪种形状< / p>

@Override
public Point getPopupLocation(MouseEvent event) {
    selectedShape = null;
    for (int i = figures.size() - 1; i >= 0; --i) {
        if (figures.get(i).contains(event.getPoint())) {
            selectedShape = figures.get(i);
        }
    }
    return super.getPopupLocation(event);
}

更完整的例子......

public class PaintPanel extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener {

    private ArrayList<Point2D.Double> points = new ArrayList<>();
    private ArrayList<Shape> figures = new ArrayList<>();

    private Shape selectedShape;

    private Color mainColor = Color.blue;
    private Color bgColor = Color.white;
    private Color special = Color.red;
    private double scrollSpeed = 5;
    private int pointsize = 4;
    private int near = 15;

    private int index;

    public PaintPanel() {
        super();
        addMouseListener(this);
        addMouseMotionListener(this);
        addMouseWheelListener(this);
        setLayout(new BorderLayout());
        setBackground(bgColor);
        setComponentPopupMenu(makePopupMenu());
    }

    protected JPopupMenu makePopupMenu() {
        JPopupMenu menu = new JPopupMenu();
        menu.add(new ColorAction("Black", Color.black));
        menu.add(new ColorAction("Blue", Color.blue));
        menu.add(new ColorAction("Cyan", Color.cyan));
        menu.add(new ColorAction("Grey", Color.gray));
        menu.add(new ColorAction("Green", Color.green));
        menu.add(new ColorAction("Megenta", Color.magenta));
        menu.add(new ColorAction("Orange", Color.orange));
        menu.add(new ColorAction("Red", Color.red));
        menu.add(new ColorAction("Yellow", Color.yellow));
        menu.add(new ColorAction("White", Color.white));

        return menu;
    }

    public Shape getSelectedShape() {
        return selectedShape;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public Point getPopupLocation(MouseEvent event) {
        selectedShape = null;
        for (int i = figures.size() - 1; i >= 0; --i) {
            if (figures.get(i).contains(event.getPoint())) {
                selectedShape = figures.get(i);
            }
        }
        return super.getPopupLocation(event);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        //...
    }

    @Override
    public void mousePressed(MouseEvent e) {
        //...
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        //...
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        //...
    }

    @Override
    public void mouseExited(MouseEvent e) {
        //...
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        //...
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        //...
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        //...
    }

    public void setShapeColor(Color color) {
        //...
    }

    public class ColorAction extends AbstractAction {

        private Color color;

        public ColorAction(String name, Color color) {
            super(name);
            this.color = color;
        }

        public Color getColor() {
            return color;
        }

        @Override
        public boolean isEnabled() {
            return getSelectedShape() != null;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setShapeColor(color);
        }

    }

}

您可以通过其他几种方式实现这一目标,但我将使用这些基本原则是设计的基石。

例如,你可以有一个“颜色模型”,它被传递给弹出菜单类,当选择颜色时会更新