簡體   English   中英

讓用戶在Java中用鼠標繪制一個矩形

[英]Letting user draw a rectangle with mouse in Java

我正在編寫一個程序,讓用戶在屏幕上的圖像上繪制一個空心矩形。 他們還可以單擊圖像並將點擊連接起來以形成多邊形。

連接點工作正常,但是當用戶拖動繪制矩形時,先前繪制的矩形和多邊形消失。 可運行的代碼如下;

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));
}
}

對不起大量的代碼,我試圖盡可能多地修剪。

單擊圖像可以繪制連接起來創建線條的點。 當用戶單擊“新建對象”按鈕時,將連接第一個和最后一個點以創建多邊形。 這一切都很好,但如果單擊“新方塊”並拖動圖像,所有以前的形狀會隨着鼠標的移動而閃爍,並在釋放鼠標按鈕時消失。 如果再次點擊“New Square”(代表我的代碼編碼不好的必要性)和另一個方形繪制,可以看到“消失”的形狀再次閃爍,但一旦釋放鼠標就會消失。 我在mouseDragged(...)事件中調用repaint(),我認為這是必要的。 當我改變時,它實際上(幾乎)可以正常工作

repaint();

對於

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

但是我讀過的每本書和文章都說我永遠不應該自己打電話給paintComponent。 然而,調用paintComponent的一個問題是背景圖像往往會閃爍很多。 如果repaint()調用paintComponent,為什么它們導致不同的結果?

我也不明白為什么,當在mouseDragged事件中使用repaint()時,我必須,我必須在mouseReleased中調用drawRectangle(...)才能看到正方形,但是當使用paintComponent時,我不會T'

任何建議或指示都非常感謝,謝謝。

在drawRectangle和drawPolygon中,您將重新獲取圖形對象,但是您正在從paintComponent中調用它們。 這就是導致奇怪行為的原因,你應該將painComponent中的圖形傳遞給那些方法。

我看到其他奇怪的行為,就像多邊形保持綠色直到我畫完一個正方形,然后它們變成紅色,但其中一條線保持綠色並最終消失。 我沒有太多關注那個。

此外,在awt中支持多邊形繪制和Point和Rectangle,您是否有任何理由選擇為這些創建自己的類?

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

}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM