提问者:小点点

为什么ActionListener不能使用JavaGUI中的按钮?


我正在开发一个JavaGUI的应用程序,我无法让ActionListener与我的按钮一起正常工作。当我单击按钮时,什么都没有发生,我的类中的相应方法也没有被执行。我不确定我做错了什么。以下是我代码中相关的类(特别是“Draw”和“DrawGUI”):

`package mydraw.logic;

import static mydraw.gui.DrawGUI.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import mydraw.gui.DrawGUI;

/**
The Draw class provides high-level API methods for drawing shapes using the DrawGUI.
It contains methods for drawing rectangles, ovals, and polylines, as well as a test method
for automatically drawing a set of shapes.
It also provides a constructor to create an instance of the DrawGUI and a method to get the
DrawGUI window component.
*/

/** The application class. Processes high-level commands sent by GUI */
public class Draw {
    private static final Object QUIT = null;
    private static final Object CLEAR = null;
    private static final Object SAVE = null;
    private static final Object AUTODRAW = "autoDraw";
    public Graphics g;
    protected DrawGUI window;

    /** main entry point. Just create an instance of this application class */
    public static void main(String[] args) {
        new Draw();
    }

    /** Application constructor: create an instance of our GUI class */
    public Draw() {
        window = new DrawGUI(this);
        g = window.getGraphics();
    }

    /**
     * This is the application method that processes commands sent by the GUI.
     * 
     * @param command - command sent by the GUI.
     */
    public void doCommand(String command) {
        if (command.equals(CLEAR)) {
            window.clear();
            System.out.println("CLEAR button clicked");
        } else if (command.equals(QUIT)) {
            window.dispose();
            System.out.println("QUIT button clicked");
            System.exit(0);
        } else if (command.equals(SAVE)) {
            Image img = window.createImageFromPanel();
            try {
                writeImage(img, "hallo.bmp");
                System.out.println("SAVE button clicked");
            } catch (IOException e) {
                System.err.println("Not working");
            }
        } else if (command.equals(AUTODRAW)) {
            autoDraw();
            System.out.println("AUTODRAW button clicked");
        }
    }

    /**
     * API method: get height.
     * 
     * @return height of the window.
     */
    public int getHeight() {
        return window.getContentPane().getHeight();
    }

    /**
     * API method: set height.
     * 
     * @param height - the new height of the window.
     * @throws SizeException if the input is negative.
     */
    public void setHeight(int height) throws SizeException {
        if (height < 0) {
            throw new SizeException("Höhe muss positiv sein.");
        }
        Dimension d = window.getContentPane().getPreferredSize();
        d.height = height;
        window.getContentPane().setPreferredSize(d);
        window.pack();
    }

    /**
     * API method: get width.
     * 
     * @return width of the window.
     */
    public int getWidth() {
        return window.getContentPane().getWidth();
    }

    /**
     * API method: set width.
     * 
     * @param width - the new width of the window.
     * @throws SizeException if the input is negative.
     */
    public void setWidth(int width) throws SizeException {
        if (width < 0) {
            throw new SizeException("Breite muss positiv sein.");
        }
        Dimension d = window.getContentPane().getPreferredSize();
        d.width = width;
        window.getContentPane().setPreferredSize(d);
        window.pack();
    }

    /**
     * API method: set foreground color.
     * 
     * @param new_color - new foreground color.
     * @throws ColorException if the input is not a valid color.
     */
    public void setFGColor(String new_color) throws ColorException {
        Color color = Color.getColor(new_color);
        if (color == null) {
            throw new ColorException("Ungueltiger Farbname.");
        }
        window.setForeground(color);
    }

    /**
     * API method: get foreground color.
     * 
     * @return the current foreground color.
     */
    public String getFGColor() {
        return window.getForeground().toString();
    }

    /**
     * API method: set background color.
     * 
     * @param new_color - new background color.
     * @throws ColorException if the input is not a valid color.
     */
    public void setBGColor(String new_color) throws ColorException {
        Color color = Color.getColor(new_color);
        if (color == null) {
            throw new ColorException("Ungueltiger Farbname.");
        }
        window.setBackground(color);
    }

    /**
     * API method: get background color.
     * 
     * @return the current background color.
     */
    public String getBGColor() {
        return window.getBackground().toString();
    }

    /**
     * API method: get drawing.
     * 
     * @return the drawing as a BufferedImage.
     */
    public BufferedImage getDrawing() {
        int width = window.getContentPane().getWidth();
        int height = window.getContentPane().getHeight();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        Graphics2D g2d = image.createGraphics();
        window.paintComponents(g2d);
        g2d.dispose();
        return image;
    }

    /**
     * API method: write image.
     * 
     * @param img      - the image to be saved.
     * @param filename - the filename to save the image to.
     * @throws IOException if there is an error while writing the image.
     */
    public void writeImage(Image img, String filename) throws IOException {
        MyBMPFile.write(filename, img);
    }

    /**
     * API method: read image.
     * 
     * @param filename - the filename to read the image from.
     * @return the image as an Image object.
     * @throws IOException if there is an error while reading the image.
     */
    public Image readImage(String filename) throws IOException {
        return MyBMPFile.read(filename);
    }

    /**
     * API method: clear the window.
     */
    public void clear() {
        g.setColor(window.getBackground());
        g.fillRect(0, 0, window.getContentPane().getWidth(), window.getContentPane().getHeight());
    }

    /**
     * 
     * Test method to automatically draw a set of shapes using the DrawGUI.
     * 
     * Draws a rectangle, an oval, and a polyline.
     */
    public void autoDraw() {

        g.setColor(Color.RED);
        drawRectangle(new Point(50, 100), new Point(150, 200)); // Rectangle 1
        g.setColor(Color.BLUE);
        drawRectangle(new Point(160, 100), new Point(260, 200)); // Rectangle 2
        g.setColor(Color.GREEN);
        drawRectangle(new Point(270, 100), new Point(370, 200)); // Rectangle 3
        g.setColor(Color.BLACK);
        drawRectangle(new Point(380, 100), new Point(480, 200)); // Rectangle 4

        g.setColor(Color.RED);
        drawOval(new Point(50, 250), new Point(150, 350)); // Oval 1
        g.setColor(Color.BLUE);
        drawOval(new Point(175, 250), new Point(275, 350)); // Oval 2
        g.setColor(Color.GREEN);
        drawOval(new Point(300, 250), new Point(400, 350)); // Oval 3
        g.setColor(Color.BLACK);
        drawOval(new Point(425, 250), new Point(525, 350)); // Oval 4

        g.setColor(Color.RED);
        java.util.List<Point> points1 = new ArrayList<>(Arrays.asList(new Point(90, 180), new Point(100, 150),
                new Point(110, 180), new Point(120, 150), new Point(130, 180)));
        drawPolyLine(points1); // Polyline 1

        g.setColor(Color.BLUE);
        java.util.List<Point> points2 = new ArrayList<>(Arrays.asList(new Point(190, 180), new Point(200, 150),
                new Point(210, 180), new Point(220, 150), new Point(230, 180)));
        drawPolyLine(points2); // Polyline 2

        g.setColor(Color.GREEN);
        java.util.List<Point> points3 = new ArrayList<>(Arrays.asList(new Point(290, 180), new Point(300, 150),
                new Point(310, 180), new Point(320, 150), new Point(330, 180)));
        drawPolyLine(points3); // Polyline 3

        g.setColor(Color.BLACK);
        java.util.List<Point> points4 = new ArrayList<>(Arrays.asList(new Point(390, 180), new Point(400, 150),
                new Point(410, 180), new Point(420, 150), new Point(430, 180)));
        drawPolyLine(points4); // Polyline 4
    }

    /**
     * 
     * Method to draw a rectangle on the DrawGUI.
     * 
     * @param upper_left  the upper-left corner of the rectangle
     * 
     * @param lower_right the lower-right corner of the rectangle
     */
    public void drawRectangle(Point upper_left, Point lower_right) {
        int width = lower_right.x - upper_left.x;
        int height = lower_right.y - upper_left.y;

        g.drawRect(upper_left.x, upper_left.y, width, height);
    }

    /**
     * 
     * Method to draw an oval on the DrawGUI.
     * 
     * @param upper_left  the upper-left corner of the oval
     * 
     * @param lower_right the lower-right corner of the oval
     */
    public void drawOval(Point upper_left, Point lower_right) {
        int width = lower_right.x - upper_left.x;
        int height = lower_right.y - upper_left.y;

        g.drawOval(upper_left.x, upper_left.y, width, height);
    }

    /**
     * 
     * Method to draw a polyline on the DrawGUI.
     * 
     * @param points a list of points defining the vertices of the polyline
     */
    public void drawPolyLine(java.util.List<Point> points) {
        int[] xpoints = new int[points.size()];
        int[] ypoints = new int[points.size()];
        for (int i = 0; i < points.size(); i++) {
            xpoints[i] = points.get(i).x;
            ypoints[i] = points.get(i).y;
        }

        g.drawPolyline(xpoints, ypoints, points.size());
    }

    /**
     * Helper method for the test class.
     *
     * @return window return the window
     */
    public Window getWindow() {
        return window;
    }

}`



