【问题标题】:Bad Color Referencing?错误的颜色参考?
【发布时间】:2018-11-07 06:14:35
【问题描述】:

我正在设计一款非常类似于 Flow free 的游戏。我在代码中遇到了一个问题,我希望能够单击网格中的一个圆圈,能够测量其颜色,然后检查颜色是否为白色。如果颜色是白色,我会打印错误,现在是一个占位符。但是,即使我单击非白色瓷砖,我仍然会看到正在打印的错误消息。我做错了什么?

我的代码:

import javax.swing.JFrame; //JFrame Class
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Shape;
import java.util.ArrayList;
import javax.swing.JPanel;
import java.awt.geom.Ellipse2D;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;


public class DriverV2 extends JPanel {


static ArrayList<Shape> circles;
static ArrayList<Color> colors;

public DriverV2() {
   circles = new ArrayList<Shape>();
   colors = new ArrayList<Color>();
   colors.add( Color.CYAN);//1
   colors.add( Color.BLUE);//2
   colors.add( Color.WHITE);//3
   colors.add( Color.WHITE);//4
   colors.add( Color.GREEN);//5
   colors.add( Color.WHITE);//6
   colors.add( Color.CYAN);//7
   colors.add( Color.WHITE);//8
   colors.add( Color.WHITE);//9
   colors.add( Color.RED);//10
   colors.add( Color.WHITE);//11
   colors.add( Color.YELLOW);//12
   colors.add( Color.WHITE);//13
   colors.add( Color.GREEN);//14
   colors.add( Color.WHITE);//15
   colors.add( Color.WHITE);//16
   colors.add( Color.BLUE);//17
   colors.add( Color.WHITE);//18
   colors.add( Color.RED);//19
   colors.add( Color.WHITE);//20
   colors.add( Color.WHITE);//21
   colors.add( Color.WHITE);//22
   colors.add( Color.WHITE);//23
   colors.add( Color.WHITE);//24
   colors.add( Color.YELLOW);//25
      int rows = 5;

   for (int y=0;y< rows;y++)
   {
      for (int x=0;x<rows;x++)
    {
        circles.add( new Ellipse2D.Double((x + 1) * 150, (y + 1) *150, 100, 100) );
    }
}
}

protected void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    Color foreground = g2d.getColor();



   int h = 0;
    for (Shape shape : circles)
    {

        g2d.setColor( colors.get(h));
        g2d.draw( shape );
        g2d.fill(shape);
        h++;
    }
}
public static boolean checkLinearity(int index1, int index2){
   if((index1%5) == (index2 %5)) { //vertical line check
      return true;
   }
   if(Math.abs(index1-index2) < 5) { //horizantal line check
      return true;
   }
   else {
      return false;
   }

}
static int counter = 0;
static int index1 = 0;
static int index2 = 0;
public static void main(String[] args)
      {

      JFrame f = new JFrame("Flow"); //new JFrame
      DriverV2 t = new DriverV2();
      f.setSize(900,900);//sets size of frame
      //  f.setLocation(100,50);//sets location of frame
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//sets default close operation
      //  f.setContentPane(new Panel()); //sets content pane
      f.setVisible(true);//makes panel visible
      f.add(t);
      f.addMouseListener( new MouseAdapter() {
         public void mouseClicked(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();

         for (Shape shape: circles) {

            if (shape.contains(x,y)) {
               counter++;
               if(counter % 2 == 1) {
                  index1 = circles.indexOf(shape)+1;
                  if(Color.WHITE.equals(colors.get(index1))) {
                     counter--;
                     System.out.println("error");
                  }
               }
               else{
                  index2 = circles.indexOf(shape) +1;
                  if(checkLinearity(index1, index2) == true) {
                     //I want to be able to draw a rectange here
                  }
               }


         }
}
         }
      });

}
}

