简体   繁体   English

Swing GUI不等待用户输入

[英]Swing GUI doesn't wait for user input

I am new to Swing, and I have created a simple GUI class with a button and text field. 我是Swing的新手,我创建了一个带有按钮和文本字段的简单GUI类。 There is a method in this class, String createAndShowUI() , and I want it to return the text of the text field. 这个类中有一个方法, String createAndShowUI() ,我希望它返回文本字段的文本。 I have created another main class that calls this method and expects the text of text field to be returned. 我创建了另一个调用此方法的主类,并期望返回文本字段的文本。 However my problem is that this method doesn't wait for the user to enter the text field and click on the button; 但是我的问题是这个方法不等待用户输入文本字段并单击按钮; it returns as soon as GUI is called. 一旦调用GUI就会返回。 I want it to wait for the button click. 我希望它等待按钮点击。

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

public class TestSwing  extends JPanel implements ActionListener {

    JButton submit;
    JTextField t1;
    String msg = "No Msg";

    public TestSwing() {
        submit = new JButton("Submit");
        t1 = new JTextField(10);
        submit.addActionListener(this);
        setLayout(new FlowLayout());
        add(t1);
        add(submit); 
    }

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == submit) {
            msg = t1.getText(); 
        }
    }

    public String createAndShowUI() {
        JFrame f = new JFrame("Sample frame");
        f.add(new TestSwing());
        f.pack();
        f.setVisible(true);
        return msg;
    }

}

//Main.java
public class Main {

    public static void main(String[] arg) {
        System.out.println(new TestSwing().createAndShowUI());
    }

}

You're getting your msg String before the user has had a chance to change it, and the reason is that you're thinking in a procedural kind of way, and this won't work for Swing. 你在用户有机会改变它之前得到你的msg字符串,原因是你正在以程序的方式思考,这对Swing不起作用。 In fact you've got to change your whole way of thinking in order to code event-driven programming like Swing. 事实上,你必须改变你的整个思维方式,以便编写像Swing这样的事件驱动编程。 So msg isn't shown after a class is created but only after the user has initiated an event -- here the press of a button which prompts an ActionListener to call its actionPerformed method. 因此,在创建类之后不会显示msg,但仅在用户启动事件之后才会显示 - 这里按下一个按钮,提示ActionListener调用其actionPerformed方法。 For example (changes highlighted with the //!! comment): 例如(使用//!!注释突出显示的更改):

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

// Significant changes noted with the //!! comment
public class TestSwing extends JPanel implements ActionListener {
   JButton submit;
   JTextField t1;
   String msg = "No Msg";

   public TestSwing() {
      submit = new JButton("Submit");
      t1 = new JTextField(10);
      submit.addActionListener(this);
      setLayout(new FlowLayout());
      add(t1);
      add(submit);

   }

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == submit) {
         msg = t1.getText();

         //!!  Display msg only **after** the user has pressed enter.
         System.out.println(msg); 
      }

   }

   public void createAndShowUI() { //!! Don't have method return anything
      JFrame f = new JFrame("Sample frame");
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //!! close GUI
      f.add(new TestSwing());
      f.pack();
      f.setLocationRelativeTo(null); // center GUI
      f.setVisible(true);
      //!! return msg; // get rid of
   }

   public static void main(String[] arg) {
      new TestSwing().createAndShowUI();
   }

}

Edit 2 编辑2
You mentioned that you wanted to get the msg text into the main method, or somewhere else other than in the TestSwing class. 您提到要将msg文本放入main方法,或者除了TestSwing类之外的其他位置。 One way is to use the Observer Design Pattern where you allow other classes to "observe" the TestSwing class -- which is the "observable". 一种方法是使用Observer设计模式,允许其他类“观察”TestSwing类 - 这是“可观察的”。 There are several ways this can be done, including: 有几种方法可以做到,包括:

  • Giving TestSwing a public void method called something like addActionListener(ActionListener al) , and in the method body add the listener passed in to the submit button. 为TestSwing提供一个名为addActionListener(ActionListener al)的公共void方法,并在方法体中添加传入提交按钮的侦听器。 That way outside classes can add an ActionListener directly to that button and respond to its events. 这样,外部类可以将ActionListener直接添加到该按钮并响应其事件。
  • Give TestSwing a way to accept ChangeListeners and notify them if the button has been pressed in its ActionListener, or 为TestSwing提供一种接受ChangeListeners的方法,并在ActionListener中按下按钮时通知它们,或者
  • Give TestSwing the ability to use PropertyChangeListeners by giving it a PropertyChangeSupport variable and public add and remove PropertyChangelistener methods. 通过为其提供PropertyChangeSupport变量并公开添加和删除PropertyChangelistener方法,为TestSwing提供使用PropertyChangeListeners的能力。 This is like the ChangeListener idea but since a PCL can listen for multiple state changes, it gives more flexibility and power, and this is currently what I prefer. 这就像ChangeListener的想法一样,但由于PCL可以监听多个状态变化,因此它提供了更大的灵活性和功能,这正是我所喜欢的。 For example: 例如:

Latest version of TestSwing: 最新版本的TestSwing:

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

@SuppressWarnings("serial")
public class TestSwing extends JPanel {
   public static final String MESSAGE = "Message";
   private JButton submit;
   private JTextField mainTextField;
   private String message = "No Msg";

   private PropertyChangeSupport propSupport = new PropertyChangeSupport(this);

   public TestSwing() {
      submit = new JButton("Submit");
      mainTextField = new JTextField(10);
      submit.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            submitActionPerformed(e);
         }
      });
      setLayout(new FlowLayout());
      add(mainTextField);
      add(submit);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      propSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      propSupport.removePropertyChangeListener(listener);
   }

   public void setMessage(String newValue) {
      String oldValue = message;
      this.message = newValue;
      PropertyChangeEvent event = new PropertyChangeEvent(this, MESSAGE, oldValue, newValue);
      propSupport.firePropertyChange(event);
   }

   private void submitActionPerformed(ActionEvent e) {
      if (e.getSource() == submit) {
         setMessage(mainTextField.getText());
      }
   }

   public static void createAndShowUI() { 
      TestSwing testSwing = new TestSwing();
      testSwing.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(TestSwing.MESSAGE)) {
               System.out.println("message = " + evt.getNewValue());
            }
         }
      });

      JFrame f = new JFrame("Sample frame");
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      f.add(testSwing);
      f.pack();
      f.setLocationRelativeTo(null); 
      f.setVisible(true);
   }

   public static void main(String[] arg) {
      createAndShowUI();
   }

}

Please read up on the Observer Design Pattern for more information. 请阅读观察器设计模式以获取更多信息。

Swing is event-driven. Swing是事件驱动的。 Wherever you want to use msg should be called as a consequence of the action listener being called. 不管你想要使用 msg ,应称为被称为动作监听的结果

Alternatively you can use one of the ready-made solutions in JOptionPane , for example 或者,您可以使用JOptionPane一个现成解决方案

String userInput = JOptionPane.showInputDialog("Please enter ...");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM