java - 让用户在Java中用鼠标绘制一个矩形

标签 java swing graphics user-input paintcomponent

我正在编写一个程序,让用户在屏幕上的图像顶部绘制一个空心矩形。他们还可以单击图像,然后将单击连接起来形成多边形。

连接点工作正常,但是当用户拖动以绘制矩形时,先前绘制的矩形和多边形会消失。可运行的代码如下;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ImageLabeller extends JFrame {

static boolean drawRectangle = false;
/**
 * some java stuff to get rid of warnings
 */
private static final long serialVersionUID = 1L;

/**
 * main window panel
 */
JPanel appPanel = null;

/**
 * toolbox - put all buttons here
 */
JPanel toolboxPanel = null;

/**
 * image panel - displays image and editing area
 */

static ImagePanel imagePanel;

/**
 * handles New Object button action
 */

public ImageLabeller(String imageFilename) {

    try {

        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent event) {
                System.out.println("Bye bye!");
                System.exit(0);
            }
        });

        // Create and set up the image panel.
        // setup main window panel
        setExtendedState(Frame.MAXIMIZED_BOTH);
        appPanel = new JPanel();
        appPanel.setLayout(new BoxLayout(appPanel, BoxLayout.Y_AXIS));
        this.setContentPane(appPanel);

        imagePanel = new ImagePanel(imageFilename);
        imagePanel.setOpaque(true); // content panes must be opaque
        imagePanel.setBorder(BorderFactory.createLineBorder(Color.green));

        // create toolbox panel
        toolboxPanel = new JPanel();
        toolboxPanel.setBorder(BorderFactory.createLineBorder(Color.black));


        JButton newPolyButton = new JButton("New object");
        newPolyButton.setMnemonic(KeyEvent.VK_N);
        // newPolyButton.setSize(50, 20);
        newPolyButton.setToolTipText("Click to add new object");
        newPolyButton.addActionListener(new DrawListener());

        JButton newSquareButton = new JButton("New Square");
        newSquareButton.setMnemonic(KeyEvent.VK_S);
        // newPolyButton.setSize(50, 20);
        newSquareButton.setEnabled(true);
        newSquareButton.setToolTipText("Click to add new square");
        newSquareButton.addActionListener(new SquareListener());



        // add all buttons to toolboxPanel
        toolboxPanel.add(newPolyButton);
        toolboxPanel.add(newSquareButton);

        // add all panels to appPanel
        appPanel.add(toolboxPanel);
        appPanel.add(imagePanel);
        // appPanel.add(Box.createRigidArea(new Dimension(0,10)));

        // display all the stuff
        this.pack();
        this.setVisible(true);
    } catch (Exception e) {
        System.err.println("Image: ");
        e.printStackTrace();
    }
}

public static void addNewPolygon() {
    imagePanel.addNewPolygon();
}

public static void addNewRectangle() {
    //imagePanel.addNewRectangle();
}

    static class DrawListener implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            addNewPolygon();
        }
    }

    static class SquareListener implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            drawRectangle = true;
            imagePanel.drawingRectangle = true;
            System.out.println(imagePanel.drawingRectangle);
        }
    }

    public static void main (String args []) {
        new ImageLabeller("/change to/a photo/ of your choice.jpg");
    }

}

_

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel implements MouseListener,
    MouseMotionListener {

Rectangle currentRectangle = null;
boolean drawingRectangle = false;

/**
 * some java stuff to get rid of warnings
 */
private static final long serialVersionUID = 1L;

/**
 * image to be tagged
 */
BufferedImage image = null;

/**
 * list of current polygon's vertices
 */
ArrayList<Point> currentPolygon = null;

/**
 * list of polygons
 */
ArrayList<ArrayList<Point>> polygonsList = null;

ArrayList<Rectangle> rectangleList = null;

/**
 * extended constructor - loads image to be labelled
 * 
 * @param imageName
 *            - path to image
 * @throws Exception
 *             if error loading the image
 */
public ImagePanel(String imageName) throws Exception {

    currentPolygon = new ArrayList<Point>();
    polygonsList = new ArrayList<ArrayList<Point>>();
    rectangleList = new ArrayList<Rectangle>();

    image = ImageIO.read(new File(imageName));
    Dimension panelSize = new Dimension(image.getWidth(), image.getHeight());
    this.setSize(panelSize);
    this.setMinimumSize(panelSize);
    this.setPreferredSize(panelSize);
    this.setMaximumSize(panelSize);

    setBounds(0, 0, image.getWidth(), image.getHeight());
    addMouseListener(this);
    addMouseMotionListener(this);
    this.setVisible(true);

}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    System.out.println("Paint Component");
    Graphics2D g2d = (Graphics2D) g;

    // Paint image on screen
    g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);

    // display all the completed polygons
    for (ArrayList<Point> polygon : polygonsList) {
        drawPolygon(polygon);
        finishPolygon(polygon);
        System.out.println("Polly");
    }

    // Display all completed squares
    for (Rectangle r : rectangleList) {
        drawRectangle(r);
        System.out.println("Square");
    }

    // display current polygon
    if (currentPolygon != null) {
        drawPolygon(currentPolygon);
    }

    // display current square
    if (currentRectangle != null) {
        drawRectangle(currentRectangle);
    }
}

