javamousemovecorruptionawtrobotmemory-corruption

Removing print statement affects functionality... corruption at play?


I wrote a java program which will minimize a window when moved to lower portion of screen. It performs the task by moving the mouse with Robot to the minimize button and pressing it with mousePress and mouseRelease. I'm certain there is a more ideal way to write this program but I am not looking for that.

I noticed something strange when testing it. When removing a print statement, the program did not work as expected, and did not minimize the window. The print statement should have no effect on the functionality of the program, so I think there may be some sort of corruption at play. Does the Point variable not actualize without the print statement for some reason?

I am wondering what is causing this failure and seeking an explanation as to what is going on behind the scenes with this issue.

Here is the code:

import java.awt.AWTException;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;

import javax.swing.JFrame;

public class AutoMinimize {

    public static void main(String[] args) {
        JFrame frame = new JFrame("My mini frame");
        frame.setSize(200,200);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        
        frame.setVisible(true);
        
        outerloop:
        while(true) {
            Point location = frame.getLocation();
            System.out.println(location); //Comment out this print statement and it doesnt work??
            if (location.getY()>700) {
                try {
                    Thread.sleep(1000);
                    location = frame.getLocation();
                    Robot r = new Robot();
                    r.mouseMove(((int) location.getX()+34), ((int) location.getY()+14));
                    r.mousePress(InputEvent.BUTTON1_MASK);
                    r.mouseRelease(InputEvent.BUTTON1_MASK);
                    break outerloop;
                } catch (AWTException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

NOTE: the mouse movement works for MacOS systems, but you may need to adjust coordinates for different operating systems.


Solution

  • As to the actual cause of your problem - I can't say (with accuracy) as it caused to many side effects and issues - not unsurprising when using Robot this way.

    However, I would:

    However, I was able to replicate the functionality using a ComponentListener instead...

    import java.awt.EventQueue;
    import java.awt.GraphicsConfiguration;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.Rectangle;
    import java.awt.Toolkit;
    import java.awt.event.ComponentAdapter;
    import java.awt.event.ComponentEvent;
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowStateListener;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    
    public class Main {
        public static void main(String[] args) {
            new Main();
        }
    
        public Main() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                    frame.addComponentListener(new ComponentAdapter() {
                        @Override
                        public void componentMoved(ComponentEvent e) {
                            GraphicsConfiguration gc = e.getComponent().getGraphicsConfiguration();
                            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
                            Rectangle bounds = gc.getBounds();
                            int height = bounds.height - (insets.top + insets.bottom);
                            int range = height - (e.getComponent().getHeight() * 2);
    
                            if (e.getComponent().getY() > range) {
                                frame.setExtendedState(JFrame.ICONIFIED);
                            }
                        }
                    });
    
                    frame.addWindowStateListener(new WindowStateListener() {
                        @Override
                        public void windowStateChanged(WindowEvent e) {
                            if (e.getNewState() == JFrame.ICONIFIED) {
                                frame.setLocationRelativeTo(null);
                            }
                        }
    
                    });
                }
            });
        }
    
        public class TestPane extends JPanel {
            public TestPane() {
                setBorder(new EmptyBorder(32, 32, 32, 32));
                setLayout(new GridBagLayout());
                add(new JLabel("Nothing to see here"));
            }
        }
    }
    

    Essentially what this does is, on move, it will calculate the current screens viewable size (taking into account the menu and task bar), calculate a "hit zone" which is the height of the screen minus double the window height, when the window passes this "hit zone" it will be minimised.

    As an additional feature, when the window is minimised, it's location will be reset (to the center of the screen)

    As a nice side effect, this is now cross platform capable