`package mydraw.gui;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;

import javax.swing.*;

import mydraw.logic.Draw;

/** This class implements the GUI for our application */
public class DrawGUI extends JFrame {

    private static final long serialVersionUID = 1L;

    /**
     * The default width of the drawing window.
     */
    public static final int WIDTH = 800;

    /**
     * The default height of the drawing window.
     */
    public static final int HEIGHT_DEFAULT = 400;

    /**
     * The labels for the buttons.
     */
    public static final String SCRIBBLE = "Scribble";
    public static final String RECTANGLE = "Rectangle";
    public static final String OVAL = "Oval";
    public static final String BLACK = "Black";
    public static final String GREEN = "Green";
    public static final String RED = "Red";
    public static final String BLUE = "Blue";
    public static final String CLEAR = "Clear";
    public static final String QUIT = "Quit";
    public static final String SAVE = "Save";
    public static final String AUTODRAW = "autoDraw";

    private final Draw logic;
    private Color color;
    private final DrawingPanel drawingPanel;

    /**
     * Constructs a new DrawGUI object with the specified Draw logic.
     *
     * @param logic the Draw object to use for the GUI's logic
     */
    public DrawGUI(Draw logic) {
        super("Draw");
        this.logic = logic;
        color = Color.black;
        drawingPanel = new DrawingPanel();

        setSize(WIDTH, HEIGHT_DEFAULT);

        Choice shape_chooser = new Choice();
        shape_chooser.add(SCRIBBLE);
        shape_chooser.add(RECTANGLE);
        shape_chooser.add(OVAL);
        shape_chooser.addItemListener(new ShapeManager(this, drawingPanel));

        Choice color_chooser = new Choice();
        color_chooser.add(BLACK);
        color_chooser.add(GREEN);
        color_chooser.add(RED);
        color_chooser.add(BLUE);

        color_chooser.addItemListener(e -> {
            if (e.getItem().equals(BLACK)) {
                color = Color.black;
            } else if (e.getItem().equals(GREEN)) {
                color = Color.green;
            } else if (e.getItem().equals(RED)) {
                color = Color.red;
            } else if (e.getItem().equals(BLUE)) {
                color = Color.blue;
            }
        });

        JButton clear = new JButton(CLEAR);
        JButton quit = new JButton(QUIT);
        JButton save = new JButton(SAVE);
        JButton autodraw = new JButton(AUTODRAW);
        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 5));
        clear.addActionListener(e -> logic.doCommand(CLEAR));
        quit.addActionListener(e -> logic.doCommand(QUIT));
        save.addActionListener(e -> logic.doCommand(SAVE));
        autodraw.addActionListener(e -> logic.doCommand(AUTODRAW));

        setLayout(new BorderLayout());
        topPanel.add(save);
        topPanel.add(autodraw);
        topPanel.add(new JLabel("Shape:"));
        topPanel.add(shape_chooser);
        topPanel.add(new JLabel("Color:"));
        topPanel.add(color_chooser);
        topPanel.add(clear);
        topPanel.add(quit);
        add(topPanel, BorderLayout.NORTH);
        add(drawingPanel, BorderLayout.CENTER);

        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                DrawGUI.this.logic.doCommand("quit");
            }

        });

        this.setBackground(Color.white);
        this.setVisible(true);

    }

    /**
     * Returns the currently selected drawing color.
     *
     * @return the currently selected drawing color
     */
    public Color getColor() {
        return color;
    }

    /**
     * Creates a new BufferedImage of the drawing panel.
     *
     * @return a new BufferedImage of the drawing panel
     */
    public BufferedImage createImageFromPanel() {
        int width = drawingPanel.getWidth();
        int height = drawingPanel.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();
        drawingPanel.paint(g2d);
        g2d.dispose();
        return image;
    }

    /**
     * Clears the drawing panel and resets the GUI.
     */
    public void clear() {
        Graphics g = getGraphics();
        g.setColor(getBackground());
        g.fillRect(0, 0, getSize().width, getSize().height);
        drawingPanel.clearImage();
    }

}`