【问题讨论】:

  • 我们可以看看你的class Shape吗?
  • 请注意,索引是从 0 开始的,因此 colors.get(index1) 可能是由于 index1 = circles.indexOf(shape)+1; 而导致的。顺便说一句,既然您正在迭代circles,那么就不需要circles.indexOf(shape) - 只需计算循环迭代次数(再次从0开始)。更好的是,创建一个包含形状和颜色的类Circle。这样,形状和颜色的索引就不会因为编程错误而失去同步。
  • @Thomas 我知道情况并非如此,因为我尝试单击网格中的所有内容并且每次打印错误消息时
  • @mackycheese21 Shape 是一个内置的 java 接口,只需 google 其文档
  • @mackycheese21:他没有“类”形状。他引用了核心 Java Shape 接口。请检查导入。

标签: java swing colors panel paint


【解决方案1】:

此外,除了 Thomas 提到的(他的回答中 1+)之外,不要将 MouseListener 添加到 JFrame。将其添加到正在绘图的 JPanel 中,否则您的 x 和 y 位置将关闭。

我自己,我会使用 JLabels 网格,即包含图标的标签。您甚至可以将标签的行和列值作为可以检索的属性。如果这是您的目标,这将允许轻松交换图标,并且可以轻松检索 哪个 网格单元被按下。

一些优点:

  • 如果 JLabels 也被放入 List&lt;JLabel&gt; 中,那么如果您需要随机放置颜色,它们可以很容易地洗牌
  • 白色的错误测试很容易。只需从选定的 JLabel 中获取图标并使用白色图标测试是否相等:if (label.getIcon == whiteIcon)
  • 同样,获取所选磁盘的行/列位置很容易,因为它是 JLabel 本身的固有属性,可以通过在 JLabel 上调用 getClientProperty 来检索,例如:label1.getClientProperty(ROW);
  • 如果您需要连续检查两次鼠标按下,请将第一次鼠标按下的结果保存到类的一个字段中,这里是一个名为 label1 的 JLabel。

例如:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.*;

public class DriverV2b extends JPanel {
    private static final String ROW = "row";
    private static final String COLUMN = "column";
    private static final int DIM = 5;
    private static final int ICON_WIDTH = 150;
    private static final int CIRCLE_WIDTH = 100;
    private JLabel[][] labelGrid = new JLabel[DIM][DIM];
    private Icon whiteIcon = createIcon(Color.WHITE);
    private Icon blueIcon = createIcon(Color.BLUE);
    private Icon greenIcon = createIcon(Color.GREEN);
    private Icon yellowIcon = createIcon(Color.YELLOW);
    private Icon redIcon = createIcon(Color.RED);
    private Icon[] coloredIcons = {blueIcon, greenIcon, yellowIcon, redIcon};
    private JLabel label1 = null;

    public DriverV2b() {
        // grid to hold the JLabels
        setLayout(new GridLayout(DIM, DIM));

        // mouse listener to add to all JLabels
        MyMouse myMouse = new MyMouse();

        // list of JLabels so we can shuffle them for random placement
        List<JLabel> labels = new ArrayList<>();
        for (int row = 0; row < labelGrid.length; row++) {
            for (int col = 0; col < labelGrid[row].length; col++) {
                // initially give all a white icon
                labelGrid[row][col] = new JLabel(whiteIcon);

                // add mouselistener
                labelGrid[row][col].addMouseListener(myMouse);

                // client property so we know what row and column the label is on
                labelGrid[row][col].putClientProperty(ROW, row);
                labelGrid[row][col].putClientProperty(COLUMN, col);

                // add JLabel to the array list
                labels.add(labelGrid[row][col]);

                // add it to the GUI
                add(labelGrid[row][col]);
            }
        }

        // shuffle the array list of JLabels, so we can add colored icons randomly
        Collections.shuffle(labels);

        // for each colored icon in the array, add *two** to the list
        for (int i = 0; i < coloredIcons.length; i++) {
            int index = 2 * i;
            labels.get(index).setIcon(coloredIcons[i]);
            labels.get(index + 1).setIcon(coloredIcons[i]);
        }
    }

