在寫一個模擬QQ的簡易網絡聊天程序,主要功能就是連到服務端的各個客戶端都能實時收發到各客戶端發的消息,只要有客戶端發消息,那麼所有客戶端都將通過服務端這個中轉站來接收到這個消息。
邏輯功能很簡單,一會就寫好了。但是在後續考慮用戶使用方便時,需要通過回車“ENTER”按鍵來直接發送消息,而不是每次發消息後都要點擊你的“Send”按鈕,這對用戶就太不友好了,所以自己的第一思路就是通過鍵盤監聽來實現,即一旦用戶按下回車鍵就在內部做出等同“send”按鈕行爲的響應。嘻嘻,自己當時以爲很簡單的,於是立即實施寫出了下面的代碼:
sendTextArea.addKeyListener(new SendMessage());
class SendMessage extends KeyAdapter implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
sendMessage();
}
@Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
sendMessage();
}
}
public void sendMessage(){
if(sendTextArea.getText().length() != 0) {
clientWriter.println(userName + ":" + sendTextArea.getText());
sendTextArea.setText(null);
sendTextArea.requestFocus();
} else {
receiveTextArea.append("QQChat Server: You can't input for nothing, please input something again!\n");
}
}
}
執行後是下面的結果: 看,輸入完hi之後發送消息的文本域沒有被置爲空而是移到了下一行的開始位置。。。當時很奇怪,再試了幾次發現都一樣: 自己期望的自然是光標能回到起始處,於是自己開始篩查原因,推測如下:造成這個現象和事件監聽處理的模型有關。當給某個組件註冊添加監聽器如此例中爲發送文本域sendTextArea添加鍵盤監聽器keyListener時,只要鼠標焦點在sendTextArea中監聽器就會隨時監聽你的鍵盤按鍵事件並立即做出相應響應,此時你按下”hi”沒反應【很顯然因爲你比較的鍵值是enter鍵嘛】。在你回車時,監聽器立馬會對此事進行響應做出你內部定義的行爲keyPressed,甚至在——文本域輸出該按鍵應有的行爲前做出響應。這句話很重要,就直接解釋了爲什麼本應該重置爲空“”的發送文本域又多了一行。正常來說程序是這樣執行的:按下enter鍵——》執行enter鍵在文本域中原有的行爲——即換行並將光標移到下一行的起始處;但是你加了鍵盤監聽後,一旦你按鍵產生鍵盤事件,鍵盤監聽器的行爲要優於按鍵原有的行爲,即程序先進入keyPressed方法執行完動作(發送信息文本並將發送文本域置空)再回去執行enter鍵的原有行爲,然後正如你所看到的——在發送完消息後又多了一行。。。
所以綜上,這個鍵盤監聽的方法雖然可以讓我們實現發送消息的功能操作,但是由於後續不理想的行爲而放棄該方法。轉而繼續思考解決方案,就考慮莫不如直接給文本域註冊個快捷鍵吧,然後通過搜索查找資料,得到inputMap, actionMap來給組件添加快捷鍵的方法(具體用法請參考官方API文檔)!具體代碼如下:
sendTextArea.getInputMap(JComponent.WHEN_FOCUSED).put(
KeyStroke.getKeyStroke('\n'),
"send");
sendTextArea.getActionMap().put("send", new SendMessage());
class SendMessage extends AbstractAction{
@Override
public void actionPerformed(ActionEvent e){
if(sendTextArea.getText().length() != 0) {
clientWriter.println(userName + ":" + sendTextArea.getText());
sendTextArea.setText("");
sendTextArea.requestFocus();
} else {
receiveTextArea.append("QQChat Server: You can't input for nothing, " +
"please input something again!\n");
}
}
}
結果如下:
發送文本域顯示沒問題,消息發送後成功置位空,但是顯示文本域結果是這樣的:
各個消息間多了個空行。。。和上面用鍵盤監聽的結果正好反過來了~
在getKeyStroke方法參數中加個modifier參數0,
sendTextArea.getInputMap(JComponent.WHEN_FOCUSED).put(
KeyStroke.getKeyStroke('\n', 0),
"send");
就可以正常顯示完全沒問題了~
後面的modifier如果不加本該默認是0的就是不用加任何修飾符直接單鍵作爲快捷鍵,但是不知道爲何還要手動加0,這是個遺留的小問題,希望自己日後弄更透徹後再回來修改完善本博文,嘻嘻!
總結:第一種鍵盤監聽方法只是插入了個監聽器,並無法改變按鍵在原組件中的原有行爲屬性,但是加快捷鍵的方法就可以改變,比如原本enter鍵是在文本域中換行並移動光標到下一行起始位置,但是你加快捷鍵後就改變了你在該文本域中按enter鍵的行爲變成你自定義的Action行爲了~至於用哪種方法實現,就看你自己取捨吧~