2013-03-26 105 views
2

我正在建立我的第一个GUI,到目前为止一切工作正常,除了一个JDialog故障。它在第一次使用时接受相应的名称和过程列表。但是当我把它拉回来输入新的输入时,它仍然没有反应。我不认为这是一个线程问题,因为我在整个源代码中使用了几个System.out.println (SwingUtilities.isEventDispatchThread());语句来测试代码。这是可能引发问题的代码的一部分。JDialog没有更新为新的输入

package testme; 




import java.awt.BorderLayout; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.*; 

public class Test {  
    JDialog dialog; 
    JButton horseList, ok, clear; 
    JPanel jpDialog = new JPanel(); 
    JPanel buttonPanel = new JPanel(); 
    GridBagLayout gbLayout = new GridBagLayout(); 
    BorderLayout borderLayout = new BorderLayout(); 
    GridBagConstraints gbc = new GridBagConstraints(); 
    int fnh = 8; 
    JTextField[] jtxt = new JTextField[fnh]; 
    int[] hNum = new int[fnh]; 
    int[] hVal = new int[fnh]; 
    String[] hNam = new String[fnh]; 
    JFrame jfr = new JFrame(); 

    public Test() { 

     jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     jfr.setTitle("My Alladin Lamp"); 
     jfr.setSize(200, 80); 
     jfr.setVisible(true); 
     jfr.setLayout(borderLayout); 


     horseList = new JButton("Enter Horse Names"); 
     jfr.add(horseList, BorderLayout.CENTER); 
     horseList.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) {  
      dialog = new JDialog(jfr, "Enter Horse Names", true); 
      dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
      dialog.setSize(260, 400);      
      jpDialog.setLayout(gbLayout);   
      JLabel label; 
      String str; 
      for(int i = 0; i < fnh; i++) 
      {     
       gbc.gridx = 0; 
       gbc.gridy = i;   
       str = new Integer(i+1) + ".";     
       label = new JLabel(str); 
       jpDialog.add(label, gbc);   

       gbc.gridx = 1; 
       gbc.gridy = i; 
       gbc.ipady = 4; 
       gbc.insets = new Insets(4,0,0,0); 
       jtxt[i] = new JTextField(15); 
       jpDialog.add(jtxt[i], gbc);    
      } 
      buttonPanel = new JPanel();   
      ok = new JButton("OK");   
      ok.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) {  
       for(int i = 0; i < fnh; i++) {    
        hNam[i] = jtxt[i].getText();         
       } 


       dialog.dispose(); 
      } 
      });   
      buttonPanel.add(ok); 

      clear = new JButton ("CLEAR");   
      clear.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        for(int i = 0; i < fnh; i++)    
        if (!"".equals(jtxt[i].getText())) 
        jtxt[i].setText("");   
        } 
      });   

      buttonPanel.add(clear);  
      JScrollPane jscr = new JScrollPane(jpDialog); 
      dialog.add(jscr, BorderLayout.CENTER); 
      dialog.add(buttonPanel, BorderLayout.SOUTH); 
      dialog.setVisible(true);  
      } 
     }); 

    } 



// ------------------------------------------------------------------------- 


    public static void main(String args[]) {     
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() 
      { 
       Test test = new Test(); 
      } 
     }); 
    } 

}        
+1