    private Icon createIcon(Color color) {
        int w = ICON_WIDTH;
        BufferedImage img = new BufferedImage(w, w, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();

        // rendering hints used to smooth the image edges
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(color);
        int width = CIRCLE_WIDTH;
        int x = (ICON_WIDTH - CIRCLE_WIDTH) / 2;
        g2.fillOval(x, x, width, width);
        g2.dispose();
        return new ImageIcon(img);
    }

    private class MyMouse extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            JLabel label = (JLabel) e.getSource();
            if (label.getIcon() == whiteIcon) {
                System.out.println("error -- ignoring this press");
                return;
            }

            if (label1 == null) {
                // first press
                label1 = label;
            } else {
                JLabel label2 = label;
                int row1 = (int) label1.getClientProperty(ROW);
                int col1 = (int) label1.getClientProperty(COLUMN);
                int row2 = (int) label2.getClientProperty(ROW);
                int col2 = (int) label2.getClientProperty(COLUMN);

                Icon icon1 = label1.getIcon();
                Icon icon2 = label2.getIcon();

                // just to show that this works:
                System.out.printf("Locaions: [%d, %d] [%d, %d]%n",
                        row1, col1, row2, col2);

                if (checkLinearity(row1, col1, row2, col2)) {
                    // TODO: do something
                }

                label1 = null; // reset this
            }
        }

        private boolean checkLinearity(int row1, int col1, int row2, int col2) {
            // TODO finish this method
            return false;
        }
    }

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

        JFrame frame = new JFrame("DriverV2b");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

添加了 whiteIcon press 的错误测试

【讨论】:

    【解决方案2】:

    您的问题似乎是为什么许多人(包括我)提倡总是添加花括号的另一个例子(即使在 1 语句块上 - 他们可能不会保持这种状态):

    看看这个sn-p:

    if (shape.contains(x,y)) 
       counter++;
         if(counter % 2 == 1) {
          ...
    

    它不会按照你的想法做,即如果你点击形状 counter 得到增加,但其余的检查是针对 每个 形状执行的。那是因为对于编译器来说,代码是这样的:

    if (shape.contains(x,y)) 
       counter++;
    if(counter % 2 == 1) {
      ...
    

    因此,当您点击一个圆圈时,counter 将为 1,因此对于之后检查的每个圆圈,counter % 2 == 1 将为 true。

    因此,在缩进的代码周围添加花括号。此外,一旦检测到命中,您可能希望中断循环,因为您可能对检查所有其他圈子也不感兴趣。

    您可能还想引入一个类Circle,它可能看起来像这样:

    class Circle {
      Shape shape;
      Color color;
    
      ... //additional properties, e.g. position, and methods
    
      public boolean wasHit(int x, int y) {
        return shape.contains(x,y);
      }
    
      public boolean isValid() {
        return Color.WHITE.equals( color );
      }
    }
    

    然后你会像这样迭代那些:

    for( Circle circle : circles ) {
      if( circle.wasHit(x, y) {
        if( circle.isValid() ) {
          //do what you'd need here, e.g. change the shape to a rectangle
        } else {
          //error
        }
    
        //break the loop since other circles can't be hit or we're not interested in those
        break;
      }
    }
    

    【讨论】:

    • 我已经添加了花括号,但我的代码似乎仍然无法正常工作。我已经更新了问题代码以匹配现在。
    • @shuryusd 我在您更新的帖子中没有看到花括号。您添加了一些,但位置错误 - 请仔细阅读我的回答。
    • @shuryusd 现在看起来好多了
    • 我现在明白了,我只需要删除我在索引中使用的 +1,它现在可以工作了。谢谢!
    猜你喜欢
    • 2020-05-05
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    • 2014-08-19
    • 2019-07-13
    • 2011-02-16
    • 2011-11-15
    相关资源
    最近更新 更多