我正在构建我的第一个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();
}
});
}
}
答案 0 :(得分:2)
调用dispose
时,会释放对话框的资源。您必须完全从头开始分配一个新的 - 或者 - 更好 - 调用setVisible(false)
来关闭对话框,然后再次需要setVisible(true)
。
第二种方法更好,因为复杂的对话框可能需要花费很长时间才能构建。对于用户来说,立即弹出对话框是一种更好的体验。我的应用程序在应用程序启动期间构建复杂的对话框 - 在任何用户界面可见之前,而启动仍然显示 - 因此。
您可以覆盖setVisible
以确保每次显示对话框时都会重新初始化对话框。
如果你仍然想在每次需要对话时从头开始构建,然后在用户做出选择时dispose
,那么最好的方法是继承JDialog
。您的代码失败了,因为它在封闭类中分配了对话框的某些部分(例如布局),然后在调用dispose()
之后假设这些部分仍然存在。这是个大问题。如果你继承JDialog
,那么你几乎不可能犯这样的错误。对话框的所有部分都将在构造函数中分配,并在子类本身内引用。对话框为displosed
后,不存在对其字段/成员的引用。
好的,我将展示一个处理几种常见情况的例子:
这个成语对我来说在许多相当大的应用程序中都运行良好。我希望它对你有所帮助。
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();
}
}
}