`package mydraw.gui;

import java.awt.*;
import java.awt.event.*;

@SuppressWarnings("unused")
public class ShapeManager implements ItemListener {
    DrawGUI gui;
    final DrawingPanel drawingPanel;

    abstract class ShapeDrawer extends MouseAdapter implements MouseMotionListener {
        @Override
        public void mouseMoved(MouseEvent e) {
            /* ignore */ }
    }

    // if this class is active, the mouse is interpreted as a pen
    class ScribbleDrawer extends ShapeDrawer implements MouseMotionListener {
        int lastx, lasty;

        @Override
        public void mousePressed(MouseEvent e) {
            lastx = e.getX();
            lasty = e.getY();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            Graphics2D g2d = drawingPanel.getImageGraphics();
            int x = e.getX() - drawingPanel.getX(), y = e.getY() - drawingPanel.getY();
            g2d.setColor(gui.getColor());
            g2d.setPaintMode();
            g2d.drawLine(lastx, lasty, x, y);
            g2d.dispose();
            lastx = x;
            lasty = y;
            drawingPanel.repaint(); // Neu hinzugefügt
        }
    }

    // if this class is active, rectangles are drawn
    class RectangleDrawer extends ShapeDrawer {
        int pressx, pressy;
        int lastx = -1, lasty = -1;

        // mouse pressed => fix first corner of rectangle
        @Override
        public void mousePressed(MouseEvent e) {
            pressx = e.getX();
            pressy = e.getY();
        }

        // mouse released => fix second corner of rectangle
        // and draw the resulting shape
        @Override
        public void mouseReleased(MouseEvent e) {
            Graphics2D g2d = drawingPanel.getImageGraphics();
            if (lastx != -1) {
                // first undraw a rubber rect
                g2d.setXORMode(gui.getColor());
                g2d.setColor(gui.getBackground());
                doDraw(pressx, pressy, lastx, lasty, g2d);
                lastx = -1;
                lasty = -1;
            }
            // these commands finish the rubberband mode
            g2d.setPaintMode();
            g2d.setColor(gui.getColor());
            // draw the final rectangle
            doDraw(pressx, pressy, e.getX(), e.getY(), g2d);
            g2d.dispose();
            drawingPanel.repaint(); // Neu hinzugefügt
        }

        // mouse released => temporarily set second corner of rectangle
        // draw the resulting shape in "rubber-band mode"
        @Override
        public void mouseDragged(MouseEvent e) {
            Graphics g = drawingPanel.getImageGraphics();
            // these commands set the rubberband mode
            g.setXORMode(gui.getColor());
            g.setColor(gui.getBackground());
            if (lastx != -1) {
                // first undraw previous rubber rect
                doDraw(pressx, pressy, lastx, lasty, g);

            }
            lastx = e.getX();
            lasty = e.getY();
            // draw new rubber rect
            doDraw(pressx, pressy, lastx, lasty, g);
        }

        public void doDraw(int x0, int y0, int x1, int y1, Graphics g) {
            // calculate upperleft and width/height of rectangle
            int x = Math.min(x0, x1);
            int y = Math.min(y0, y1);
            int w = Math.abs(x1 - x0);
            int h = Math.abs(y1 - y0);
            // draw rectangle
            g.drawRect(x, y, w, h);
        }
    }

    // if this class is active, ovals are drawn
    class OvalDrawer extends RectangleDrawer {
        @Override
        public void doDraw(int x0, int y0, int x1, int y1, Graphics g) {
            int x = Math.min(x0, x1);
            int y = Math.min(y0, y1);
            int w = Math.abs(x1 - x0);
            int h = Math.abs(y1 - y0);
            // draw oval instead of rectangle
            g.drawOval(x, y, w, h);
        }
    }

    ScribbleDrawer scribbleDrawer = new ScribbleDrawer();
    RectangleDrawer rectDrawer = new RectangleDrawer();
    OvalDrawer ovalDrawer = new OvalDrawer();
    ShapeDrawer currentDrawer;

    public ShapeManager(DrawGUI gui, DrawingPanel drawingPanel) {
        this.gui = gui;
        this.drawingPanel = drawingPanel;

        currentDrawer = scribbleDrawer;
        this.gui.addMouseListener(currentDrawer);
        this.gui.addMouseMotionListener(currentDrawer);
    }

    // reset the shape drawer
    public void setCurrentDrawer(ShapeDrawer l) {
        if (currentDrawer == l)
            return;

        // activate new drawer
        gui.removeMouseListener(currentDrawer);
        gui.removeMouseMotionListener(currentDrawer);
        currentDrawer = l;
        gui.addMouseListener(currentDrawer);
        gui.addMouseMotionListener(currentDrawer);
    }

    // user selected new shape => reset the shape mode
    @Override
    public void itemStateChanged(ItemEvent e) {
        if (e.getItem().equals("Scribble")) {
            setCurrentDrawer(scribbleDrawer);
        } else if (e.getItem().equals("Rectangle")) {
            setCurrentDrawer(rectDrawer);
        } else if (e.getItem().equals("Oval")) {
            setCurrentDrawer(ovalDrawer);
        }
    }
}`


