2016-12-21 48 views
1

我最近开始学习JAVA,并试图创建一个小壳程序(我不依赖于系统shell执行命令)。等待参数在Java中的价值

我设法得到基本的I/O东西的工作,但我被困在以下情况:

比方说,我用命令“Makefile文件路径/到/文件”命令将检查存在并询问“文件已存在!你想删除它吗?是/否”

我的问题是等待用户输入Y,N或其他任何东西,而不锁定外壳接口(JTextArea)。

import java.util.StringTokenizer; 

public abstract class Command { 

private final String bin; 
protected Shell shell; 

public Command(Shell shell, final String bin) { 
    this.shell = shell; 
    this.bin = bin; 
} 

String getBin() { 
    return this.bin; 
} 

protected String ask(String question) { 
    shell.setQuestionAsked(true); 
    shell.setResponse(""); 
    shell.write(question); 
    String response = shell.getResponse(); 

    while(response.isEmpty()) { 
     response = shell.getResponse(); 
    } 

    shell.setQuestionAsked(false); 
    return response; 
} 

public abstract void execute(StringTokenizer stringTokenizer);  
} 

我试图在并发/线程中找到解决方案,但找不到解决方案。

在@Holger评论中,这是GUI代码部分,因为您可以看到一个Listener已经存在。我的问题在于,当一个命令用上面显示的ask方法询问用户输入时,执行不会等待用户输入,只是继续或在当前的while(response.isEmpty())中导致死锁。

所以我正在寻找一个解决方案来保持ask()方法的执行,直到用户在GUI中按下Enter键。

import javax.swing.*; 
import java.awt.*; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.datatransfer.StringSelection; 
import java.awt.datatransfer.UnsupportedFlavorException; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.io.IOException; 


public class ShellPanel extends Shell { 

    private JTextArea shellArea; 
    private JPanel panel; 
    private JScrollPane scrollPanel; 

    private int bufferLength = 0; 
    private String oldText = ""; 

    ShellPanel() { 


     shellArea.addKeyListener(new KeyAdapter() { 
      @Override 
      public void keyPressed(KeyEvent e) { 
       super.keyPressed(e); 

       switch (e.getKeyCode()) { 

        case KeyEvent.VK_UP: 
        case KeyEvent.VK_DOWN: 

         e.consume(); 

         break; 
        case KeyEvent.VK_LEFT: 

         if (shellArea.getCaretPosition() <= bufferLength) { 
          e.consume(); 
         } 

         break; 

        case KeyEvent.VK_BACK_SPACE: 

         if (shellArea.getText().length() <= bufferLength) { 
          e.consume(); 
         } 

         break; 
        case KeyEvent.VK_DELETE: 
         break; 
        case KeyEvent.VK_ENTER: 
         read(getNewInput()); 
         updateReferences(); 
         e.consume(); 
         break; 
        case KeyEvent.VK_HOME: 
         shellArea.setCaretPosition(bufferLength); 
         break; 
       } 

      } 

     }); 

     shellArea.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       super.mouseClicked(e); 

       switch (e.getButton()) { 
        case MouseEvent.BUTTON3: 

         String selected = shellArea.getSelectedText(); 
         StringSelection selection = new StringSelection(selected); 

         if (!selected.isEmpty()) { 
          Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); 
         } 

         try { 
          String clip = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor); 

          if (!clip.isEmpty()) { 
           shellArea.append(clip); 
          } 

         } catch (UnsupportedFlavorException | IOException e1) { 
          e1.printStackTrace(); 
         } 
         break; 
       } 
      } 
     }); 
     init(); 
     updateReferences(); 
    } 

    JPanel getPanel() { 
     return panel; 
    } 

    private void updateReferences() { 
     oldText = shellArea.getText(); 
     bufferLength = oldText.length(); 
     shellArea.setCaretPosition(bufferLength); 
    } 

    @Override 
    public void write(String content) { 
     shellArea.append(content); 
     updateReferences(); 
    } 

    private String getNewInput() { 
     return this.shellArea.getText().replace(this.oldText, ""); 
    } 

    @Override 
    public void clear() { 
     this.shellArea.setText(""); 
    } 
    } 

感谢

+0

不要等待。将一个监听器添加到事件发生时将被调用的文本区域中,并且如果该事件意味着必要的先决条件(即,输入了“Y”或“N”),则可以执行期望的操作。 – Holger

+0

谢谢@Holger,我忘了提到一个监听器已经存在,我将添加GUI代码来澄清我的声明 – Shalien

+0

您需要在单独的线程中执行此操作。 – ACV

回答

0

一般来说,你应该避免必须等待一个UI事件,而不是让合适的事件监听器触发后续行动的程序逻辑。

等待逻辑与打开模式对话框相似,而打开方法将在对话框关闭时返回。在JOptionPane.showInputDialog的情况下,它甚至会返回输入的值。这个逻辑已经在Java 7中被抽象出来,允许任意“等待事件”场景。这里是一个自包含的例子:

public class WaitForInput { 
    public static void main(String[] args) { 
     EventQueue.invokeLater(() -> { 
      JFrame frame=new JFrame("Example"); 
      JTextArea ta=new JTextArea(20,40); 
      ta.setEditable(false); 
      frame.setContentPane(new JScrollPane(ta)); 
      frame.pack(); 
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      frame.setVisible(true); 
      char result = waitForInput(ta, "Press Y or N", 
       ch -> Character.toUpperCase(ch)=='Y' || Character.toUpperCase(ch)=='N'); 
      waitForInput(ta, 
       "You pressed "+result+", press Enter to continue", ch -> ch==10); 
      ta.append("Ok, I'm happy... Close window to quit"); 
     }); 
    } 
    static char waitForInput(JTextArea ta, String message, IntPredicate p) { 
     ta.append(message); 
     ta.append("\n"); 
     SecondaryLoop loop = ta.getToolkit().getSystemEventQueue().createSecondaryLoop(); 
     final class WaitOp extends KeyAdapter { 
      char actualChar; 
      public void keyTyped(KeyEvent e) { 
       if(p.test(e.getKeyChar())) { 
        actualChar=e.getKeyChar(); 
        loop.exit(); 
       } 
      } 
     } 
     WaitOp op = new WaitOp(); 
     ta.addKeyListener(op); 
     loop.enter(); 
     ta.removeKeyListener(op); 
     return op.actualChar; 
    } 
} 

但必须强调的是,不像一个模态对话框,没有视觉指示,有已停止在中间,等待特定的输入操作(除你自己编程)。此外,其余的用户界面不会被阻止,并且可能会产生新的操作,这些操作也可能会停在中间,等待不同的事件,从而使程序处于不可维护的状态。

这就是为什么应尽可能避免这种情况。但是,如果您将其使用限制在可维护的最低限度,它可能非常有用。

+0

这是一个完美的解决方案,再加上使用lambda使其简单。谢谢; – Shalien