简体   繁体   English

使用带有 Swing 的鼠标绘制(单色)数组的最简单方法是什么?

[英]What's the easiest way to draw a (monochrome) array using a mouse with Swing?

I've been searching for a way to draw a black-and-white array on screen.我一直在寻找一种在屏幕上绘制黑白数组的方法。 It's a simple array, just 20x20.这是一个简单的数组,只有 20x20。 What I plan to do is to draw on an array with the mouse so that each pixel "toggles" from black to white and back when clicked, then pass the array as a set of booleans (or integers) to another function.我打算做的是用鼠标在数组上绘制,以便每个像素在单击时从黑色“切换”到白色并返回,然后将数组作为一组布尔值(或整数)传递给另一个函数。 Currently I'm using Swing.目前我正在使用 Swing。 I do remember to have used Swing for drawing on a canvas, but I still can't find the actual usage.我记得曾经使用 Swing 在画布上绘图,但我仍然找不到实际用法。 Should I use a canvas, or instead rely on JToggleButtons?我应该使用画布,还是依赖 JToggleButtons?

You can simply use a JFrame (or other Swing component) and override the paint(Graphics) method to draw a representation of the boolean matrix (note that in the case of a lightweight component such as JPanel you should override paintComponent(Graphics) . This will give you the click-and-drag capability you require (which is very difficult to achieve using a grid of individual Swing components).您可以简单地使用JFrame (或其他 Swing 组件)并覆盖paint(Graphics)方法来绘制布尔矩阵的表示(请注意,对于像JPanel这样的轻量级组件,您应该覆盖paintComponent(Graphics) 。这将为您提供所需的单击和拖动功能(使用单个 Swing 组件的网格很难实现)。

As other people have commented, AWT Canvas doesn't give you anything not provided by Swing components and you'll see in the example below that I've used the createBufferStrategy method also present on JFrame to ensure a non-flicker display.正如其他人评论的那样,AWT Canvas不会为您提供 Swing 组件未提供的任何内容,您将在下面的示例中看到,我使用了JFrame上也存在的createBufferStrategy方法来确保非闪烁显示。

笑脸

Note that my example is fairly simple in that it toggles every pixel you drag across rather than the click operation establishing whether you're in "paint" mode or "erase" mode and then exclusively applying black or white pixels for the duration of the drag.请注意,我的示例相当简单,因为它切换您拖动的每个像素,而不是单击操作确定您是处于“绘画”模式还是“擦除”模式,然后在拖动期间专门应用黑色或白色像素.

public class Grid extends JFrame {
    private static final int SCALE = 10; // 1 boolean value == 10 x 10 pixels.
    private static final int SIZE = 20;

    private boolean[][] matrix = new boolean[SIZE][SIZE];
    private boolean painting;
    private int lastX = -1;
    private int lastY = -1;

    public Grid() throws HeadlessException {
        setPreferredSize(new Dimension(SIZE * SCALE, SIZE * SCALE));
        setResizable(false);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setBackground(Color.WHITE);

        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                painting = true;
                tryAdjustValue(e.getPoint());
            }

            public void mouseReleased(MouseEvent e) {
                painting = false;
                lastX = -1;
                lastY = -1;
            }
        });

        addMouseMotionListener(new MouseMotionListener() {
            public void mouseDragged(MouseEvent e) {
                tryAdjustValue(e.getPoint());
            }

            public void mouseMoved(MouseEvent e) {
                tryAdjustValue(e.getPoint());
            }
        });
    }

    private void tryAdjustValue(Point pt) {
        int newX = pt.x / SCALE;
        int newY = pt.y / SCALE;

        if (painting && isInRange(newX) && isInRange(newY) && (newX != lastX || newY != lastY)) {
            // Only invert "pixel" if we're currently in painting mode, both array indices are valid
            // and we're not attempting to adjust the same "pixel" as before (important for drag operations).
            matrix[newX][newY] = !matrix[newX][newY];
            lastX = newX;
            lastY = newY;
            repaint();
        }
    }

    private boolean isInRange(int val) {
        return val >= 0 && val < SIZE;
    }

    public void paint(Graphics g) {
        super.paint(g);

        for (int x=0; x<SIZE; ++x) {
            for (int y=0; y<SIZE; ++y) {
                if (matrix[x][y]) {
                    g.fillRect(x * SCALE, y * SCALE, SCALE, SCALE);
                }
            }
        }
    }

    public static void main(String[] args) {
        Grid grid = new Grid();
        grid.pack();
        grid.setLocationRelativeTo(null);
        grid.createBufferStrategy(2);
        grid.setVisible(true);
    }
}

