JDialog不会更新新输入

时间:2013-03-26 22:10:58

标签: java swing jtextfield jdialog

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

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

}                             

2 个答案:

答案 0 :(得分:2)

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

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

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

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

好的,我将展示一个处理几种常见情况的例子:

  1. 每次对话框变为可见时刷新组件数据。
  2. 每次对话框变为可见时清除选择。
  3. 布尔标志,如果按下确定,则为真,或者双击等效操作。
  4. 如果按下取消或用户手动关闭对话框,则标记为false。
  5. 这个成语对我来说在许多相当大的应用程序中都运行良好。我希望它对你有所帮助。

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

答案 1 :(得分:1)

即使你创建了一个新的JDialog,你每次都使用相同的JPanel,jpDialog,它拥有原始的JTextFields。创建一个新的东西,包括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();
      }
   }

}