2013-03-26 47 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