/**
 * displays a polygon without last stroke
 * 
 * @param polygon
 *            to be displayed
 */
public void drawPolygon(ArrayList<Point> polygon) {
    Graphics2D g = (Graphics2D) this.getGraphics();
    // set to red so I can see when it's being redrawn
    g.setColor(Color.RED);
    g.setStroke(new BasicStroke(3));
    for (int i = 0; i < polygon.size(); i++) {
        Point currentVertex = polygon.get(i);
        if (i != 0) {
            Point prevVertex = polygon.get(i - 1);
            g.drawLine(prevVertex.getX(), prevVertex.getY(),
                    currentVertex.getX(), currentVertex.getY());
        }
        g.fillOval(currentVertex.getX() - 5, currentVertex.getY() - 5, 10,
                10);
    }
}

public void drawRectangle(Rectangle r) {
    Graphics2D g = (Graphics2D) this.getGraphics();
    g.setStroke(new BasicStroke(3));
    g.setColor(Color.BLUE);
    g.drawLine(r.getX1(), r.getY1(), r.getX2(), r.getY1());
    g.drawLine(r.getX1(), r.getY1(), r.getX1(), r.getY2());
    g.drawLine(r.getX2(), r.getY2(), r.getX2(), r.getY1());
    g.drawLine(r.getX2(), r.getY2(), r.getX1(), r.getY2());

    System.out.println(r.getX1() + " " + r.getY1() + " " + r.getX2());
    System.out.println("Drawn rectangle");
}

/**
 * displays last stroke of the polygon (arch between the last and first
 * vertices)
 * 
 * @param polygon
 *            to be finished
 */
public void finishPolygon(ArrayList<Point> polygon) {
    // if there are less than 3 vertices than nothing to be completed
    if (polygon.size() >= 3) {
        Point firstVertex = polygon.get(0);
        Point lastVertex = polygon.get(polygon.size() - 1);

        Graphics2D g = (Graphics2D) this.getGraphics();
        g.setColor(Color.GREEN);
        g.setStroke(new BasicStroke(3));
        g.drawLine(firstVertex.getX(), firstVertex.getY(),
                lastVertex.getX(), lastVertex.getY());
    }
}

/**
 * moves current polygon to the list of polygons and makes pace for a new
 * one
 */
public void addNewPolygon() {
    // finish the current polygon if any
    if (currentPolygon != null) {
        finishPolygon(currentPolygon);
        polygonsList.add(currentPolygon);
    }

    currentPolygon = new ArrayList<Point>();
}

public void mouseClicked(MouseEvent e) {

    if (!drawingRectangle) {
        int x = e.getX();
        int y = e.getY();

        // check if the cursor is within image area
        if (x > image.getWidth() || y > image.getHeight()) {
            // if not do nothing
            return;
        }

        Graphics2D g = (Graphics2D) this.getGraphics();

        // if the left button than we will add a vertex to poly
        if (e.getButton() == MouseEvent.BUTTON1) {
            g.setColor(Color.GREEN);
            if (currentPolygon.size() != 0) {
                Point lastVertex = currentPolygon
                        .get(currentPolygon.size() - 1);

                g.setStroke(new BasicStroke(3));
                g.drawLine(lastVertex.getX(), lastVertex.getY(), x, y);
            }
            g.fillOval(x - 5, y - 5, 10, 10);

            currentPolygon.add(new Point(x, y));
            System.out.println(x + " " + y + " polygon point");
        }
    }
}

public void mouseEntered(MouseEvent arg0) {
}

public void mouseExited(MouseEvent arg0) {
}