`/**
This class represents a panel for drawing shapes.
It provides methods to clear the image, retrieve the graphics object of the image,
and paint the image on the panel.
*/

package mydraw.gui;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class DrawingPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private BufferedImage image;

    /**
     * 
     * Constructs a new DrawingPanel with a default image size of 800 x 400 pixels.
     * The image is initialized with a white background.
     */
    public DrawingPanel() {
        image = new BufferedImage(800, 400, BufferedImage.TYPE_INT_ARGB);
        clearImage();
    }

    /**
     * 
     * Clears the image by filling it with a white color.
     */
    public void clearImage() {
        Graphics2D g2d = image.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
        g2d.dispose();
    }

    /**
     * 
     * Returns the graphics object of the image for drawing shapes on it.
     * 
     * @return the graphics object of the image
     */
    public Graphics2D getImageGraphics() {
        return image.createGraphics();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, null);
    }
}
`

我已经尝试使用System. out.println来“调试”“doCommand”方法,我发现只有当单击“autoDraw”时,“autoDraw被按下”的句子才会打印到控制台。当单击其余按钮时,没有任何东西会打印到控制台。只有当我通过macOS菜单关闭应用程序窗口时,“Quit按钮被按下”才会在控制台上输出,而不是通过单击Quit按钮本身。


共2个答案

匿名用户

稍后我会把这个编辑成一个真正的答案,但是是在黑暗中拍摄的。

更改下面的这一行。

if(命令. equals(CLEAR)){

改成这样吧。

if(命令. equals(DrawGUI.CLEAR)){

您可能需要进行一些导入。

匿名用户

发生这种情况是因为在本节中,最终变量CLEAR、QUIT、SAVE被初始化为null,因此您的if比较总是错误的。像IntelliJ这样的好IDE会发现这个问题并警告您。

我想你可能搞混了,因为你的Draw有这些变量(它们为空),DrawGUI类也有这些变量(它们有值),你正在相互比较这两个变量。去掉Draw类中的变量,这样你就可以将同一个变量与它本身进行比较。

public void doCommand(String command) {
    if (command.equals(CLEAR)) {
        window.clear();
        System.out.println("CLEAR button clicked");
    } else if (command.equals(QUIT)) {
        window.dispose();
        System.out.println("QUIT button clicked");
        System.exit(0);
    } else if (command.equals(SAVE)) {
        Image img = window.createImageFromPanel();
        try {
            writeImage(img, "hallo.bmp");
            System.out.println("SAVE button clicked");
        } catch (IOException e) {
            System.err.println("Not working");
        }
    } else if (command.equals(AUTODRAW)) {
        autoDraw();
        System.out.println("AUTODRAW button clicked");
    }
}

附言:从风格上来说,我不喜欢你通过一个带有参数的doCommand()方法运行所有内容,该参数用于调度要采取的操作。如果它是我的,我会为每个操作使用不同的方法,只需从操作侦听器中调用这些方法。这样你就可以摆脱所有这些变量,根本不需要做任何比较if/else-if的东西。