4

I am stuck with a very unusual situation. I have a class "ScreenSizeSelector" which has a method 'getSelectedScreenSize'. The method's work is to create a UI, user drags the UI and method return back size of window.

Now I am calling the method of class in following ways:

  1. A simple class (non GUI)
  2. On the button click from a JFrame

In the first case, it is working perfectly fine (i.e. size selector window opens, user drags it, resize it and it is giving back window coordinates) but in second case, window opens but in disabled mode, user is not able to perform any operation on the window, not even able to close the window.

Here is the code I am using

ScreenSizeSelector class :

package screenrecorder;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.Border;


class ScreenSizeSelector {

    private JFrame sizeSelectorWindow;
    private JButton btnOk;
    private Border emptyBorder;
    private Rectangle screenArea = null;
    private static Object lock = new Object();



    public Rectangle getSelectedScreenSize(){

        screenSizeSelectorUI();

        Thread t = new Thread() {
            public void run() {
                synchronized(lock) {
                    while (sizeSelectorWindow.isVisible())
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                }
            }
        };

        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return screenArea;
    }


    public void screenSizeSelectorUI() {
        emptyBorder = BorderFactory.createEmptyBorder();

        sizeSelectorWindow = new JFrame("Select screen area");

        btnOk = new JButton("Start");
        sizeSelectorWindow.setUndecorated(true);
        sizeSelectorWindow.getRootPane().setWindowDecorationStyle(3);
        sizeSelectorWindow.setBackground( new Color(0, 0, 0, 0) );
        sizeSelectorWindow.setSize(400,400);

        sizeSelectorWindow.addWindowListener(new WindowEventHandler());
        sizeSelectorWindow.setAlwaysOnTop(true);
        sizeSelectorWindow.setLocationRelativeTo(null);


        btnOk.setToolTipText("Click this button after deciding the screen area");
        btnOk.addActionListener(new ButtonEventHandler());


        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.setBackground(new Color(0,0,0,0));
        buttonPanel.add(btnOk);
        sizeSelectorWindow.add(buttonPanel,BorderLayout.SOUTH);

        sizeSelectorWindow.setVisible(true);
        sizeSelectorWindow.setEnabled(true);

    }

class ButtonEventHandler implements ActionListener {

@Override
public void actionPerformed(ActionEvent e) {

    int x = (int)(sizeSelectorWindow.getBounds().getX());
    int y = (int) (sizeSelectorWindow.getBounds().getY());
    int width = sizeSelectorWindow.getWidth();
    int height = sizeSelectorWindow.getHeight();

    screenArea = new Rectangle(x,y,width,height);
    sizeSelectorWindow.dispatchEvent(new WindowEvent(sizeSelectorWindow, WindowEvent.WINDOW_CLOSING));
}


}

class WindowEventHandler implements WindowListener{

    @Override
    public void windowOpened(WindowEvent e) {
    }

    @Override
    public void windowClosing(WindowEvent e) {

        synchronized (lock) {
            sizeSelectorWindow.setVisible(false);
            lock.notify();
        }
    }

    @Override
    public void windowClosed(WindowEvent e) {
    }

    @Override
    public void windowIconified(WindowEvent e) {
        sizeSelectorWindow.setState(JFrame.NORMAL);
        Toolkit.getDefaultToolkit().beep();
    }

    @Override
    public void windowDeiconified(WindowEvent e) {}

    @Override
    public void windowActivated(WindowEvent e) {}

    @Override
    public void windowDeactivated(WindowEvent e) {}


    }

}

Test1 class :

package screenrecorder;

import java.awt.Rectangle;

public class Test1{

    public static void main(String[] args){
        System.out.println(new ScreenSizeSelector().getSelectedScreenSize());
    }
}

Test2 class :

package screenrecorder;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Test2 extends JFrame{

    public Test2(){

        JButton btn = new JButton("Click ME");
        btn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println(new ScreenSizeSelector().getSelectedScreenSize());

            }
        });

        getContentPane().add(btn);
        setSize(100,100);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

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

}

Any help is appreciated.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433

1 Answers1

0

when you click the button, the action listener waits for the getSelectedScreenSize() function to return. and the getSelectedScreenSize() function is waiting for the second window created by screenSelectorUI() to be invisible. screenSelectorUI() does create a second window, but you set the color like this:

sizeSelectorWindow.setBackground( new Color(0, 0, 0, 0) );

if you look at the color constructor javadocs:

public Color(int r,
                int g,
                int b,
                int a)

Creates an sRGB color with the specified red, green, blue, and alpha values in the range (0 - 255).
Parameters:

  • r - the red component
  • g - the green component
  • b - the blue component
  • a - the alpha component

you set the alpha value to 0, making it completely invisible. (alpha value is transparency) also, this second window is undecorated and does not exit on close, so you don't even know it's there at all.

what I don't get is how test1 worked at all. side note: when I try test 1 on mac it only shows the button and all I can do is click it. the button will disappear, but the application will still be running.

This is basically a total guess, but a lot of the swing components make requests to the operating system, not commands. sort of like saying, "hey can I please be resized to 400, 400?" the OS doesn't technically have to do what you say. and I was reading How does Java handle multithreading? which says that multithreading really depends on the OS. I have a feeling it just messes up somewhere when screenSelectorUI() is called by itself, but somehow gets it right when it's inside the thread of some button.

Community
  • 1
  • 1
Funny Geeks
  • 483
  • 5
  • 12
  • Hi, the UI is visible (in Test1 and I ran the same on windows). The border of the frame is visible though the background is transparent. So You will see a button and the border of the frame. – Chirag Bansal Jul 28 '16 at 09:54