Как мне получить пользовательский ввод из JTextField?

#java #swing #jtextfield

#java #swing #jtextfield

Вопрос:

Я пытаюсь создать очень простую форму, предназначенную для ввода пользовательского ввода в JTextField и отображения того же ввода через всплывающее диалоговое окно.

Я могу жестко запрограммировать JTextField, чтобы иметь заданный номер, используя setText() . Если я это сделаю, моя программа будет работать безупречно.

Однако, когда я оставляю поле пустым и пытаюсь getText(), чтобы отобразить текст во всплывающем диалоговом окне, я либо получаю пустой всплывающий фрейм, либо получаю исключение «пустая строка» (я пытаюсь разобрать строку на Double.)

package buttontest; import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import javax.swing.*; import java.awt.event.ActionEvent; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; public class ButtonTest { public static void main(String[] args) { ButtonFrame frame = new ButtonFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } class ButtonFrame extends JFrame { @SuppressWarnings("LeakingThisInConstructor") public ButtonFrame() { setTitle("SunStream Loan Calculator v2.0"); setSize(900,900); ButtonPanel panel = new ButtonPanel(); panel.add(new JLabel("Enter your loan amount:")); loanAmt = new JTextField(40); panel.add(loanAmt); add(panel,BorderLayout.CENTER); } public JTextField loanAmt; class ButtonPanel extends JPanel implements ActionListener { private Component frame; public ButtonPanel() { final JButton b2 = new JButton("Calculate"); add(b2, BorderLayout.SOUTH); b2.setActionCommand("calculate"); b2.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { ButtonFrame bf = new ButtonFrame(); if("calculate".equals(e.getActionCommand())) { JOptionPane.showMessageDialog(frame, bf.loanAmt.getText()); } } }); } @Override public void actionPerformed(ActionEvent ae) { throw new UnsupportedOperationException("Not supported yet."); } } }

Буду признателен за любую помощь. Я изучаю использование KeyListener или KeyEvent, но я не совсем понимаю это достаточно хорошо.

Ответ №1:

Вы создаете «теневую» переменную ButtonFrame внутри ActionListener b2. Да, переменная bf ссылается на объект ButtonFrame, который относится к тому же классу, что и отображаемый объект ButtonFrame, но он ссылается на совершенно отдельный и невизуализируемый объект. Ключом к решению является получение текста из объекта ButtonFrame, который фактически отображается, и его можно получить из внутреннего класса с помощью ButtonFrame.this конструкции:

      b2.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           //!! ButtonFrame bf = new ButtonFrame();
           if ("calculate".equals(e.getActionCommand())) {

              //!! note use of ButtonFrame.this:
              JOptionPane.showMessageDialog(frame, ButtonFrame.this.loanAmt.getText());
           }
        }

     });
  

Затем рассмотрите возможность использования общедоступных методов получения, а не прямого доступа к таким полям, как JTextField. Это снижает вероятность того, что код вызовет побочные эффекты, такие как непреднамеренное изменение свойств объекта JTextField.

Например (изменения, обозначаемые //!! комментарий):

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

public class ButtonTest {
   public static void main(String[] args) {
      ButtonFrame frame = new ButtonFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}

class ButtonFrame extends JFrame {

   private JTextField loanAmt; // !! Make field private

   @SuppressWarnings("LeakingThisInConstructor")
   public ButtonFrame() {

      setTitle("SunStream Loan Calculator v2.0");
      setSize(900, 900);
      ButtonPanel panel = new ButtonPanel();
      panel.add(new JLabel("Enter your loan amount:"));
      loanAmt = new JTextField(40);
      panel.add(loanAmt);

      add(panel, BorderLayout.CENTER);
   }

   // !! create a public method to get JTextField's text
   // !! without exposing the JTextField itself.
   public String getLoanAmtText() {
      return loanAmt.getText();
   }

   class ButtonPanel extends JPanel implements ActionListener {
      private Component frame;

      public ButtonPanel() {

         final JButton b2 = new JButton("Calculate");
         add(b2, BorderLayout.SOUTH);
         b2.setActionCommand("calculate");
         b2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               // !! ButtonFrame bf = new ButtonFrame();
               if ("calculate".equals(e.getActionCommand())) {

                  //!! call public method on ButtonFrame object
                  JOptionPane.showMessageDialog(frame,
                        ButtonFrame.this.getLoanAmtText());
               }
            }

         });

      }

      @Override
      public void actionPerformed(ActionEvent ae) {
         throw new UnsupportedOperationException("Not supported yet.");
      }

   }
}
  

Комментарии:

1. Это было ТАК полезно! Большое вам спасибо, что нашли время взглянуть на это!

2. Добро пожаловать! Удачи в этом проекте и в ваших исследованиях Java!

3. @Phoenix: ключевым моментом здесь является то, что все дело в ссылках . Вам нужна ссылка на фактический отображаемый объект, а не на какой-либо объект ButtonFrame. Чем больше вы понимаете ссылки и ссылочные переменные, тем лучше вы будете понимать Java и OOPs.

4. В этом так много смысла. Я бился головой о стену, пытаясь понять это. Поэтому при создании 3 новых текстовых полей мне нужно будет ссылаться на каждый отображаемый объект (ButtonFrame1.this — ButtonFrame2.this — ButtonFrame3.this ), чтобы что-то с ними делать. Я пытаюсь создать простой калькулятор амортизации

5. @Phoenix: Нет, я думаю, что нет. Если у вас есть три JTextFields и все они хранятся в одном классе, ButtonFrame , тогда вам понадобится только ссылка на один объект ButtonFrame , ButtonFrame.this . Затем вам понадобятся либо три метода доступа для получения текста из трех JTextFields, либо один метод доступа, который принимает параметр, который каким-то образом указывает методу, какой текст JTextField должен возвращаться.

Ответ №2:

Единственный способ получить доступ к вашему loanAmt это через саму ButtonPanel. Потому что вы добавляете loanAmt к этой кнопке, верно?

Итак, если вы хотите получить доступ к loanAmt. Вы должны получить все компоненты на этой панели кнопок. Это мой псевдокод, как получить доступ к вашему loanAmt из класса ButtonPanel.

 b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        ButtonFrame bf = new ButtonFrame();
        if("calculate".equals(e.getActionCommand())) {
            // Get all component 
            java.awt.Component[] componentList = this.getComponents();
            JTextField txtField;
            String value;
            for (int i = 0; i < componentList.length; i  ) {
                if (componentList[i].getClass().getName().equals("javax.swing.JTextField")) {
                    txtField = (JTextField) componentList[i];
                    value = textField.getText();
                }
            }
            if (value != null) JOptionPane.showMessageDialog(frame, value);
        }
    }
});
  

Комментарии:

1. А что, если JTextField вложен в JPanels, которые вложены в другие JPanels? А что, если макет графического интерфейса позже изменится? А что, если графический интерфейс имеет несколько JTextFields? Нет, это очень хрупкий способ извлечения информации, который легко сломается и плохо масштабируется. Лучше использовать общедоступные методы доступа. Еще лучшие, но более продвинутые способы описаны здесь и здесь .

2. @HovercraftFullOfEels да, это кошмар, если JTextField находится внутри вложенной панели. Я согласен с вашим решением 🙂

3. Я отредактировал ваш пост (добавил пробел), чтобы отменить голосование. Я рекомендую вам прочитать ссылки в моем комментарии выше, поскольку они просто потрясающие и действительно открыли мне глаза. Они поместили мои рекомендации в мой ответ на стыд.