模态JDialog的最佳位置,以避免卡住

时间:2013-01-11 07:48:39

标签: java swing jframe jdialog

我的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,则可能看起来用户将应用程序框架移动到屏幕之外,并且相对定位的对话框对用户不可见。因为它是模态的,所以游戏会被卡住。

考虑到上述两个问题,最佳解决方案是什么?

4 个答案:

答案 0 :(得分:4)

我认为,最好将对话框置于当前屏幕中间,如here所述。

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,但您需要invoke it at the right time

答案 1 :(得分:4)

这让我想起了我在StackOverflow上使用Window.setLocationByPlatform(true)的一个非常喜欢的帖子。

How to best position Swing GUIs

编辑1:

您可以在FocusListenerJDialog方法中添加focusGained(...)setLocationRelativeTo(null)和{{1}可以使用JFrame无论他们以前在哪里,他们都会到达屏幕的中心。

JDialog

编辑2:

我在这里和那里搜索了一下,在我看来,实际上你的应用程序在第一个实例上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 */ } }); } } 实际上将确定它是GraphicsConfiguration。虽然当我漫游API时,只有一个getter方法用于上述Monitor Screen东西,并且没有相同的setter方法(仍然可以通过任何顶级窗口的构造函数指定一个,即JFrame(...) / JDialog(...))。

现在,您可以使用此代码来占据您的头部,该代码可用于确定您想要设置的适当位置,在我看来,您可能必须使用GraphicsConfiguration方法来满足条件2你的问题看一下附加的代码,虽然不需要创建focusGain(),只是看看如何获​​取屏幕的坐标(可以在new JFrame/JDialog方法中添加以确定整个应用程序的位置。)

focusGain()

编辑3:

尝试改变这一点:

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();
    }
}

只是:

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

为了测试上述内容,我按原样使用了setLocationRelativeTo(mainWindow); 类,但我已将更改添加到FrameFocus方法中,如此修改后的CustomDialog类所示。

CustomDialog

答案 2 :(得分:4)

使用JDialog.setLocation()在期望的Point on the screen

上移动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();
            }
        });
    }
}

答案 3 :(得分:2)

在所有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;
        }
    }
}