2012-04-05 30 views
10

Tôi có một số JTextField mà tôi hy vọng sẽ đề xuất các kết quả phù hợp với đầu vào của người dùng. Tôi đang hiển thị các đề xuất này trong một số JList có trong một số JPopupMenu.Dừng JPopupMenu lấy cắp tiêu điểm

Tuy nhiên, khi mở menu bật lên được lập trình qua show(Component invoker, int x, int y), tiêu điểm được lấy từ JTextField.

Thật kỳ lạ, nếu tôi gọi setVisible(true) thay vào đó, tiêu điểm không bị đánh cắp; nhưng sau đó JPopupMenu không được đính kèm vào bất kỳ bảng điều khiển nào và khi giảm thiểu ứng dụng trong khi hộp đang mở, nó vẫn được vẽ trên cửa sổ.

Tôi cũng đã cố gắng để thiết lập lại tập trung vào JTextField sử dụng requestFocus(), nhưng sau đó tôi phải khôi phục lại vị trí dấu nháy sử dụng SwingUtilities.invokeLater(), và invoke sau bên thứ là cho người sử dụng một biên độ nhẹ để lộn xộn xung quanh với nội dung hiện có/ghi đè lên/hoặc thực hiện những điều không thể đoán trước khác.

Mã tôi nhận được là một cách hiệu quả:

JTextField field = new JTextField(); 
JPopupMenu menu = new JPopupMenu(); 

field.addKeyListener(new KeyAdapter() { 
    public void keyTyped(KeyEvent e) { 
     JList list = getAListOfResults(); 

     menu.add(list); 
     menu.show(field, 0, field.getHeight()); 
    } 
}); 

bất cứ ai có thể đề xuất những con đường tốt nhất để đi xuống để hiển thị các JPopupMenu lập trình trong khi duy trì sự tập trung vào các JTextField?

Trả lời

14

Câu trả lời kỹ thuật là để thiết lập tài sản đặt tiêu điểm của popup để sai:

popup.setFocusable(false); 

Ý nói textfield có để tiếp nhận tất cả các hành động bàn phím và chuột kích hoạt thường được xử lý bởi các danh sách riêng của mình, sosmething như:

final JList list = new JList(Locale.getAvailableLocales()); 
final JPopupMenu popup = new JPopupMenu(); 
popup.add(new JScrollPane(list)); 
popup.setFocusable(false); 
final JTextField field = new JTextField(20); 
Action down = new AbstractAction("nextElement") { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     int next = Math.min(list.getSelectedIndex() + 1, 
       list.getModel().getSize() - 1); 
     list.setSelectedIndex(next); 
     list.ensureIndexIsVisible(next); 
    } 
}; 
field.getActionMap().put("nextElement", down); 
field.getInputMap().put(
     KeyStroke.getKeyStroke("DOWN"), "nextElement"); 

như hoàn cảnh của bạn rất giống với một JComboBox, bạn có thể xem xét việc có một cái nhìn vào nguồn BasicComboBoxUI và Basi cComboPopup.

Sửa

Just for fun, các sau đây là không trả lời các câu hỏi tập trung :-) Thay vào đó, nó cho thấy làm thế nào để sử dụng một sắp xếp được/JXList lọc để chỉ hiển thị các tùy chọn trong menu thả xuống tương ứng các văn bản đánh máy (ở đây với một bắt đầu với các quy tắc)

// instantiate a sortable JXList 
final JXList list = new JXList(Locale.getAvailableLocales(), true); 
list.setSortOrder(SortOrder.ASCENDING); 

final JPopupMenu popup = new JPopupMenu(); 
popup.add(new JScrollPane(list)); 
popup.setFocusable(false); 
final JTextField field = new JTextField(20); 

// instantiate a PatternModel to map text --> pattern 
final PatternModel model = new PatternModel(); 
model.setMatchRule(PatternModel.MATCH_RULE_STARTSWITH); 
// listener which to update the list's RowFilter on changes to the model's pattern property 
PropertyChangeListener modelListener = new PropertyChangeListener() { 

    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
     if ("pattern".equals(evt.getPropertyName())) { 
      updateFilter((Pattern) evt.getNewValue()); 
     } 
    } 

    private void updateFilter(Pattern newValue) { 
     RowFilter<Object, Integer> filter = null; 
     if (newValue != null) { 
      filter = RowFilters.regexFilter(newValue); 
     } 
     list.setRowFilter(filter); 
    } 
}; 
model.addPropertyChangeListener(modelListener); 

// DocumentListener to update the model's rawtext property on changes to the field 
DocumentListener documentListener = new DocumentListener() { 

    @Override 
    public void removeUpdate(DocumentEvent e) { 
     updateAfterDocumentChange(); 
    } 

    @Override 
    public void insertUpdate(DocumentEvent e) { 
     updateAfterDocumentChange(); 
    } 

    private void updateAfterDocumentChange() { 
     if (!popup.isVisible()) { 
      popup.show(field, 0, field.getHeight()); 
     } 
     model.setRawText(field.getText()); 
    } 

    @Override 
    public void changedUpdate(DocumentEvent e) { 
    } 
}; 
field.getDocument().addDocumentListener(documentListener); 
+0

Câu trả lời hay ... hoạt động hoàn hảo .. cảm ơn;) – Isaac

+0

Điều này đã giúp tôi rất nhiều, cảm ơn! – Epaga

+0

Sau rất nhiều googling, câu trả lời này đã giúp tôi rất nhiều –

2

Dường như thẳng về phía tôi. Thêm dòng sau

field.requestFocus();

sau

menu.add(list); 
menu.show(field, 0, field.getHeight()); 

Tất nhiên, bạn sẽ phải viết mã cho khi để ẩn popup vv dựa trên những gì đang xảy ra với JTextField.

tức là;

menu.show(field, field.getX(), field.getY()+field.getHeight()); 
menu.setVisible(true); 
field.requestFocus(); 
+0

Cảm ơn câu trả lời của bạn; tiếc là tôi đã thử phương pháp này. Nó trở nên phức tạp hơn vì sau đó tôi phải khôi phục lại vị trí dấu mũ bằng cách sử dụng 'SwingUtilities.invokeLater()', và phía * gọi sau * của mọi thứ cho người dùng một chút lề để làm rối tung các nội dung hiện có/ghi đè lên nó hoặc làm những điều không thể đoán trước khác. – Isaac

1

Bạn có thể có một cái nhìn để JXSearchField, mà là một phần của xswingx

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