Why not a simple 20 x 20 grid of JPanel held in a GridLayout(20, 20), and flip the panel's background color if clicked via a MouseListener's mousePressed method.为什么不将简单的 20 x 20 网格 JPanel 保存在 GridLayout(20, 20) 中,并在通过 MouseListener 的 mousePressed 方法单击时翻转面板的背景颜色。 You could hold the panels in a 2D array and query their background color whenever the need arises.您可以将面板保存在二维数组中,并在需要时查询它们的背景颜色。

You could also use JLabels for this, but you'd have to remember to turn their opaque properties to true.您也可以为此使用 JLabels,但您必须记住将它们的不透明属性设置为 true。 A JButton would work as well or a JToggleButton, ... the options are almost limitless. JButton 或 JToggleButton 也可以工作,......选项几乎是无限的。 I do not recommend though that you use AWT (Canvas) as their's no need to step backwards in functionality since Swing handles this so well.我不建议您使用 AWT(画布),因为它们不需要在功能上退步,因为 Swing 处理得很好。

If you get stuck on this, why not come back and show us your code and we'll better be able to give you more specific help.如果您遇到了这个问题,为什么不回来向我们展示您的代码,我们将更好地为您提供更具体的帮助。

Another way to solve this is to use a single JPanel and override its paintComponent method.解决此问题的另一种方法是使用单个 JPanel 并覆盖其paintComponent 方法。 You could give it an int[][] array to serve as its model, and then in the paintComponent method draw rectangles of whatever color desired based on the state of the model.你可以给它一个 int[][] 数组作为它的模型,然后在paintComponent方法中根据模型的状态绘制任何所需颜色的矩形。 Then give it a MouseListener that changes the state of the model and calls repaint.然后给它一个 MouseListener 来改变模型的状态并调用重绘。

eg,例如,

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

@SuppressWarnings("serial")
public class BlackWhiteGridPanel extends JPanel {
   // can have multiple colors if desired
   // public static final Color[] COLORS = {Color.black, Color.red, Color.blue, Color.white}; 
   public static final Color[] COLORS = {Color.black, Color.white};
   public static final int SIDE = 20;
   private static final int BWG_WIDTH = 400;
   private static final int BWG_HEIGHT = BWG_WIDTH;

   private int[][] model = new int[SIDE][SIDE]; // filled with 0's.

   public BlackWhiteGridPanel() {
      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent e) {
            myMousePressed(e);
         }
      });
   }

   private void myMousePressed(MouseEvent e) {
      // find relative position of mouse press on grid.
      int i = (e.getX() * SIDE) / getWidth();
      int j = (e.getY() * SIDE) / getHeight();

      int value = model[i][j];
      // the model can only hold states allowed by the COLORS array. 
      // So if only two colors, then value can only be 0 or 1.
      value = (value + 1) % COLORS.length;
      model[i][j] = value;
      repaint();
   }

   public int[][] getModel() {
      // return a copy of model so as not to risk corruption from outside classes 
      int[][] copy = new int[model.length][model[0].length];
      for (int i = 0; i < copy.length; i++) {
         System.arraycopy(model[i], 0, copy[i], 0, model[i].length);
      }
      return copy;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      int width = getWidth();
      int ht = getHeight();
      for (int i = 0; i < model.length; i++) {
         for (int j = 0; j < model[i].length; j++) {
            Color c = COLORS[model[i][j]];
            g.setColor(c);
            int x = (i * width) / SIDE;
            int y = (j * ht) / SIDE;
            int w = ((i + 1) * width) / SIDE - x;
            int h = ((j + 1) * ht) / SIDE - y;
            g.fillRect(x, y, w, h);
         }
      }
   }

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

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

      JFrame frame = new JFrame("BlackWhiteGrid");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java Swing客户端使用Web服务的最简单方法是什么? - What's the easiest way for a Java Swing client to consumer a webservice? 在Java Swing中显示Windows资源管理器类型的文件结构的最简单方法是什么? - What's the easiest way to show a Windows Explorer-type file structure in Java Swing? 带有Java Swing的Netbeans GUI Builder; 组织小部件最简单的方法是什么? - Netbeans GUI Builder with Java Swing; What's the easiest way to organize Widgets? 使用OpenGL ES绘制纹理的最简单方法是什么? - What is the easiest way to draw texture with OpenGL ES? 在Eclipse IDE中设计Java Swing GUI的最简单方法是什么? - What is the easiest way to design Java Swing GUIs in Eclipse IDE? 将值加x最简单的方法是什么 - What's the easiest way to increment a value by x 使用OpenGL在Java 3d空间中绘制图像的最简单方法是什么? - What is the easiest way to draw an image in 3d space in Java with OpenGL? 持久化 Java 对象的最简单方法是什么? - What's the easiest way to persist java objects? 在 Java 中实现计时器的最简单方法是什么? - What's the easiest way to implement a timer in Java? 在Java中,将String数组转换为float数组的最快,最简单的方法是什么? - In Java what's the fastest and easiest way to convert an array of String into an array of float?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM