模态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)如果将其设置为绝对值,并将app框移动到第二个屏幕,则第一个屏幕上会显示对话框,这很奇怪。

2)如果将相对值设置为JFrame,则可能看起来用户将应用程序框架移动到屏幕之外,并且相对定位的对话框对用户不可见。 因为它是模态的,所以游戏会被卡住。

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

这让我想起了我最喜欢的post,在StackOverflow上使用Window.setLocationByPlatform(true) 。

如何最好地定位Swing GUI

编辑1:

你可以在你的JDialogfocusGained(...)方法中添加一个FocusListener ,你可以对JFrameJDialog使用setLocationRelativeTo(null) ,这样无论它们在哪里,它们都会到达屏幕的中心。 。

 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 thingy并且没有相同的setter方法(仍然可以通过任何顶级窗口的构造函数指定一个,即JFrame(…) / JDialog( ……) )。

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

 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使用了我的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 */ } }); } } 

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

 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但是您需要在正确的时间调用它 。

使用JDialog.setLocation() 在屏幕上的所需Point上移动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位回答者的帮助下,我提出的代码似乎正是我所需要的。 首先, 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; } } }