如果基因的答案不能解决你的问题,然后再考虑创建和发布的[SSCCE(HTTP:// SSCCE。org),这是一个小型的可编译和可运行的程序,我们可以不加改变地运行,并为我们展示了您的问题。 – 2013-03-26 22:25:45

回答

2

当调用dispose时,对话框的资源被释放。您必须从零开始完全分配一个新的,或者 - 更好 - 请拨打setVisible(false)关闭对话框,然后在您再次需要时拨打setVisible(true)

第二种方法更好,因为复杂的对话框可能需要很长时间才能构建。让用户立即弹出对话框是一种更好的体验。我的应用程序在应用程序启动过程中构建了复杂的对话框 - 在任何用户界面显示之前,仍然显示启动画面之前 - 出于此原因。

您可以覆盖setVisible以确保每次显示对话框都会重新初始化。

如果你仍然想从头开始构建每次需要对话框,然后dispose当用户做出选择,那么最好的方法是去JDialog的子类。你的代码失败了,因为它正在分配封闭类中的对话框的某些部分(例如布局),然后假定在调用dispose()之后这些部分仍然存在。这是个大问题。如果你的子类JDialog,你几乎没有办法做出这样的错误。对话框的所有部分都将在构造函数中分配并在子类本身内引用。在对话框displosed之后,不存在对其字段/成员的引用。

好吧,我将表明,处理一些常见的情况为例:

  1. 刷新组件每一个对话框变为可见时间数据。
  2. 每当对话框变为可见时清除选择。
  3. 布尔标志如果按下OK或者双击等效操作,则为true。
  4. 如果按下取消或用户手动关闭对话框,则标志为false。

这个成语在很多相当大的应用程序上运行良好。我希望这对你有帮助。

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class Test extends JFrame { 

    // The dialog we'll create and use repeatedly. 
    TestDialog testDialog; 

    // Some words to fill a list. 
    String [] words = ("Four score and seven years ago our fathers brought " 
      + "forth on this continent a new nation conceived in liberty and " 
      + "dedicated to the proposition that all men are created equal") 
      .split("\\s+"); 

    // Start index of words to load next time dialog is shown. 
    int wordIndex = 0; 

    // A place we'll show what was done by the dialog. 
    JLabel msg; 

    public Test() { 

     setSize(800, 600); 
     setLocationRelativeTo(null); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     // Add the "show dialog" button. 
     JButton showDialog = new JButton("Press to show the dialog"); 
     add(showDialog, BorderLayout.NORTH); 

     // Add the "dialog result" label. 
     msg = new JLabel(" Dialog Result: --"); 
     add(msg, BorderLayout.CENTER); 

     showDialog.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       // Create the dialog lazily. 
       if (testDialog == null) { 
        testDialog = new TestDialog(Test.this); 
       } 
       // Load fresh data in the dialog prior to showing it. 
       // Here it's just an array of words into the dialog. 
       String [] newWords = new String[5]; 
       for (int i = 0; i < newWords.length; i++) { 
        newWords[i] = words[wordIndex]; 
        wordIndex = (wordIndex + 1) % words.length; 
       } 
       testDialog.initialize(newWords); 

       // Show the dialog and block until user dismisses it. 
       testDialog.setVisible(true); 

       // Handle the result. Here we just post a message. 
       if (testDialog.getOkClicked()) { 
        msg.setText("Ok, we have: " + testDialog.getSelectedString()); 
       } 
       else { 
        msg.setText("Cancelled!"); 
       } 
      } 
     });   
    } 

    public static void main(String[] args) { 
     // Don't forget Swing code must run in the UI thread, so 
     // must invoke setVisible rather than just calling it. 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new Test().setVisible(true); 
      } 
     }); 
    } 
} 

// A test dialog with some common UI idioms. Subclass JDialog so 
// that all dialog data is encapsulated. Nice and clean. 
class TestDialog extends JDialog { 

    // A list of words that can be double-clicked to return a result. 
    private final JList<String> list; 

    // A design pattern that works well for all modal dialogs: 
    // Boolean flag that's True if OK was clicked, list double-clicked, etc. 
    // False if the dialog was cancelled or closed with no action. 
    boolean okClicked; 

    public TestDialog(JFrame owner) { 

     super(owner, true); // true => modal! 

     JPanel content = new JPanel(new GridBagLayout()); 

     // Initialize all dialog components and set listeners. 

     // Hierarchy listener is a way to detect actual visibility changes. 
     addHierarchyListener(new HierarchyListener() { 
      @Override 
      public void hierarchyChanged(HierarchyEvent e) { 
       // Reset the ok clicked flag every time we become visible. 
       // We could also do this by overriding setVisible, but this is cleaner. 
       // Can also do other state settings like clearing selections. 
       if (isVisible()) { 
        okClicked = false; 
        list.clearSelection(); 
       } 
      } 
     }); 

     // Set up child components. 
     // The usual Java layout fiddling. Nothing special here. 
     // Add the list first at position (0,0) spanning 2 columns. 
     GridBagConstraints constraint = new GridBagConstraints(); 
     constraint.fill = GridBagConstraints.HORIZONTAL; 
     constraint.gridwidth = 2; 
     list = new JList<>(new String[]{}); 
     list.addMouseListener(new MouseAdapter() { 

      @Override 
      public void mouseClicked(MouseEvent e) { 

       // Treat double click on list as select+OK press. 
       if (e.getClickCount() == 2) { 
        okClicked = true; 
        setVisible(false); 
       } 
      } 
     }); 
     content.add(list, constraint); 

     // Add Cancel button below list and in left column. 
     constraint.gridwidth = 1; 
     constraint.fill = GridBagConstraints.NONE; 
     constraint.gridy = 1; 
     JButton cancel = new JButton("Cancel"); 
     cancel.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 

       // OK not clicked here! Let flag alone. 
       setVisible(false); 
      } 
     }); 
     content.add(cancel, constraint); 

     // Add OK button below list and in right column. 
     constraint.gridx = 1; 
     JButton ok = new JButton("OK"); 
     ok.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       okClicked = true; 
       setVisible(false); 
      } 
     }); 
     content.add(ok, constraint); 

     // Replace default content pane with our JPanel. 
     setContentPane(content); 
    } 

    // Fill the list in the dialog with fresh values. 
    public void initialize(final String [] vals) { 
     list.setModel(new AbstractListModel<String>() { 
      @Override public int getSize() { return vals.length; } 
      @Override public String getElementAt(int index) { return vals[index]; } 
     }); 
     pack(); // Resize to fit contents. 
     setLocationRelativeTo(getOwner()); // Position in middle of parent. 
    } 

    public boolean getOkClicked() { 
     return okClicked; 
    } 

    public String getSelectedString() { 
     String val = list.getSelectedValue(); 
     return (val == null) ? "[none]" : val; 
    } 
} 
+0

感谢您的回应基因。我正在处理这个问题,很快就会回复你。请你留意这篇文章,好吗? :) – user2143292 2013-03-26 22:59:52

+0

再次嗨。我添加了语句“dialog = new JDialog(jfr,”Enter Horse Names“,true);”作为马列表按钮的动作监听器的第一行,以便每次单击该按钮时创建一个新的JDialog对象。它没有工作。尽管我使用了dialog.dispose()语句,但我之前在文本字段中输入的马名称仍然存在。对话框中的OK和Clear按钮也不会响应。在使用dispose方法之前,我使用了setVisible方法,这就是问题的起因。 – user2143292 2013-03-26 23:20:24

+0

同样,第一次使用时对话框工作正常。当它被拉回来时,这种不正当行为就会发生。 – user2143292 2013-03-26 23:22:49

1

即使你创建一个新的JDialog,你每次都使用相同的JPanel,jpDialog,一个持有原始JTextField的。创建一个包括JPanel在内的新东西。

 dialog = new JDialog(jfr, "Enter Horse Names", true); 
     dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     dialog.setSize(260, 400);   

     jpDialog = new JPanel(); // !! added !! *********** 

     jpDialog.setLayout(gbLayout);   
     JLabel label; 
     String str; 

虽然我自己,但我只保留一个对话框和面板,并在需要时清除它,而不是继续重新创建GUI。

喜欢的东西:

import java.awt.BorderLayout; 
import java.awt.Dialog.ModalityType; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.GridLayout; 
import java.awt.Insets; 
import java.awt.Window; 
import java.awt.event.ActionEvent; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.awt.event.WindowListener; 

import javax.swing.*; 

public class Test2 { 
    private static final int HORSE_NAMES_FIELD_COUNT = 10; 
    private JPanel mainPanel = new JPanel(); 
    private EnterHorseNames enterHorsesNames = new EnterHorseNames(
     HORSE_NAMES_FIELD_COUNT); 
    private JDialog enterHorseNamesDialog = null; 

    public Test2() { 
     mainPanel.add(new JButton(new EnterHorsesAction("Enter Horse Names"))); 
    } 

    public JComponent getMainComponent() { 
     return mainPanel; 
    } 

    private class EnterHorsesAction extends AbstractAction { 

     public EnterHorsesAction(String text) { 
     super(text); 
     } 