public void mousePressed(MouseEvent arg0) {
    if (drawingRectangle) {
        currentRectangle = new Rectangle(arg0.getX(), arg0.getY(),
                arg0.getX(), arg0.getY(), Color.BLACK);

    }
}

public void mouseReleased(MouseEvent arg0) {
    if (drawingRectangle) {
        rectangleList.add(new Rectangle(currentRectangle.getX1(),
                currentRectangle.getY1(), arg0.getX(), arg0.getY(),
                currentRectangle.getColor()));

        System.out.println(currentRectangle.getX1() + " "
                + currentRectangle.getY1() + " " + arg0.getX() + " "
                + arg0.getY() + " rectangle point");

        // unnecessary when mouseDragged calls paintComponent directly?
        drawRectangle(new Rectangle(currentRectangle.getX1(),
                currentRectangle.getY1(), arg0.getX(), arg0.getY(),
                currentRectangle.getColor()));

        currentRectangle = null;
        drawingRectangle = false;

    }
}

public void mouseDragged(MouseEvent arg0) {

    if (drawingRectangle) {
        currentRectangle = new Rectangle(currentRectangle.getX1(),
                currentRectangle.getY1(), arg0.getX(), arg0.getY(),
                currentRectangle.getColor());

        System.out.println(currentRectangle.getX1() + " "
                + currentRectangle.getY1() + " " + arg0.getX() + " "
                + arg0.getX() + " " + "Dragging");
        repaint();

    // It works better using this instead on repaint()

//           Graphics g = this.getGraphics();
//           paintComponent(g);
    }

}

public void mouseMoved(MouseEvent arg0) {
    // TODO Auto-generated method stub

}

}

-

public class Point {
private int x = 0;
private int y = 0;

public Point() {
}

public Point(int x, int y) {
    this.x = x;
    this.y = y;
}

public int getX() {
    return x;
}

public void setX(int x) {
    this.x = x;
}

public int getY() {
    return y;
}

public void setY(int y) {
    this.y = y;
}

}

-

import java.awt.Color;
import java.awt.Graphics2D;

public class Rectangle {

// Initialize variables
private int x1; // x coordinate of first endpoint
private int y1; // y coordinate of first endpoint
private int x2; // x coordinate of second endpoint
private int y2; // y coordinate of second endpoint
private Color colour; // colour of the shape

// A no-parameter constructor that sets all the coordinates of the shape to
// 0 and the
// colour to Color.BLACK
public Rectangle() {
    x1 = 0;
    y1 = 0;
    x2 = 0;
    y2 = 0;
    colour = Color.BLACK;
}

// A constructor that initializes the coordinates and colour to the values
// of the
// parameters supplied.
public Rectangle(int x1, int y1, int x2, int y2, Color col) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.colour = col;
}

public void setX1(int x1) {
    this.x1 = x1;
}

public void setY1(int y1) {
    this.y1 = y1;
}

public void setX2(int x2) {
    this.x2 = x2;
}

public void setY2(int y2) {
    this.y2 = y2;
}

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

public int getX1() {
    return this.x1;
}

public int getY1() {
    return this.y1;
}

public int getX2() {
    return this.x2;
}

public int getY2() {
    return this.y2;
}

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

public int getWidth() {
    return (Math.abs(x2 - x1));
}

public int getHeight() {
    return (Math.abs(y2 - y1));
}

public int getUpperLeftX() {
    return (Math.min(x1, x2));
}

public int getUpperLeftY() {
    return (Math.min(y1, y2));
}
}

对于大量代码,我深感抱歉,我已尽力删减。

单击图像可绘制点,这些点连接起来可创建线条。当用户单击“新对象”按钮时,第一个点和最后一个点将连接起来以创建多边形。这一切都工作正常,但如果您单击“新正方形”并在图像上拖动,则所有先前的形状都会随着鼠标移动而闪烁,并在释放鼠标按钮时消失。如果再次单击“新方 block ”(到目前为止,这对我来说是一个糟糕的编码的必要条件)并绘制了另一个方 block ,则可以看到“消失”的形状再次闪烁,但一旦释放鼠标就会消失。 我在 mouseDragged(...) 事件中调用 repaint() ,我认为这就是必要的。当我改变时,它实际上(几乎)按我想要的方式工作

repaint();

对于

Graphics g = this.getGraphics();
paintComponent(g); 

但是我读过的每本书和文章都说我永远不应该自己调用paintComponent。然而,调用paintComponent 的一个问题是背景图像往往会频繁闪烁。 如果repaint()调用paintComponent,为什么它们会导致不同的结果?

