2016-12-21 55 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