用额外的颜色为形状上色

Posted

技术标签:

【中文标题】用额外的颜色为形状上色【英文标题】:Coloring shapes in order with extra colors 【发布时间】:2014-12-26 23:24:02 【问题描述】:

我正在制作一个程序,允许用户在屏幕上绘制多个形状并选择所需的颜色。目前,我有九种预设颜色可供用户选择。我计划使用JColorChooser 来允许用户选择不同的颜色。但是,我无法找到一种方法来存储可以选择的额外颜色,以便在重新绘制绘制的形状时,它们将保持与绘制时相同的颜色。

我想出了一种方法,可以按照绘制的顺序和绘制时使用的颜色重新绘制形状,如下所示:

private List<Shape> shapeList = new ArrayList<Shape>();
private List<Integer> opNumList = new ArrayList<Integer>();

@Override
protected void paintComponent(Graphics g) 
    super.paintComponent(g);
    int index = 0;
    Graphics2D g2 = (Graphics2D) g.create();

    if (!opNumList.isEmpty()) 
        for (Shape s : shapeList) 
            switch (opNumList.get(index))
                case  0: g2.setColor(Color.red);    g2.draw(s); break;
                case  1: g2.setColor(Color.red);    g2.fill(s); break;
                case  2: g2.setColor(Color.orange); g2.draw(s); break;
                case  3: g2.setColor(Color.orange); g2.fill(s); break;
                case  4: g2.setColor(Color.yellow); g2.draw(s); break;
                case  5: g2.setColor(Color.yellow); g2.fill(s); break;
                case  6: g2.setColor(Color.green);  g2.draw(s); break;
                case  7: g2.setColor(Color.green);  g2.fill(s); break;
                case  8: g2.setColor(Color.blue);   g2.draw(s); break;
                case  9: g2.setColor(Color.blue);   g2.fill(s); break;
                case 10: g2.setColor(purple);       g2.draw(s); break;
                case 11: g2.setColor(purple);       g2.fill(s); break;
                case 12: g2.setColor(brown);        g2.draw(s); break;
                case 13: g2.setColor(brown);        g2.fill(s); break;
                case 14: g2.setColor(Color.white);  g2.draw(s); break;
                case 15: g2.setColor(Color.white);  g2.fill(s); break;
                case 16: g2.setColor(Color.black);  g2.draw(s); break;
                case 17: g2.setColor(Color.black);  g2.fill(s); break;
                default: return;
            
            index++;
        
    


@Override
public void mouseReleased(MouseEvent ev) 
    if (color == Color.red) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(0);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(1);
    

    if (color == Color.orange) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(2);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(3);
    

    if (color == Color.yellow) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(4);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(5);
    

    if (color == Color.green) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(6);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(7);
    

    if (color == Color.blue) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(8);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(9);
    

    if (color == purple) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(10);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(11);
    

    if (color == brown) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(12);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(13);
    

    if (color == Color.white) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(14);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(15);
    

    if (color == Color.black) 
        if (toolNum == LINE || (toolNum == RECTANGLE && !cbFillItem.isSelected()) || (toolNum == OVAL && !cbFillItem.isSelected()))
            opNumList.add(16);
        if ((toolNum == RECTANGLE || toolNum == OVAL) && cbFillItem.isSelected())
            opNumList.add(17);
    
    repaint();

所以发生的情况是,当用户绘制一个形状时,它存储在ArrayListShape 对象中。根据绘制的形状及其颜色,整数存储在单独的列表中。然后当程序重绘所有形状时,它会遍历列表中的每个形状,并为形状赋予它们绘制时使用的颜色,并在必要时填充它们。

现在,我想弄清楚的是一种将这些颜色转移到它们自己的 List 甚至是 Map 的方法,以避免创建大量 Color 对象并添加到已经长长的代码列表,这样如果用户决定使用其他颜色,程序就会知道什么颜色属于什么形状。例如,如果用户决定绘制一个颜色为 128,128,128 的填充矩形;当程序重绘形状时,它将知道矩形已被填充并被着色为特定的灰色阴影。但我还没有走那么远。现在,我正在尝试找到一种仅适用于我目前拥有的九种颜色的解决方案。

有没有人知道如何做到这一点?

【问题讨论】:

【参考方案1】:

我花了一些研究和环顾四周,但我终于找到了解决问题的方法。

最初我考虑使用Map,这样我就可以添加一个键值对,只要我可以访问地图的所有键(实现Shape 接口的对象),我就可以配对他们的价值观(Color 对象)很容易。所以我想出了这个:

Map<Shape,Color> map = new HashMap<Shape,Color>();

这使我可以存储用户绘制的任何形状以及使用的相应颜色。但是现在我必须找到一种方法来使用for 循环检索所有存储的形状,以便我可以重新绘制它们。做了一些研究,我遇到了this answer,它展示了如何使用所述循环遍历Map。所以我可以用这个替换switch 语句:

for (Entry<Shape,Color> entry : map.entrySet()) 
    Shape shape = entry.getKey();
    Color color = entry.getValue();

    g2.setColor(color);
    g2.draw(shape);

但是,我遇到了另一个问题:键值对不按顺序排列,这意味着某些形状会随机出现在其他形状之前,而它们之前在它们之后,反之亦然。所以更多的研究帮助我确定我应该改用LinkedHashMap,它保留了键值对的存储顺序:

Map<Shape,Color> map = new LinkedHashMap<Shape,Color>();

一些反复试验帮助我意识到,由于键值对保证保持有序,我总是可以使用opNumList 来确定给定的形状是打开还是填充。

int index = 0;
for (Entry<Shape,Color> entry : map.entrySet()) 
    Shape shape = entry.getKey();
    Color color = entry.getValue();

    g2.setColor(color);
    if (!opNumList.isEmpty()) 
        if (opNumList.get(index) == 0)
            g2.draw(shape);
        if (opNumList.get(index) == 1)
            g2.fill(shape);
    
    index++;

【讨论】:

以上是关于用额外的颜色为形状上色的主要内容,如果未能解决你的问题,请参考以下文章

icon镂空上色 & currentcolor关键字

使用JS控制图片形状

如何在 Visual C++ 中使用具有颜色和形状的工具栏创建绘图应用程序

达到边界颜色时,填充无法填充整个形状?

AI实时上色的底色怎么变透明呢?

我想在 UIView 上绘制像苹果形状这样的自定义形状