How to figure out on which screen a JDialog is shown
Asked Answered
O

3

7

I have a really big application which has multiple dialogs. My task is to make sure that a dialog, which is not completely visible (because the user pulled it out of the visible screen area) is moved back to the center of the screen.

That's no problem when I'm dealing with one screen only. It works just fine ... however, most users of this application have two screens on their desktop ...

When I try to figure out on which screen the dialog is shown and center it on that specific screen, ... well, it actually DOES center, but on the primary screen (which may not be the screen the dialog is shown on).

To show you what my thoughts were so far, here's the code ...

 /**
 * Get the number of the screen the dialog is shown on ...
 */
private static int getActiveScreen(JDialog jd) {
    int screenId = 1;
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gd = ge.getScreenDevices();
    for (int i = 0; i < gd.length; i++) {
        GraphicsConfiguration gc = gd[i].getDefaultConfiguration();
        Rectangle r = gc.getBounds();
        if (r.contains(jd.getLocation())) {
            screenId = i + 1;
        }
    }
    return screenId;
}

/**
* Get the Dimension of the screen with the given id ...
*/
private static Dimension getScreenDimension(int screenId) {
    Dimension d = new Dimension(0, 0);
    if (screenId > 0) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        DisplayMode mode = ge.getScreenDevices()[screenId - 1].getDisplayMode();
        d.setSize(mode.getWidth(), mode.getHeight());
    }
    return d;
}

/**
 * Check, if Dialog can be displayed completely ...
 * @return true, if dialog can be displayed completely
 */
private boolean pruefeDialogImSichtbarenBereich() {
    int screenId = getActiveScreen(this);
    Dimension dimOfScreen = getScreenDimension(screenId);
    int xPos = this.getX();
    int yPos = this.getY();
    Dimension dimOfDialog = this.getSize();
    if (xPos + dimOfDialog.getWidth() > dimOfScreen.getWidth() || yPos + dimOfDialog.getHeight() > dimOfScreen.getHeight()) {
        return false;
    }
    return true;
}

/**
 * Center Dialog...
 */
private void zentriereDialogAufMonitor() {
    this.setLocationRelativeTo(null);
}

While debugging I kind of came across the fact that getActiveScreen() does not seem to work the way i though; it seems to always return 2 (which is kind of crap, since it would mean the dialog is always shown in the second monitor...which of course isn't the truth).

Anyone got any idea how to center my dialog on the screen it is actually shown on?

Olvera answered 28/8, 2012 at 11:42 Comment(3)
How many screens will app shown on multiple displays?Budgerigar
I'm not quite sure if i get your question, but if I understood it correctly, ... I don't know. It doesn't even matter, because the position of the dialogs is saved and checked everytime the dialog gets visible ... does this answer your question? :-)Olvera
Why don't you specify location on the screen for the dialog?Budgerigar
A
1

Your getActiveScreen method worked, except it used the screen containing the top-left corner of the window. If you use Component.getGraphicsConfiguration() instead, it will give you which screen has the most of the window's pixels. setLocationRelativeTo(null) is no help here because it always uses the primary screen. Here's how to solve it:

static boolean windowFitsOnScreen(Window w) {
    return w.getGraphicsConfiguration().getBounds().contains(w.getBounds());
}

static void centerWindowToScreen(Window w) {
    Rectangle screen = w.getGraphicsConfiguration().getBounds();
    w.setLocation(
        screen.x + (screen.width - w.getWidth()) / 2,
        screen.y + (screen.height - w.getHeight()) / 2
    );
}

Then you can do:

JDialog jd;
...
if (!windowFitsOnScreen(jd)) centerWindowToScreen(jd);

which will center the dialog to the nearest screen (monitor). You might need to make sure the dialog has been initially displayed/positioned first.

Assize answered 28/8, 2012 at 16:14 Comment(1)
Thanks for your reply :-) It does not work 100% the way I initially wanted it to work, but the behaviour is quite okay now :-) Thank you very much! :-)Olvera
P
1

I'm not sure how much of this will be of use, but this is the code that I use when trying to determine graphic devices for windows.

I cheat a little, I tend to use Component and allow the utility methods to either find the top level window or use the Component's screen point.

/**
 * Returns the GraphicsDevice that the specified component appears the most on.
 */
public static GraphicsDevice getGraphicsDevice(Component comp) {

    GraphicsDevice device = null;

    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice lstGDs[] = ge.getScreenDevices();

    ArrayList<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
    if (comp != null && comp.isVisible()) {
        Rectangle parentBounds = comp.getBounds();

        /*
         * If the component is not a window, we need to find its location on the
         * screen...
         */
        if (!(comp instanceof Window)) {
            Point p = new Point(0, 0);
            SwingUtilities.convertPointToScreen(p, comp);
            parentBounds.setLocation(p);
        }

        for (GraphicsDevice gd : lstGDs) {
            GraphicsConfiguration gc = gd.getDefaultConfiguration();
            Rectangle screenBounds = gc.getBounds();
            if (screenBounds.intersects(parentBounds)) {
                lstDevices.add(gd);
            }
        }

        if (lstDevices.size() == 1) {
            device = lstDevices.get(0);
        } else {

            GraphicsDevice gdMost = null;
            float maxArea = 0;
            for (GraphicsDevice gd : lstDevices) {
                int width = 0;
                int height = 0;

                GraphicsConfiguration gc = gd.getDefaultConfiguration();
                Rectangle bounds = gc.getBounds();

                Rectangle2D intBounds = bounds.createIntersection(parentBounds);

                float perArea = (float) ((intBounds.getWidth() * intBounds.getHeight()) / (parentBounds.width * parentBounds.height));
                if (perArea > maxArea) {
                    maxArea = perArea;
                    gdMost = gd;
                }
            }

            if (gdMost != null) {
                device = gdMost;
            }
        }
    }
    return device;
}

/**
 * Returns the GraphicsDevice at the specified point
 */
public static GraphicsDevice getGraphicsDeviceAt(Point pos) {
    GraphicsDevice device = null;
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice lstGDs[] = ge.getScreenDevices();

    List<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
    for (GraphicsDevice gd : lstGDs) {

        GraphicsConfiguration gc = gd.getDefaultConfiguration();
        Rectangle screenBounds = gc.getBounds();
        if (screenBounds.contains(pos)) {
            lstDevices.add(gd);
        }
    }

    if (lstDevices.size() > 0) {
        device = lstDevices.get(0);
    }

    return device;
}

/**
 * Returns the Point that would allow the supplied Window to be
 * centered on it's current graphics device.
 * 
 * It's VERY important that the Window be seeded with a location
 * before calling this method, otherwise it will appear on the 
 * device at 0x0
 *
 * @param window
 * @return
 */
public static Point centerOfScreen(Window window) {
    // Try and figure out which window we actually reside on...
    GraphicsDevice gd = getGraphicsDeviceAt(window.getLocation());
    GraphicsConfiguration gc = gd.getDefaultConfiguration();

    Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gd.getDefaultConfiguration());
    Rectangle bounds = gc.getBounds();
    Dimension size = bounds.getSize();

    size.width -= (screenInsets.left + screenInsets.right);
    size.height -= (screenInsets.top + screenInsets.bottom);

    int width = window.getWidth();
    int height = window.getHeight();

    int xPos = screenInsets.left + ((size.width - width) / 2);
    int yPos = screenInsets.top + ((size.height - height) / 2);

    return new Point(xPos, yPos);
}
Planospore answered 29/8, 2012 at 3:41 Comment(0)
B
0

Here's the code used to center location of the window.

  //Center the window
  Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  Dimension frameSize = frame.getSize();
  if (frameSize.height > screenSize.height) {
    frameSize.height = screenSize.height;
  }
  if (frameSize.width > screenSize.width) {
    frameSize.width = screenSize.width;
  }
  frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);

with the frame you can use the dialog as well.

Budgerigar answered 28/8, 2012 at 12:28 Comment(1)
This does not answer the question. It just tells how to do it in a single-screen environment (which OP stated is already working for him)...Mozza

© 2022 - 2024 — McMap. All rights reserved.