2014-12-20 1 views
2

У меня есть JTextField, что я пытаюсь добавить меню автозаполнения. Но у меня проблемы с тем, как я должен справиться с этим.Java Swing: управление фокусом с помощью текстового поля и диалогового окна автозаполнения/меню

Вот SSCCE

package test; 

import java.awt.Point; 

import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JTextField; 
import javax.swing.SwingUtilities; 
import javax.swing.event.DocumentEvent; 
import javax.swing.event.DocumentListener; 

public class SSCCE extends JFrame implements DocumentListener { 
    private AutocompletionDialog dialog; 

    public SSCCE() { 
     dialog = new AutocompletionDialog(); 

     JTextField textField = new JTextField(20); 
     textField.getDocument().addDocumentListener(this); 

     add(textField); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     pack(); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       new SSCCE().setVisible(true); 
      } 
     }); 
    } 

    public void insertUpdate(DocumentEvent e) { 
     Point p = this.getLocationOnScreen(); 
     dialog.setLocation(p.x, p.y + 50); 
     dialog.setVisible(true); 
    } 

    public void removeUpdate(DocumentEvent e) { } 
    public void changedUpdate(DocumentEvent e) { } 

    private class AutocompletionDialog extends JDialog { 
     JList<String> list = new JList<>(
       new String[] { "One", "Two", "Three" }); 

     AutocompletionDialog() { 
      setSize(100, 100); 
      add(list); 
     } 
    } 
} 

Конечно, есть больше логики к ней в реальной программе, но проблема у меня в том, что я хочу, чтобы показать автозаполнения диалоговое/меню, но все еще быть в состоянии продолжайте вводить текст в текстовое поле. В то же время я также хочу, чтобы вы могли перемещаться по меню со стрелками вверх/вниз и клавишей ввода, а также с помощью мыши, чтобы выбрать один из вариантов завершения.

Может кто-нибудь, пожалуйста, помогите мне с тем, как я должен действовать здесь? Благодаря!

EDIT:

Благодаря @camickr «s ответ я играл немного с setFocusableWindowState вместе с InputMap/ActionMap всегда держать фокус в текстовом поле, и вручную управлять выбранным элементом списка. Проблема в том, что вы получаете визуальную разницу, когда делаете это так, по сравнению с тем, если в списке есть надлежащий фокус. Смотрите снимки экрана.

Это то, на что похоже, если я не вмешиваюсь в фокус (это то, что я хочу).

dialog with proper focus

Это то, что это выглядит, как если бы я бег setFocusableWindowState(false)

dialog with no focus

Основные отличия гвоздя граница (темно-синим) вокруг выбранного элемента списка, но и синяя изюминка вокруг всего диалогового окна. Тогда есть также различия в заголовке.

(Не против рендер артефакты, я подключение к трехлетний виртуальной установке Linux с помощью старого NX клиента)

EDIT 2:

Я боялся, что это было Look and Feel или OS, которые определяют, как должен выглядеть элемент выбранного списка (например, с выделенной границей). Но оказывается, что именно это делает обработчик ячеек. Зная, что я чувствовал себя намного лучше в написании своего собственного рендеринга ячеек, и теперь у меня есть решение, которым я доволен.

Это код, который я закончил с использованием:

private class CellRenderer extends DefaultListCellRenderer 
{ 
    @Override 
    public Component getListCellRendererComponent(
      JList<?> jlist, Object value, int index, 
      boolean isSelected, boolean cellHasFocus) { 
     super.getListCellRendererComponent(
       jlist, value, index, isSelected, cellHasFocus); 

     if (isSelected) { 
      Border border = UIManager.getBorder(
        "List.focusSelectedCellHighlightBorder"); 

      if (border == null) { 
       border = UIManager.getBorder(
         "List.focusCellHighlightBorder"); 
      } 

      setBorder(border); 
     } 

     return this; 
    } 
} 

ответ

2

Как я показываю меню автоматического завершения фокус дается в этом диалоге.

Чтобы предотвратить фокус от перехода в всплывающем окне вы можете использовать:

JDialog dialog = new JDialog(...); 
dialog.setFocusableWindowState(false); 
... 
dialog.setVisible(true); 

Я также хочу, чтобы иметь возможность перемещаться по меню с помощью кнопок вверх/вниз стрелки и клавишу ввода

Затем вам необходимо переопределить действия по умолчанию, предоставляемые текстовым полем. За дополнительной информацией обращайтесь к Key Bindings.

Вы также можете проверить: button highlighting using keyboard keys, где я просто предоставил простой пример реализации действия.

+0

Да, я пробовал это. Именно это побудило меня отредактировать в последней части моего вопроса: «Но, с другой стороны, если я сделаю так, чтобы меню не могло получить фокус, я не могу (с правильным визуальным внешним видом) контролировать выбранные пункт меню.". Вы видите, выбирая элемент с 'setFocusableWindowState (false);' не выглядит совершенно правильным, по сравнению с тем, как он выглядит с помощью 'setFocusableWindowState (true);'. – Tobbe

+0

@Tobbe. Единственное различие, которое я замечаю при использовании JDK7 в Windows 7, заключается в том, что Border на выбранном элементе не отображается. Я бы предположил, что вы можете исправить это, используя собственный рендерер для JList, который всегда рисует границу, имеет ли компонент фокус или нет. Другой вариант - вызывать 'setFocusableWindowState (true)' после отображения диалогового окна. – camickr

+0

Я быстро общался с ложными/истинными вызовами 'setFocusableWindowState', но не мог заставить его работать правильно. В документе docs указано «Чтобы обеспечить согласованное поведение на разных платформах, установите фокусируемое состояние окна, когда окно невидимо, а затем покажите его» http://docs.oracle.com/javase/7/docs/api/java/awt/Window. html # setFocusableWindowState (boolean) Я использую некоторую (возможно, старую) версию RedHat Enterprise Linux, используя JDK7. – Tobbe

Смежные вопросы