     @Override 
     public void actionPerformed(ActionEvent evt) { 
     if (enterHorseNamesDialog == null) { 
      Window mainWindow = SwingUtilities.getWindowAncestor(mainPanel); 
      enterHorseNamesDialog = new JDialog(mainWindow, 
        "Enter Horses Name", ModalityType.APPLICATION_MODAL); 
      enterHorseNamesDialog.getContentPane().add(enterHorsesNames.getMainComponent()); 
      enterHorseNamesDialog.pack(); 
      enterHorseNamesDialog.setLocationRelativeTo(mainWindow); 

     } 

     enterHorseNamesDialog.setVisible(true); 

     System.out.println("Horse Names:"); 
     for (int row = 0; row < HORSE_NAMES_FIELD_COUNT; row++) { 
      System.out.printf("%2d: %s%n", row + 1, enterHorsesNames.getTextFieldText(row)); 
     } 

     // clear fields 
     enterHorsesNames.clearFields(); 

     } 

    } 

    private static void createAndShowGui() { 
     Test2 test2 = new Test2(); 

     JFrame frame = new JFrame("Test2"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(test2.getMainComponent()); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

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

class EnterHorseNames { 
    private static final int FIELD_COLS = 18; 
    private JPanel mainPanel = new JPanel(); 
    private JTextField[] textFields; 

    public EnterHorseNames(int fieldCount) { 
     textFields = new JTextField[fieldCount]; 
     JPanel centralPanel = new JPanel(new GridBagLayout()); 
     for (int i = 0; i < textFields.length; i++) { 
     textFields[i] = new JTextField(FIELD_COLS); 
     addField(centralPanel, textFields[i], i); 
     } 

     JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0)); 
     btnPanel.add(new JButton(new OkAction("OK"))); 
     btnPanel.add(new JButton(new ClearAction("Clear"))); 

     mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 
     mainPanel.setLayout(new BorderLayout(5, 5)); 
     mainPanel.add(centralPanel, BorderLayout.CENTER); 
     mainPanel.add(btnPanel, BorderLayout.PAGE_END); 
    } 

    public void clearFields() { 
     for (int i = 0; i < textFields.length; i++) { 
     textFields[i].setText(""); 
     } 
    } 

    public String getTextFieldText(int row) { 
     if (row < 0 || row >= textFields.length) { 
     throw new ArrayIndexOutOfBoundsException(row); 
     } 

     return textFields[row].getText(); 
    } 

    private void addField(JPanel container, JTextField textField, int row) { 
     GridBagConstraints gbc = new GridBagConstraints(0, row, 1, 1, 1.0, 1.0, 
      GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 
        5, 10), 0, 0); 
     container.add(new JLabel(String.valueOf(row + 1)), gbc); 

     gbc.gridx = 1; 
     gbc.anchor = GridBagConstraints.EAST; 
     gbc.fill = GridBagConstraints.HORIZONTAL; 
     gbc.insets = new Insets(5, 10, 5, 5); 
     container.add(textField, gbc); 
    } 

    public JComponent getMainComponent() { 
     return mainPanel; 
    } 

    private class OkAction extends AbstractAction { 
     public OkAction(String text) { 
     super(text); 
     } 

     @Override 
     public void actionPerformed(ActionEvent evt) { 
     Window win = SwingUtilities.getWindowAncestor(mainPanel); 
     win.setVisible(false); 
     } 
    } 

    private class ClearAction extends AbstractAction { 
     public ClearAction(String text) { 
     super(text); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
     clearFields(); 
     } 
    } 

} 
+0

嘿哈弗,我同意重新创建一个GUI。在关闭框之前清除字段用于之前,但没有结果。我还没有测试过,但希望你的最后一个建议能为我提供解决方案。会及时向大家发布。无法感谢您的关注。最好的祝福。 – user2143292 2013-03-27 01:27:30

+0

@ user2143292:请参阅编辑为例。 – 2013-03-27 02:17:37

+0

宾果!问题解决了!解决方案非常简单,在您的一条评论中提出。每当它被调用时,它就会让我为对话框的--- ALL ---组件生成新的对象。再次感谢你们在这件事上的注意。希望在我面临下一期问题时再次引起您的注意。马科斯安东尼奥 – user2143292 2013-03-27 03:40:54