javaswingjframerepaintglasspane

JFrame and GlassPane - Trouble with repaint()


This question may be a simple matter of me lacking a fundamental understanding of Java Swing or Graphics, and if so, I apologize.

I'm trying to develop a GUI application using Java Swing that can be controlled by an external device that sends pitch, yaw, and roll values via bluetooth to the Application. My idea is to create a cursor (perhaps an empty circle) that moves around when the external device moves around. I have no problems with receiving the data from the device, just the part where I need to actually paint something over all of my components.

I figured that a GlassPane was the easiest way to show a cursor over the entire application, and have it move around when the external device is moved around. I use a Thread to capture the data, and I'm trying to call repaint() afterwards, but it doesn't seem to be triggering.

Here is the relevant code:

JFrame:

public class Frame extends JFrame {

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    //Thread myoHandlerThread = new Thread(myoHandler);
                    //myoHandlerThread.start();

                    Frame frame = new Frame();
                    GlassPane glassPane = new GlassPane();
                    glassPane.setVisible(true);
                    frame.setGlassPane(glassPane);

                    frame.setVisible(true);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */

    public Frame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(50, 50, 1000, 650);

        /* Code to add and place components */
    }
}

And my GlassPane:

public class GlassPane extends JComponent {

    private static double pitch;
    private static double yaw;
    private static double roll;

    Point point;

    public void setPoint(Point p) {
        this.point = p;
    }

    public void paintComponent(Graphics g) {
        if (point != null) {
            System.out.println("Test print statement");
            g.setColor(Color.red);
            g.fillOval(point.x - 10, point.y - 10, 20, 20);
        }
    }

    public GlassPane() {
        Thread handler = new Thread(deviceHandler);
        handler.start();
    }

    private Runnable deviceHandler = new Runnable() {

        @Override
        public void run() {

            Hub hub = new Hub("com.garbage");

            System.out.println("Attempting to find device...");
            Device externalDevice = hub.waitForDevice(10000);

            if (externalDevice == null) {
                throw new RuntimeException("Unable to find device!");
            }

            System.out.println("Connected");
            DataCollector dataCollector = new DataCollector();
            hub.addListener(dataCollector);

            while (true) {
                hub.run(1000/20); //gathers data and stores in dataCollector
                roll = dataCollector.getRoll();
                pitch = dataCollector.getPitch();
                yaw = dataCollector.getYaw();

                Point p = new Point();
                p.setLocation(Math.abs(pitch) * 10, Math.abs(yaw) * 10);
                setPoint(p);

                repaint();

            }
        }

    };

}

What I would like to happen is for a red circle to be drawn somewhere on the GUI depending on the orientation of the external device. At this point, my "test print statement" doesn't fire even once.

My guess is that I'm lacking some sort of basic understanding of Java's GlassPane or even how paint, paintComponent, and repaint even works. Could anyone point out what I'm doing wrong?


Solution

  • The likely cause of your frustration is trying to set the glass pane visible (Swing components are visible by default), before setting it as the frames GlassPane.

    The JFrame is likely resetting the glass pane to be invisible, meaning that it won't be painted (no point painting something that's not visible)

    Try setting the glass pane visible AFTER you apply it to the frame