2015-08-07 2 views
0

Я привязываюсь, чтобы сделать программу, которая действует аналогично командной строке Windows или терминалу. В основном это JFrame с JTextArea как output, а JTextField - как input. Это выглядит следующим образом:Сделать программу «пауза» до тех пор, пока пользователь ничего не введет в JTextField

enter image description here

Я хочу, чтобы иметь возможность получить ввод с JTextField всякий раз, когда моя программа вызывает метод, который возвращает строку, что-то вроде:

public static String getInput() { 
    //Wait for user to enter something, then press the enter key 
} 

Я добавил AbstractAction поэтому я могу делать что-то, когда нажата клавиша ввода, но я все еще могу понять, как возвращать входные данные как String всякий раз, когда я вызываю метод.

Action action = new AbstractAction(){ 
    @Override 
    public void actionPerformed(ActionEvent e) { 

     //Clears the JTextField 
     input.setText(""); 

    } 
}; 

я мог бы поставить что-то вроде userInput = input.getText() в public void actionPerformed(), поэтому было бы просто установить переменную к тому, что было введено каждый раз, и использовать userInput всякий раз, когда я хочу, но я хочу, чтобы пользователь имел время, чтобы прочитать, Что на экране, затем попросите программу подождать ответа, вместо того, чтобы просто использовать последнее, что они ввели сразу.

Я пытался использовать userInput переменную и логическую переменную так:

private static String userInput = ""; 
private static boolean enterPressed = false; 

Action action = new AbstractAction(){ 
    @Override 
    public void actionPerformed(ActionEvent e) { 

     userInput = input.getText() 
     enterPressed = true; 
     input.setText(""); 

    } 
}; 

... 

public static String getInput() { 

    enterPressed = false; 
    while(!enterPressed){ 
     //Do Nothing 
    } 
    enterPressed = false; 
    return userInput; 

} 

Когда я назвал output.setText(getInput());, он работал, как я хотел, за исключением того, что while(!enterPressed){} сделал мой процессор работать намного сложнее, чем должен понадобиться. Я почти уверен, что, вероятно, есть намного лучший способ сделать это.

Вот весь мой код прямо сейчас:

public class ConsoleFrame { 

//Objects for Console Frame 
JFrame frame = new JFrame(); 
JTextArea output = new JTextArea(); 
JTextField input = new JTextField(); 
BoxLayout boxLayout = new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS); 
JScrollPane scrollPane = new JScrollPane(output); 
DefaultCaret caret = (DefaultCaret)output.getCaret(); 
Action action = new AbstractAction(){ 
    @Override 
    public void actionPerformed(ActionEvent e) { 

     input.setText(""); 

    } 
}; 
ConsoleFrame(){ 
    input.addActionListener(action); 
    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 
    frame.setLayout(boxLayout); 
    frame.add(scrollPane); 
    frame.add(input); 
    frame.pack(); 
    frame.setVisible(true); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(500, 250); 
    frame.setLocationRelativeTo(null); 
    input.setMaximumSize(new Dimension(Integer.MAX_VALUE, 10)); 
    output.setEditable(false); 
    output.setAutoscrolls(true); 
} 
public static String getInput() { 
    return null; 
} 

} 

Итак, как я мог бы остановить программу, пока пользователь нажмет не вводить каждый раз, когда я называю getInput();?

+2

У вас нет. Swing, как и почти все работы графического интерфейса GUI, управляется событиями, то есть в какой-то момент времени (который вы не можете определить) что-то произойдет, и тогда вы ответите на него. Вы не можете думать о графическом интерфейсе линейным способом, когда код переходит из одной точки в другую. По сути, если вы поместите текстовую область и текстовое поле на экран, программа «приостанавливается», ожидая, когда пользователь что-то сделает. Вам нужно разработать решение по этой функции. – MadProgrammer

+0

