如何在 Java 中的事件处理程序中的 JLabel 上画一条线?

How to draw a line on a JLabel in an event handler in Java?

我一直在努力解决这个问题,但我一遍又一遍地面临同样的错误。

我基本上是在尝试加载 .png 文件,然后在单击两次后画一条线。

public class GroundTruthMarker extends JPanel {

private JFrame frame;
boolean leftSideDone = false;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                GroundTruthMarker window = new GroundTruthMarker();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the application.
 */
public GroundTruthMarker() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 1178, 844);
    frame.setResizable(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);

    // points to hold the clicked coordinates
    Point leftSide = new Point();
    Point rightSide = new Point();

    // status label
    JLabel lblStatus = new JLabel("");
    lblStatus.setBounds(373, 807, 134, 20);
    frame.getContentPane().add(lblStatus);

    JButton btnSave = new JButton("Save");
    btnSave.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            lblStatus.setText("Saved!");
        }
    });
    btnSave.setBounds(215, 807, 117, 25);
    frame.getContentPane().add(btnSave);

    JLabel lblpicture = new JLabel("");
    lblpicture.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {

            if (leftSideDone == false) {
                leftSide.x = e.getX();
                leftSide.y = e.getY();
                lblStatus.setText("Left Side Done!");
                leftSideDone = true;
            } else {
                rightSide.x = e.getX();
                rightSide.y = e.getY();
                lblStatus.setText("Right Side Done!");
                leftSideDone = false;

                Graphics g = getGraphics();
                g.setColor(Color.cyan);
                g.drawLine(leftSide.x, leftSide.y, rightSide.x, rightSide.y);
            }

        }
    });

    // picture label
    lblpicture.setBackground(Color.WHITE);
    lblpicture.setBounds(12, 12, 1154, 765);
    // create a line border with the specified color and width
    Border border = BorderFactory.createLineBorder(Color.BLUE, 1);
    // set the border of this component
    lblpicture.setBorder(border);
    frame.getContentPane().add(lblpicture);

    JButton btnLoadImages = new JButton("Load Images");
    btnLoadImages.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // set up the file chooser
            JFileChooser fileChooser = new JFileChooser();
            // only directories
            fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
                File dir = fileChooser.getSelectedFile();
                // load from the directory
                System.out.println(dir.getName());
                // loop over the image directory
                if (dir.isDirectory()) { // make sure it's a directory
                    for (final File f : dir.listFiles()) {
                        BufferedImage img = null;
                        // read every image and display it in the gui
                        try {
                            lblStatus.setText("New Image!");
                            img = ImageIO.read(f);
                            lblpicture.setIcon(new ImageIcon(img));

                        } catch (final IOException e1) {
                            // handle errors here
                            System.out.println("Error:" + e1.getMessage());
                        }
                    }
                }
            }
        }
    });
    btnLoadImages.setBounds(23, 807, 144, 25);
    frame.getContentPane().add(btnLoadImages);
}

}

这是我在运行时遇到的错误,当我期待一行时:

java.lang.NullPointerException
    at GroundTruthMarker.mouseClicked(GroundTruthMarker.java:101)
    at java.awt.Component.processMouseEvent(Component.java:6538)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
    at java.awt.Component.processEvent(Component.java:6300)
    at java.awt.Container.processEvent(Container.java:2236)
    at java.awt.Component.dispatchEventImpl(Component.java:4891)
    at java.awt.Container.dispatchEventImpl(Container.java:2294)
    at java.awt.Component.dispatchEvent(Component.java:4713)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4534)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
    at java.awt.Container.dispatchEventImpl(Container.java:2280)
    at java.awt.Window.dispatchEventImpl(Window.java:2750)
    at java.awt.Component.dispatchEvent(Component.java:4713)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
    at java.awt.EventQueue.access0(EventQueue.java:97)
    at java.awt.EventQueue.run(EventQueue.java:709)
    at java.awt.EventQueue.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.awt.EventQueue.run(EventQueue.java:731)
    at java.awt.EventQueue.run(EventQueue.java:729)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

请记住,绘图必须在事件处理程序中进行。我尝试了一些方法,但遇到了 "You cannot do this in mouse-event-handler" 种错误,所以它们没有用。

感谢任何形式的帮助。

谢谢。

像这样更改您的代码

public class GroundTruthMarker extends JPanel {

    private BufferedImage img = null;  // ADD THIS LINE
    [...]
    private void initialize() {
        [...]
        // JLabel lblpicture = new JLabel("");  // REMOVE THIS LINE
        // ADD THE FOLLOWING INSTEAD
        JPanel lblpicture = new JPanel(){
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(img,0,0,null);
                g.setColor(Color.cyan);
                g.drawLine(leftSide.x, leftSide.y, rightSide.x, rightSide.y);
            }
        };
        [...]
        public void mouseClicked(MouseEvent e) {
            [...]
            // REMOVE THIS!
            //Graphics g = getGraphics();
            //g.setColor(Color.cyan);
            //g.drawLine(leftSide.x, leftSide.y, rightSide.x, rightSide.y);
            // ADD THIS INSTEAD
            lblpicture.repaint();
        }
        [...]
        public void actionPerformed(ActionEvent e) {
            [...]
            // REMOVE THIS LINE
            //BufferedImage img = null;
            [...]
            // REMOVE THIS LINE
            //lblpicture.setIcon(new ImageIcon(img));
            // ADD THIS LINE INSTEAD
            lblpicture.repaint();
            [...]
        }
    }
}