2013-01-11 21 views
3

我的Swing應用程序必須向用戶顯示模態對話框。對不起,不發佈SSCCE。避免卡住的模態JDialog的最佳位置

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,它可能出現的用戶移動的應用程序框架的屏幕的外側和對話框被相對位於將不可見給用戶。而且因爲它是模態的,所以遊戲會卡住。

什麼是考慮上述兩種問題的最佳解決方案?

+0

回報一些JComponent的 – mKorbel

+0

@mKorbel點,對不起,不明白這一點 –

+0

[見這裏](http://stackoverflow.com/a/10283669/714968):-),取消'// dialog.setLocation(x,y);'並且註釋'dialog.setLocationRelativeTo(frame);','dialog.setVisible(true);'必須在'invokeLater'裏面 – mKorbel

回答

4

這讓我想起了我的一個非常喜歡的職位,採用Window.setLocationByPlatform(true),在計算器上。

How to best position Swing GUIs

編輯1:

您可以添加FocusListenerJDialogfocusGained(...)方法,你可以使用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漫遊,僅存在用於所述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 
       */ 
      } 
     }); 
    } 
} 
+1

+1我的最愛,我喜歡截圖:) –

+0

我將JFrame移動到第二個屏幕,但JDialog出現在第一個屏幕上。它沒有解決問題#1。 –

+0

@NikolayKuznetsov:如果你爲你的'JDialog'添加一個FocusListener,並執行我在'focusGained()'方法編輯中提到的步驟?我希望這個解決方法可以適用於這兩種情況。 –

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

'd.setLocationRelativeTo(null)'' ?這是鏈接下主要答案。 –

+0

也可以使用,但也請參閱「怪癖」下的鏈接。 – h22

+1

所有使用'setLocationRelativeTo'的IMO都沒有怪癖,只能在*正確的時間調用* [見這裏](http://stackoverflow.com/a/5351620/1133011)。 –

4

使用JDialog.setLocation()爲所需Point on the screen

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

我對帖子+1,但我必須等待10小時這個:( –

+1

大多數天在這裏我有同樣的問題:-) – mKorbel

+0

+1和良好的代碼,我不明白它是如何解決問題#2。 –

2

移動JDialog與所有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; 
     } 
    } 
} 
+0

在本代碼中再次看到,'JFrame'出現的'First Monitor Screen'將成爲'GraphicsConfiguration'的一部分,因此迭代第二個值將是沒有意義的。儘管如果你把這個'JFrame'帶到另一個屏幕上,它仍然會用這個去到第一個屏幕。所以在這種情況下,'focusGained()'方法可以與'setLocationRelativeTo(null)'一起工作。雖然我會在某個時候嘗試這些代碼,但當我回到家時,我可以鞏固這種方法的優點。 –

+0

@GagandeepBali,你是對的。這是我的原始版本,在測試過程中得到了極大的更新。 –

+0

@NikolayKuznelsov:Ahha,雖然更新後的答案確實有效,但是在某些時候,如果我將mainWindow放到第二臺顯示器的最底部,然後按照我的示例中所示按下'JButton',然後用你的代碼,'JDialog'來到'mainWindow'的這個位置,儘管'mainWindow'本身就是中心。如果你面臨同樣的問題,那麼我已經用** EDIT 3 **更新了我的答案,看一看,這也可以解決這個問題,我猜... ... +1你的努力,在你的答案: - ) –