Skip to content
Advertisement

JFrame.addMouseListener doesn’t register clicks

I am currently writing an application in java that needs to take in input from the user. I have tried many ways to implement the input but none of them work. I am rendering objects with the graphics interface if that helps. I have tried a couple of methods to implement mouse interaction:

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

public class Window extends Canvas {
    JFrame frame;
    boolean mousePressed = false;

    public Window(String windowName, int windowWidth, int windowHeight, Main main) {
        frame = new JFrame(windowName);
        frame.setSize(new Dimension(windowWidth, windowHeight));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("Clicked!");
            }
        });
        frame.add(main);
        frame.setVisible(true);
        main.start();
    }
}

And

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

public class Window extends Canvas implements MouseListener {
    JFrame frame;
    boolean mousePressed = false;

    public Window(String windowName, int windowWidth, int windowHeight, Main main) {
        frame = new JFrame(windowName);
        frame.setSize(new Dimension(windowWidth, windowHeight));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.addMouseListener(this);
        frame.add(main);
        frame.setVisible(true);
        main.start();
    }
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("Clicked!");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("Clicked!");
            }
}

However when I run the application it doesent print anything. Here is my main class:

import java.awt.*;
import java.awt.image.BufferStrategy;

public class Main extends Canvas implements Runnable {
    final String windowName = "Hand Written Digits Reader";
    final int windowWidth = 500;
    final int windowHeight = 500;

    boolean running = false;

    Window window;
    Thread thread;
    NeuralNetwork neuralNetwork = new NeuralNetwork();

    public Main() {
        window = new Window(windowName, windowWidth, windowHeight, this);
    }
    public void start() {
        thread = new Thread(this);
        thread.start();
        running = true;
    }
    public void stop() {
        try {
            thread.join();
            running = false;
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    public void run() {
        long lastTime = System.nanoTime();
        double fps = 1.0;
        double ns = 100000000 / fps;
        double delta = 0;

        while(running)
        {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while(delta >= 1)
            {
                tick();
                delta--;
            }

            render();
        }
        stop();
    }
    public void tick() {
    }
    public void render() {
        BufferStrategy bs = this.getBufferStrategy();
        if (bs == null) {
            this.createBufferStrategy(3);
            return;
        }
        Graphics g = bs.getDrawGraphics();
        neuralNetwork.drawGUI(g, window.frame, window.mousePressed);

        g.dispose();
        bs.show();
    }
    public static void main(String[] args) {
        new Main();
    }
}

Advertisement

Answer

Add the MouseListener to the component you are interested in monitoring, in this case, that would be your Main class.

JFrame is never a good candidate for a MouseListener, it’s a composite component, meaning that it has a number of components presented on top if it, any of which could consume mouse events

enter image description here

(from How to Use Root Panes)

Your Window class makes sense, there’s no need for it to extend from Canvas, and since Window is already a class in AWT, it’s also confusing.

There’s no need for Main to be calling Window, this is just adding more confusion. A component shouldn’t be creating it’s own window, that’s not it’s responsibility, instead, it should be added to a container of callers choosing when its created.

This…

public void stop() {
    try {
        thread.join();
        running = false;
    } catch(Exception e) {
        e.printStackTrace();
    }
}

is never going to work, since the loop is waiting for running to be false and join is blocking call, there’s no way that the thread will ever exit. Also consider that running is been used across different threads and it’s possible that you’ll end up in a “dirty read/write” scenario.

I’ve seen this code before, so where ever you are copying it from, stop and find a better source.

Your main loop is also dangerous. It’s creating a “wild loop”, these kind of loops can consume CPU cycles, starving other threads from running (or running as often as they should) and generally cause no end of performance issues. Instead, you should be (at the very least), making use of Thread.yield or, even better, Thread.sleep.

Remember, a screen can only refresh so many times a second, so updating the UI beyond that range is just wasting time. A “decent” target might be 60fps.

delta += (now - lastTime) / ns; doesn’t make sense to me (but I be dumb), what you really want to know is the amount of time it took to run the last update cycle and how long you need to wait in order to maintain the frame rate, double delta = (now - lastTime) / ns; makes more sense (to me).

Your use of BufferStrategy is also, well, wrong. The JavaDocs for BufferStrategy has an excellent example how you should be using it.

Again, I don’t know where you got the original code from, but I don’t recommending using that source in the future.

Runnable example…

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MainSurface mainSurface = new MainSurface();
                JFrame frame = new JFrame();
                frame.add(mainSurface);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                mainSurface.start();
            }
        });
    }

    public class MainSurface extends Canvas {
        private volatile boolean running = false;
        private Thread thread;
//        NeuralNetwork neuralNetwork = new NeuralNetwork();

        private Point dotty;

        public MainSurface() {
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    dotty = e.getPoint();
                }
            });
        }

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

        public void start() {
            if (thread != null) {
                stop();
            }
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    makeItSo();
                }
            });
            thread.start();
            running = true;
        }

        public void stop() {
            try {
                running = false;
                thread.join();
            } catch (Exception e) {
                e.printStackTrace();
            }
            thread = null;
        }

        protected void makeItSo() {
            long lastTime = System.nanoTime();
            double fps = 1.0;
            double ns = 100000000 / fps;
            double delta = 0;

            createBufferStrategy(3);

            while (running) {
                long now = System.nanoTime();
                delta += (now - lastTime) / ns;
                lastTime = now;
                if (delta > 0) {
                    try {
                        Thread.sleep((int) delta);
                    } catch (InterruptedException ex) {
                    }
                }
//                while (delta >= 1) {
//                    tick();
//                    delta--;
//                }

                render();
            }
            stop();
        }

        public void tick() {
        }

        public void render() {
            BufferStrategy bs = null;
            while (bs == null) {
                bs = getBufferStrategy();
            }
            do {
                // The following loop ensures that the contents of the drawing buffer
                // are consistent in case the underlying surface was recreated
                do {
                    // Get a new graphics context every time through the loop
                    // to make sure the strategy is validated
                    Graphics2D g2d = (Graphics2D) bs.getDrawGraphics();
                    g2d.setColor(getBackground());
                    g2d.fillRect(0, 0, getWidth(), getHeight());

                    // Render to graphics
                    // ...
                    g2d.setColor(Color.RED);
                    int x = (getWidth() - 100) / 2;
                    int y = (getHeight() - 100) / 2;
                    g2d.fillRect(x, y, 100, 100);

                    if (dotty != null) {
                        x = dotty.x - 10;
                        y = dotty.y - 10;
                        g2d.setColor(Color.BLUE);
                        g2d.fillOval(x, y, 20, 20);
                    }
                    // Dispose the graphics
                    g2d.dispose();

                    // Repeat the rendering if the drawing buffer contents
                    // were restored
                } while (bs.contentsRestored());
                // Display the buffer
                bs.show();
                // Repeat the rendering if the drawing buffer was lost
            } while (bs.contentsLost());
        }
    }
}
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement