2011-12-15 25 views
9

Có các ràng buộc khóa đã đăng ký cho "SPACE" và "SPACE được phát hành" hoạt động như được quảng cáo khi không gian là phím duy nhất được nhấn/phát hành, tôi nhận thấy không gian nhấn, sau đó nhấn ctrl (hoặc bất kỳ phím bổ trợ nào khác), sau đó giải phóng không gian và cuối cùng phát hành ctrl sẽ gây ra hành động liên quan đến "SPACE" được thực hiện, nhưng không phải hành động liên quan đến "SPACE được phát hành".ràng buộc chìa khóa java swing - thiếu hành động cho khóa được phát hành

Cách ưa thích để thực hiện hành động khi không gian được nhấn nữa (hoặc phím bổ trợ được nhấn đồng thời)? Tôi chỉ thử điều này trên Windows 7, 64-bit.

import javax.swing.SwingUtilities; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.AbstractAction; 
import javax.swing.KeyStroke; 
import java.awt.event.ActionEvent; 
import java.awt.Cursor; 

class Bind extends JPanel { 
    { 
    getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed"); 
    getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released"); 
    getActionMap().put("pressed", new AbstractAction() { 
     @Override public void actionPerformed(ActionEvent e) { 
     System.out.println("pressed"); 
     setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
     } 
    }); 
    getActionMap().put("released", new AbstractAction() { 
     @Override public void actionPerformed(ActionEvent e) { 
     System.out.println("released"); 
     setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
     } 
    }); 
    } 
    public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     @Override public void run() { 
     JFrame f = new JFrame("Key Bindings"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(new Bind()); 
     f.setSize(640, 480); 
     f.setVisible(true); 
     } 
    }); 
    } 
} 

CẬP NHẬT: Đây là cách để tránh không gian dính khi vô tình nhấn Ctrl, Alt hoặc Shift trước khi thả không gian:

import javax.swing.SwingUtilities; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.AbstractAction; 
import javax.swing.KeyStroke; 
import java.awt.event.ActionEvent; 
import java.awt.Cursor; 

class Bind extends JPanel { 
    { 
    getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed"); 
    getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("ctrl released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("shift released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("shift ctrl released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("alt released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("alt ctrl released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("alt shift released SPACE"), "released"); 
    getInputMap().put(KeyStroke.getKeyStroke("alt shift ctrl released SPACE"), "released"); 
    getActionMap().put("pressed", new AbstractAction() { 
     @Override public void actionPerformed(ActionEvent e) { 
     System.out.println("pressed"); 
     setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
     } 
    }); 
    getActionMap().put("released", new AbstractAction() { 
     @Override public void actionPerformed(ActionEvent e) { 
     System.out.println("released"); 
     setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
     } 
    }); 
    } 
    public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     @Override public void run() { 
     JFrame f = new JFrame("Key Bindings"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(new Bind()); 
     f.setSize(640, 480); 
     f.setVisible(true); 
     } 
    }); 
    } 
} 
+2

Để được trợ giúp tốt hơn sớm hơn, hãy đăng [SSCCE] (http://sscce.org/). –

+2

[SSCCE] (http://sscce.org/) được thêm vào để được trợ giúp tốt hơn sớm hơn :-) – Aksel

+1

OK .. Đó là một câu hỏi rất hay. Tôi nhìn thấy hành vi mà bạn mô tả (trong 32 bit Win 7), nhưng không có ý tưởng làm thế nào để sửa chữa nó. Hy vọng rằng một trong những bậc thầy quan trọng ràng buộc sẽ xảy ra bởi .. mùa đông. :) –

Trả lời

6

Làm cho cảm giác rằng sự kiện released SPACE không được kích hoạt khi phím Control vẫn được giữ. Tôi mong đợi một sự kiện control released SPACE sẽ được kích hoạt.

Thêm dòng sau vào code của bạn:

getInputMap().put(KeyStroke.getKeyStroke("control released SPACE"), "released"); 

Đối với lý do tương tự trường hợp SPACE sẽ không cháy nếu bạn lần đầu tiên giữ phím Control xuống. Vì vậy, bạn cũng sẽ cần phải thêm các ràng buộc cho control SPACE.

Bạn cần thực hiện việc này cho tất cả các phím bổ trợ, có thể hoặc không thể là giải pháp đơn giản hơn là theo dõi các sự kiện chính.

+0

Tôi chấp nhận câu trả lời của bạn là câu trả lời tôi đã tự làm (thêm ràng buộc cho TẤT CẢ không gian + tổ hợp bổ trợ), nhưng tôi không chấp nhận logic của nó (tôi không đồng ý rằng nó có ý nghĩa). Khi hành động cho không gian được thực hiện tôi sẽ mong đợi hành động cho không gian phát hành được thực hiện tại một số điểm sau khi không gian đã được phát hành, sửa đổi hay không. Như bạn chỉ ra tôi phải thêm các ràng buộc cho tất cả các tổ hợp phím + phím bổ trợ và tất cả các tổ hợp phím bổ trợ (cũng là ctrl + alt + shift + dấu cách) để ngăn chặn kiểu hành vi này. – Aksel

+1

Nó có ý nghĩa hoàn chỉnh (cho dù bạn có đồng ý hay không). Nếu một sự kiện không gian được tạo ra mỗi khi phím Space được nhấn thì bạn sẽ phân biệt như thế nào với Space và Control/Space? Với logic của bạn, bạn sẽ luôn nhận được 2 sự kiện, một cho Control/Space và một cho Space. Vì vậy, ngay cả khi người dùng sẽ chỉ cố gắng thực hiện Hành động Kiểm soát/Không gian, một Hành động Không gian sẽ được ném miễn phí. – camickr

+0

Tôi không nói rằng tôi sẽ nhận được một sự kiện không gian cho không gian ctrl +, tôi nói rằng tôi muốn một sự kiện không gian phát hành khi một sự kiện không gian. Những gì tôi nhận được bây giờ là một sự kiện không gian ctrl + phát hành khi một sự kiện không gian, và trong khi đó có thể có ý nghĩa với bạn, và mặc dù bạn đã tự mình đánh giá những gì có ý nghĩa hay không, nó không phải là rất hữu ích cho tôi. – Aksel

3

Có thể là hệ điều hành của bạn không bắn keyReleased sự kiện , nhưng chỉ keyPressedkeyTyped sự kiện hoặc một số kết hợp khác, vì vậy hãy kiểm tra điều đó trước tiên. Bạn có thể chỉ cần kiểm tra các sự kiện keyTyped thay vì keyReleased và bạn sẽ được thực hiện với nó.

Câu trả lời ngắn:

Sử dụng một mảng bitmask hoặc để theo dõi các phím hiện đang trong "ép" nhà nước, sau đó sử dụng những giá trị để kích hoạt sự kiện. Đó là, không sử dụng các sự kiện Swing trực tiếp để kích hoạt phản hồi trong ứng dụng của bạn - bạn cần thêm một lớp về cơ bản lưu trữ trạng thái của bàn phím và từ trạng thái đó, thực hiện các hành động có liên quan.

Cũng có sẵn các phương pháp (see the end of this tutorial - "isAltDown", "isCtrlDown" etc.) để kiểm tra xem các phím bổ trợ có được nhấn khi bạn nhận được sự kiện như phím "Không gian" đang được nhấn hay không.

dài câu trả lời:

Bạn đúng rằng các sự kiện bị sa thải khi các phím được nhấn và nhả. Nó phải hoạt động theo cách đó để bạn có thể hỗ trợ các ứng dụng nên xử lý riêng những sự kiện đó, trái với nhau. Một ví dụ (mặc dù đây không phải là duy nhất) là trò chơi video trên PC nơi bạn có thể nhấn nhiều phím/phím bổ trợ cùng một lúc (ví dụ: A để sang trái và W để tiếp tục) và trò chơi phải xử lý hai sự kiện này là đầu vào riêng biệt, trái ngược với đầu vào tổng hợp, dẫn đến chuyển động của bạn đi về phía trước bên trái. Vì vậy, những gì bạn về cơ bản muốn làm, nếu bạn cần phải đối phó với đầu vào tổng hợp, có một mảng đơn giản các hành động mà ứng dụng của bạn cần phản hồi và các liên kết khóa liên quan của chúng (cho dù đơn hoặc đa khóa không hoạt động) 't thực sự quan trọng). Khi một phím được nhấn, bạn về cơ bản bật một lá cờ cho chìa khóa đó nói rằng nó hiện đang "ép", và xóa cờ khi nó được phát hành.

Sau đó, để kích hoạt các sự kiện, bạn chỉ cần kiểm tra tất cả các phím được nhấn (thông qua việc kiểm tra phím "cờ" nào đang hoạt động) và nhấn tổ hợp phím của sự kiện cụ thể.

Nếu bạn có ít hơn 32 khóa kích hoạt sự kiện, thì bạn có thể thực sự thực hiện việc này với một giá trị bitmask và 32 bit bit int, chứ không phải là một mảng. Trong thực tế, nó đơn giản hơn nhiều để làm điều đó theo cách này nếu bạn có thể. Nếu bạn cần đến 64 phím, hãy thực hiện tương tự với một số long.Nếu bạn có rất ít khóa kích hoạt sự kiện (ví dụ 8 hoặc ít hơn), bạn có thể sử dụng loại8 bit.

+0

Vì vậy, câu trả lời thậm chí ngắn hơn là: Không sử dụng các ràng buộc chính. Tôi nghi ngờ nhiều. Nó làm tôi buồn. :-) – Aksel

+0

Tôi thực sự vừa sửa đổi câu trả lời của mình và thêm một đoạn vào đầu. Có thể hệ điều hành của bạn không kích hoạt cả ba sự kiện. Đó là một quirk của Swing khi áp dụng cho nhiều nền tảng. Đó thực sự có thể là câu trả lời của bạn. – jefflunt

+0

Đọc qua toàn bộ tài liệu 'KeyEvent' (ít nhất là phần/tổng quan hàng đầu), hoặc có thể không trợ giúp: http://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent. html – jefflunt

Các vấn đề liên quan