对于一个模式的JDialog最佳位置,以避免被卡住(Optimal location for a m

2019-07-18 02:36发布

我的Swing应用程序必须显示一个模式对话框给用户。 对不起,不张贴SSCCE。

topContainer可能JFrameJApplet

private class NewGameDialog extends JDialog {
     public NewGameDialog () {
         super(SwingUtilities.windowForComponent(topContainer), "NEW GAME", ModalityType.APPLICATION_MODAL);

         //add components here

         getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

         //TODO:
         setSize(new Dimension(250, 200));
         setLocation(650, 300);
     }
}

我开始对话这样的网络事件

SwingUtilities.invokeLater(new Runnable() {
     @Override
     public void run() {
         NewGameDialog dialog = new NewGameDialog();
         dialog.setVisible(true);
     }
});

问题是我的对话框中设置的最佳位置。

1)如果它被设置为绝对值,并且我移动应用程序帧到第二屏幕,然后被显示在第一屏幕,其是奇怪的对话框。

2)如果它被设置的相对值的JFrame,它可能出现的用户移动的应用程序框架的屏幕的外侧和对话框被相对位于不会对用户可见。 而且由于它是模态,比赛将被卡住。

什么是考虑上述两种问题的最佳解决方案?

Answer 1:

这让我想起了我的一个非常喜欢的职位,采用Window.setLocationByPlatform(真) ,在计算器上。

如何最佳位置摇摆的GUI

编辑1:

您可以将添加FocusListener到您JDialogfocusGained(...)方法,你可以使用setLocationRelativeTo(null)同时为JFrameJDialog ,让他们都来给屏幕的中心,无论他们在哪里之前。

import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

/**
 * Created with IntelliJ IDEA.
 * User: Gagandeep Bali
 * Date: 1/14/13
 * Time: 7:34 PM
 * To change this template use File | Settings | File Templates.
 */
public class FrameFocus
{
    private JFrame mainwindow;
    private CustomDialog customDialog;

    private void displayGUI()
    {
        mainwindow = new JFrame("Frame Focus Window Example");
        customDialog = new CustomDialog(mainwindow, "Modal Dialog", true);
        mainwindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        JButton mainButton = new JButton(
                "Click me to open a MODAL Dialog");
        mainButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!customDialog.isShowing())
                    customDialog.setVisible(true);
            }
        });
        contentPane.add(mainButton);
        mainwindow.setContentPane(contentPane);
        mainwindow.pack();
        mainwindow.setLocationByPlatform(true);
        mainwindow.setVisible(true);
    }

    public static void main(String... args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new FrameFocus().displayGUI();
            }
        });
    }
}


class CustomDialog extends JDialog
{
    private JFrame mainWindow;
    public CustomDialog(JFrame owner, String title, boolean modal)
    {
        super(owner, title, modal);
        mainWindow = owner;
        JPanel contentPane = new JPanel();
        JLabel dialogLabel = new JLabel(
                "I am a Label on JDialog.", JLabel.CENTER);
        contentPane.add(dialogLabel);
        setContentPane(contentPane);
        pack();

        addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
                mainWindow.setLocationRelativeTo(null);
                setLocationRelativeTo(null);
            }

            @Override
            public void focusLost(FocusEvent e) {
                /*
                 * Nothing written for this part yet
                 */
            }
        });
    }
}

编辑2:

我搜索了一下这里和那里,而且事实证明,在我看来,实际上在其Monitor Screen应用程序自带的第一个实例,将决定它的GraphicsConfiguration 。 虽然我通过API漫游,只有在说一个getter方法GraphicsConfiguration啄出于同样没有setter方法(你仍然可以指定一个通过任何顶层窗口即构造的JFrame(...) / 的JDialog( ...) )。

现在,您可以占据你的脑袋与此代码,可以用来确定适当的位置,要设定,同样,你可能需要使用focusGain()方法在我看来,以满足你的问题的条件2。 看看连接的代码,但没有必要建立一个new JFrame/JDialog ,只是看如何让坐标屏幕(您可以在添加focusGain()方法来确定整个应用程序的位置。)

GraphicsEnvironment ge = GraphicsEnvironment.
    getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
for (int j = 0; j < gs.length; j++) {
    GraphicsDevice gd = gs[j];
    GraphicsConfiguration[] gc =
            gd.getConfigurations();
    for (int i=0; i < gc.length; i++) {
        JFrame f = new
        JFrame(gs[j].getDefaultConfiguration());
        Canvas c = new Canvas(gc[i]);
        Rectangle gcBounds = gc[i].getBounds();
        int xoffs = gcBounds.x;
        int yoffs = gcBounds.y;
        f.getContentPane().add(c);
        f.setLocation((i*50)+xoffs, (i*60)+yoffs);
        f.show();
    }
}

编辑3:

尝试改变这一点:

int x = loc.getX() + (mainWindow.getWidth() - getWidth()) / 2;
int y = loc.getY() + (mainWindow.getHeight() - getHeight()) / 2;
setLocation(x, y);

只是:

setLocationRelativeTo(mainWindow);

为了检验上述啄,我用我的FrameFocus类原样,虽然我已经加你改变我的CustomDialog方法,如本修改CustomDialog类。

class CustomDialog extends JDialog
{
    private JFrame mainWindow;
    public CustomDialog(JFrame owner, String title, boolean modal)
    {
        super(owner, title, modal);
        mainWindow = owner;
        JPanel contentPane = new JPanel();
        JLabel dialogLabel = new JLabel(
                "I am a Label on JDialog.", JLabel.CENTER);
        contentPane.add(dialogLabel);
        setContentPane(contentPane);
        pack();

        addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
                //mainWindow.setLocationRelativeTo(null);
                //setLocationRelativeTo(null);
                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                GraphicsDevice[] gs = ge.getScreenDevices();
                for (int j = 0; j < gs.length; j++) {
                    GraphicsDevice gd = gs[j];
                    GraphicsConfiguration[] gc = gd.getConfigurations();
                    for (int i=0; i < gc.length; i++) {
                        Rectangle gcBounds = gc[i].getBounds();

                        Point loc = mainWindow.getLocationOnScreen();
                        if (gcBounds.contains(loc)) {
                            System.out.println("at " + j + " screen");

                            int x = gcBounds.x + (gcBounds.width - mainWindow.getWidth()) / 2;
                            int y = gcBounds.y + (gcBounds.height - mainWindow.getHeight()) / 2;
                            mainWindow.setLocation(x, y);

                            //x = (int) (loc.getX() + (mainWindow.getWidth() - CustomDialog.this.getWidth()) / 2);
                            //y = (int) (loc.getY() + (mainWindow.getHeight() - CustomDialog.this.getHeight()) / 2);
                            //CustomDialog.this.setLocation(x, y);
                            CustomDialog.this.setLocationRelativeTo(mainWindow);

                            break;
                        }
                    }
                }
            }

            @Override
            public void focusLost(FocusEvent e) {
                /*
                 * Nothing written for this part yet
                 */
            }
        });
    }
}


Answer 2:

我认为,最好的是描述居中对话框在当前屏幕的中间位置 。

Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = toolkit.getScreenSize();
int x = (screenSize.width - d.getWidth()) / 2;
int y = (screenSize.height - d.getHeight()) / 2;
d.setLocation(x, y);

这始终工作,以及它如何可以是无形的用户,如果它是正确的在屏幕的中心? 而setLocationRelativeTo也可以使用,但你需要在适当的时候调用它 。



Answer 3:

使用JDialog.setLocation() ,用于移动JDialog期望在屏幕上点

import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

public class JDialogAtPoint {

    private JFrame frame = new JFrame();
    private JPanel panel = new JPanel();
    private JDialog dialog;
    private Point location;

    public JDialogAtPoint() {
        createGrid();
        createDialog();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.setLocation(100, 100);
        frame.pack();
        frame.setVisible(true);
    }

    private void createGrid() {
        panel.setLayout(new GridLayout(3, 3, 4, 4));
        int l = 0;
        int row = 3;
        int col = 3;
        JButton buttons[][] = new JButton[row][col];
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                buttons[i][j] = new JButton("");
                buttons[i][j].putClientProperty("column", i + 1);
                buttons[i][j].putClientProperty("row", j + 1);
                buttons[i][j].setAction(updateCol());
                panel.add(buttons[i][j]);
                l++;
            }
        }
    }

    private void createDialog() {
        dialog = new JDialog();
        dialog.setAlwaysOnTop(true);
        dialog.setModal(true);
        dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
        JPanel pane = (JPanel) dialog.getContentPane();
        pane.setBorder(new EmptyBorder(20, 20, 20, 20));
        dialog.pack();
    }

    public Action updateCol() {
        return new AbstractAction("Display JDialog at Point") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                JButton btn = (JButton) e.getSource();
                System.out.println("Locations coordinates" + btn.getLocation());
                System.out.println("clicked column "
                        + btn.getClientProperty("column")
                        + ", row " + btn.getClientProperty("row"));
                if (!dialog.isVisible()) {
                    showingDialog(btn.getLocationOnScreen());
                }
            }
        };
    }

    private void showingDialog(final Point loc) {
        dialog.setVisible(false);
        location = loc;
        int x = location.x;
        int y = location.y;
        dialog.setLocation(x, y);
        Runnable doRun = new Runnable() {

            @Override
            public void run() {//dialog.setLocationRelativeTo(frame);
                dialog.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(doRun);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JDialogAtPoint cf = new JDialogAtPoint();
            }
        });
    }
}


Answer 4:

所有3名应答者的帮助下,我想出了代码,这似乎正是我需要的。 首先, JFrame得到了摆在当前屏幕的中间,然后JDialog相应。

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
for (int j = 0; j < gs.length; j++) {
    GraphicsDevice gd = gs[j];
    GraphicsConfiguration[] gc = gd.getConfigurations();
    for (int i=0; i < gc.length; i++) {
        Rectangle gcBounds = gc[i].getBounds();

        Point loc = mainWindow.getLocationOnScreen();
        if (gcBounds.contains(loc)) {
            System.out.println("at " + j + " screen");

            int x = gcBounds.x + (gcBounds.width - mainWindow.getWidth()) / 2;
            int y = gcBounds.y + (gcBounds.height - mainWindow.getHeight()) / 2;
            mainWindow.setLocation(x, y);

            int x = loc.getX() + (mainWindow.getWidth() - getWidth()) / 2;
            int y = loc.getY() + (mainWindow.getHeight() - getHeight()) / 2;
            setLocation(x, y);

            break;
        }
    }
}


文章来源: Optimal location for a modal JDialog to avoid stuck