2

我正在构建我的第一个 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();
            }
        });
    }

}                             
4

2 回答 2

2

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

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

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

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

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

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

这个成语在一些相当大的应用程序上对我来说效果很好。我希望它对你有帮助。

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;
    }
}
于 2013-03-26T22:20:49.320 回答
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();
      }
   }

}
于 2013-03-27T01:12:25.527 回答