Что вы хотите показать в консоли, когда 'getInput' вызван _not_. Если вы ничего не делаете, зачем останавливать программу? Вы просто хотите что-то выводить и ждать ввода, правильно? Вам даже не нужен метод getInput. Вы отключите JTextField при выводе материала и включите его, когда хотите ввода. – Sweeper

+2

* «Я хочу иметь возможность получать входные данные от JTextField всякий раз, когда моя программа вызывает метод, который возвращает строку, что-то вроде:« * - 'JTextField # getText'. Вместо этого вы можете использовать шаблон наблюдателя вместо этого, где при запуске 'ActionListener' вы запускаете другое событие зарегистрированному слушателю (возможно, вашего собственного типа), который сообщает любой заинтересованной стороне, что новое значение доступно ... – MadProgrammer

ответ

2

Я хочу, чтобы иметь возможность получить ввод с JTextField всякий раз, когда моя программа вызывает метод который возвращает строку, что-то вроде:

Я добавил AbstractAction, чтобы я мог делать что-то, когда клавиша ввода нажата , но я все еще мог выяснить, как вернуть ввод как Строка всякий раз, когда я вызываю метод.

public String getInput() { 
    return input.getText(); 
} 

Итак, как я мог остановить программу, пока пользователь нажмет не вводить каждый раз, когда я называю getInput() ;?

У вас нет. Качели, как и большинство работ с рамками пользовательского интерфейса, управляются событиями, то есть что-то происходит, и вы отвечаете на него.

Таким образом, вы должны подумать о том, чтобы использовать какой-либо вид Observer Pattern, где вы используете обратный звонок, чтобы получать уведомления о каком-либо изменении, которое вас интересует, например, ваш ActionListener.

Вместо этого, вы можете предоставить какой-то слушатель, который заинтересованные стороны будут регистрировать с и при изменении поля вы уведомляют их, к примеру ...

import java.util.EventListener; 
import java.util.EventObject; 

public class InputEvent extends EventObject { 

    private final String text; 

    public InputEvent(Object source, String text) { 
     super(source); 
     this.text = text; 
    } 

    public String getText() { 
     return text; 
    } 

} 

public interface InputObsever extends EventListener { 

    public void inputChanged(InputEvent evt); 

} 

Итак, теперь у нас есть наблюдатель, который будет уведомляться, когда когда-либо будет изменен/обновлен вход.

Тогда мы просто нужен способ для ип/зарегистрировать и запустить событие ...

import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 
import javax.swing.event.EventListenerList; 
import javax.swing.text.DefaultCaret; 

public class ConsoleFrame { 

//Objects for Console Frame 
    JFrame frame = new JFrame(); 
    JTextArea output = new JTextArea(); 
    JTextField input = new JTextField(); 
    BoxLayout boxLayout = new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS); 
    JScrollPane scrollPane = new JScrollPane(output); 
    DefaultCaret caret = (DefaultCaret) output.getCaret(); 
    Action action = new AbstractAction() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 

      fireInputChanged(input.getText()); 
      input.selectAll(); 

     } 
    }; 

    private EventListenerList listenerList = new EventListenerList(); 

    ConsoleFrame() { 
     input.addActionListener(action); 
     caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 
     frame.setLayout(boxLayout); 
     frame.add(scrollPane); 
     frame.add(input); 
     frame.pack(); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(500, 250); 
     frame.setLocationRelativeTo(null); 
     input.setMaximumSize(new Dimension(Integer.MAX_VALUE, 10)); 
     output.setEditable(false); 
     output.setAutoscrolls(true); 
    } 

    public String getInput() { 
     return input.getText(); 
    } 

    public void addInputObsever(InputObsever obsever) { 
     listenerList.add(InputObsever.class, obsever); 
    } 

    public void removeInputObsever(InputObsever obsever) { 
     listenerList.remove(InputObsever.class, obsever); 
    } 

    protected void fireInputChanged(String text) { 

     InputObsever[] listeners = listenerList.getListeners(InputObsever.class); 
     if (listeners.length > 0) { 

      InputEvent evt = new InputEvent(this, text); 
      for (InputObsever obsever : listeners) { 
       obsever.inputChanged(evt); 
      } 

     } 

    } 

} 

Теперь, дело здесь в том, когда вы хотите знать, когда текст был введен/изменен, зарегистрировать наблюдателя к экземпляру ConsoleFrame

console.addInputObsever(new InputObsever() { 
    @Override 
    public void inputChanged(InputEvent evt) { 
     // Do what ever you need to do... 
    } 
}); 
+0

Я нашел что-то еще, что, похоже, тоже работает. Используя синхронизированный блок (?), Как описано здесь: http://stackoverflow.com/a/5999146/3291305 Я не уверен, что это хорошая практика, вызвали бы те же проблемы, что и вы упомянули с Thead.sleep? В любом случае, я отмечаю ваш ответ, потому что это самый близкий ответ на то, что я искал. (Не говоря уже о том, что ваши комментарии к другим сообщениям тоже помогли мне) Спасибо! – hhaslam11

4

EDIT: Первая половина снята. Мне было доведено до сведения, что это было ошибочно.

Лучший вариант - заключить вызов того, что вам нужно, чтобы ваш компьютер выполнялся после того, как пользователь вводит текст внутри вашего метода actionPerformed. Поэтому, когда пользователь вводит текст и нажимает, программа автоматически продолжается оттуда.

Action action = new AbstractAction(){ 
@Override 
    public void actionPerformed(ActionEvent e) { 

    userInput = input.getText() 
    enterPressed = true; 
    input.setText(""); 
    //call next method; 

    } 
}; 

Это требует от вас большего количества работы по форматированию, но это может быть полезно в зависимости от вашего проекта. This link - больше информации об этой стратегии.

Надеюсь, это помогло.

+1

Добро пожаловать к прекрасному миру, как полностью ввернуть вашу программу в Swing. Swing - это однопоточная среда, используя «Thread».sleep' в пределах EDT приведет к тому, что пользовательский интерфейс станет отзывчивым и, как правило, считается плохой идеей (на самом деле, вы должны использовать какой-то замок, который уменьшает процессор до головы до 0). – MadProgrammer

+0

@MadProgrammer Я знаю, что это не идеальное решение, и я никогда не утверждал, что он один. Я просто обнаружил, что это работает для меня во многих ситуациях. Вероятно, вы правы, что это не очень хорошая идея для более сложного кодирования, но я думаю, что он может быть подходящим для простых программ. –

+0

Следующий вопрос, который задает OP, - «почему моя программа больше не отвечает на ввод пользователя» - из-за того, что вы ему сказали, что тратит время OP и лишает других потенциальных пользователей заблуждение, делая больше работы для остальные из нас и одновременно уменьшают вашу репутацию. Это не хороший совет вообще (для Swing), и это не решение проблемы OP. Ваша вторая половина вопроса будет решением, которое требует OP. Вместо OP, пытающегося думать, как программа является консольной/линейной программой, им нужно думать в концепции среды, управляемой событиями. – MadProgrammer

-1
jTextField1.addActionListener(new java.awt.event.ActionListener() { 
     public void actionPerformed(java.awt.event.ActionEvent evt) { 
       yourFunction(jTextField1.getText()); 
       jTextField1.setText(""); 
     } 
    }); 

Btw только наконечник, вы можете append в JTextArea, чтобы получить ощущение console window

+1

ПОЧЕМУ !? У ОП уже есть «ActionListener», который будет выполнять ту же работу и делает это на кросс-платформенной основе !? Как общее правило, это плохая идея, чтобы присоединить 'KeyListener' к текстовым компонентам, так как есть множество лучших решений, доступных для мониторинга изменений и предоставления фильтрующих функций! – MadProgrammer

+0

@MadProgrammer Я изменил код, теперь все в порядке? – Rahul

+0

Хорошо, теперь вы можете объяснить ОП «почему» этот метод лучше любого другого подхода. – MadProgrammer

Смежные вопросы

 Смежные вопросы