我也不明白为什么,当在mouseDragged事件中使用repaint()时,我必须,我还必须在mouseReleased中调用drawRectangle(...)才能看到正方形,但是当使用paintComponent时,我不知道?

非常感谢任何建议或指示,谢谢。

最佳答案

在您的drawRectangle和drawPolygon中,您正在重新获取图形对象,但您是从paintComponent调用它们。这就是导致奇怪行为的原因,您应该将图形从 painComponent 传递到这些方法中。

不过,我看到了其他奇怪的行为,比如多边形保持绿色,直到我完成绘制一个正方形,然后它们变成红色,但其中一条线保持绿色并最终消失。我没有太关注这个。

此外,awt 支持多边形绘制以及点和矩形,您选择为这些创建自己的类有什么原因吗?

package test;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel implements MouseListener,
    MouseMotionListener {

Rectangle currentRectangle = null;
boolean drawingRectangle = false;

/**
 * some java stuff to get rid of warnings
 */
private static final long serialVersionUID = 1L;

/**
 * image to be tagged
 */
BufferedImage image = null;

/**
 * list of current polygon's vertices
 */
ArrayList<Point> currentPolygon = null;

/**
 * list of polygons
 */
ArrayList<ArrayList<Point>> polygonsList = null;

ArrayList<Rectangle> rectangleList = null;

/**
 * extended constructor - loads image to be labelled
 * 
 * @param imageName
 *            - path to image
 * @throws Exception
 *             if error loading the image
 */
public ImagePanel(String imageName) throws Exception {

    currentPolygon = new ArrayList<Point>();
    polygonsList = new ArrayList<ArrayList<Point>>();
    rectangleList = new ArrayList<Rectangle>();

    image = ImageIO.read(new File(imageName));
    Dimension panelSize = new Dimension(image.getWidth(), image.getHeight());
    this.setSize(panelSize);
    this.setMinimumSize(panelSize);
    this.setPreferredSize(panelSize);
    this.setMaximumSize(panelSize);

    setBounds(0, 0, image.getWidth(), image.getHeight());
    addMouseListener(this);
    addMouseMotionListener(this);
    this.setVisible(true);

}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    System.out.println("Paint Component");
    Graphics2D g2d = (Graphics2D) g;

    // Paint image on screen
    g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);

    // display all the completed polygons
    for (ArrayList<Point> polygon : polygonsList) {
        drawPolygon(polygon,g);
        finishPolygon(polygon);
        System.out.println("Polly");
    }

    // Display all completed squares
    for (Rectangle r : rectangleList) {
        drawRectangle(r,g);
        System.out.println("Square");
    }

    // display current polygon
    if (currentPolygon != null) {
        drawPolygon(currentPolygon, g);
    }

    // display current square
    if (currentRectangle != null) {
        drawRectangle(currentRectangle, g);
    }
}

/**
 * displays a polygon without last stroke
 * 
 * @param polygon
 *            to be displayed
 */
public void drawPolygon(ArrayList<Point> polygon,  Graphics gr) {
    Graphics2D g = null;
    if (gr instanceof Graphics2D) {
        g = (Graphics2D) gr;
    }
    else{ return; }
    // set to red so I can see when it's being redrawn
    g.setColor(Color.RED);
    g.setStroke(new BasicStroke(3));
    for (int i = 0; i < polygon.size(); i++) {
        Point currentVertex = polygon.get(i);
        if (i != 0) {
            Point prevVertex = polygon.get(i - 1);
            g.drawLine(prevVertex.getX(), prevVertex.getY(),
                    currentVertex.getX(), currentVertex.getY());
        }
        g.fillOval(currentVertex.getX() - 5, currentVertex.getY() - 5, 10,
                10);
    }
}

public void drawRectangle(Rectangle r, Graphics gr) {
    Graphics2D g = null;
    if (gr instanceof Graphics2D) {
        g = (Graphics2D) gr;
    }
    else{ return; }
    g.setStroke(new BasicStroke(3));
    g.setColor(Color.BLUE);
    g.drawLine(r.getX1(), r.getY1(), r.getX2(), r.getY1());
    g.drawLine(r.getX1(), r.getY1(), r.getX1(), r.getY2());
    g.drawLine(r.getX2(), r.getY2(), r.getX2(), r.getY1());
    g.drawLine(r.getX2(), r.getY2(), r.getX1(), r.getY2());

    System.out.println(r.getX1() + " " + r.getY1() + " " + r.getX2());
    System.out.println("Drawn rectangle");
}

/**
 * displays last stroke of the polygon (arch between the last and first
 * vertices)
 * 
 * @param polygon
 *            to be finished
 */
public void finishPolygon(ArrayList<Point> polygon) {
    // if there are less than 3 vertices than nothing to be completed
    if (polygon.size() >= 3) {
        Point firstVertex = polygon.get(0);
        Point lastVertex = polygon.get(polygon.size() - 1);

        Graphics2D g = (Graphics2D) this.getGraphics();
        g.setColor(Color.GREEN);
        g.setStroke(new BasicStroke(3));
        g.drawLine(firstVertex.getX(), firstVertex.getY(),
                lastVertex.getX(), lastVertex.getY());
    }
}

/**
 * moves current polygon to the list of polygons and makes pace for a new
 * one
 */
public void addNewPolygon() {
    // finish the current polygon if any
    if (currentPolygon != null) {
        finishPolygon(currentPolygon);
        polygonsList.add(currentPolygon);
    }

    currentPolygon = new ArrayList<Point>();
}

public void mouseClicked(MouseEvent e) {

    if (!drawingRectangle) {
        int x = e.getX();
        int y = e.getY();

        // check if the cursor is within image area
        if (x > image.getWidth() || y > image.getHeight()) {
            // if not do nothing
            return;
        }

        Graphics2D g = (Graphics2D) this.getGraphics();

        // if the left button than we will add a vertex to poly
        if (e.getButton() == MouseEvent.BUTTON1) {
            g.setColor(Color.GREEN);
            if (currentPolygon.size() != 0) {
                Point lastVertex = currentPolygon
                        .get(currentPolygon.size() - 1);

                g.setStroke(new BasicStroke(3));
                g.drawLine(lastVertex.getX(), lastVertex.getY(), x, y);
            }
            g.fillOval(x - 5, y - 5, 10, 10);

            currentPolygon.add(new Point(x, y));
            System.out.println(x + " " + y + " polygon point");
        }
    }
}

public void mouseEntered(MouseEvent arg0) {
}

public void mouseExited(MouseEvent arg0) {
}

public void mousePressed(MouseEvent arg0) {
    if (drawingRectangle) {
        currentRectangle = new Rectangle(arg0.getX(), arg0.getY(),
                arg0.getX(), arg0.getY(), Color.BLACK);

    }
}

public void mouseReleased(MouseEvent arg0) {
    if (drawingRectangle) {
        rectangleList.add(new Rectangle(currentRectangle.getX1(),
                currentRectangle.getY1(), arg0.getX(), arg0.getY(),
                currentRectangle.getColor()));

        System.out.println(currentRectangle.getX1() + " "
                + currentRectangle.getY1() + " " + arg0.getX() + " "
                + arg0.getY() + " rectangle point");

        // unnecessary when mouseDragged calls paintComponent directly?
        /*drawRectangle(new Rectangle(currentRectangle.getX1(),
                currentRectangle.getY1(), arg0.getX(), arg0.getY(),
                currentRectangle.getColor()));*/

        currentRectangle = null;
        drawingRectangle = false;

    }
}

public void mouseDragged(MouseEvent arg0) {

    if (drawingRectangle) {
        currentRectangle = new Rectangle(currentRectangle.getX1(),
                currentRectangle.getY1(), arg0.getX(), arg0.getY(),
                currentRectangle.getColor());

        System.out.println(currentRectangle.getX1() + " "
                + currentRectangle.getY1() + " " + arg0.getX() + " "
                + arg0.getX() + " " + "Dragging");
        repaint();

    // It works better using this instead on repaint()

//           Graphics g = this.getGraphics();
//           paintComponent(g);
    }

}

public void mouseMoved(MouseEvent arg0) {
    // TODO Auto-generated method stub

}

}

关于java - 让用户在Java中用鼠标绘制一个矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12746783/

相关文章:

java - 如何使用 C# 终止正在运行的 jar 文件

java - 获取EventHubException : Connection aborted when I create TWO instances of EventHubClient

java - 从 JPanel 隐藏 JInternalFrame

java - 从特定的 CSV 文件中读取数据并将其显示在 JTable 中

graphics - JavaFX 设计器

java - 切换时区进行计算

java - 如何知道屏幕上容器或窗口的确切大小?

c - 了解图形的绘制方式

javascript - Phaser - 显示图形对象 50 毫秒,并在同时按下一个或多个按键时销毁每个按键

java - 泛型函数的问题