У меня есть 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 всегда держать фокус в текстовом поле, и вручную управлять выбранным элементом списка. Проблема в том, что вы получаете визуальную разницу, когда делаете это так, по сравнению с тем, если в списке есть надлежащий фокус. Смотрите снимки экрана.
Это то, на что похоже, если я не вмешиваюсь в фокус (это то, что я хочу).
Это то, что это выглядит, как если бы я бег setFocusableWindowState(false)
Основные отличия гвоздя граница (темно-синим) вокруг выбранного элемента списка, но и синяя изюминка вокруг всего диалогового окна. Тогда есть также различия в заголовке.
(Не против рендер артефакты, я подключение к трехлетний виртуальной установке 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;
}
}
Да, я пробовал это. Именно это побудило меня отредактировать в последней части моего вопроса: «Но, с другой стороны, если я сделаю так, чтобы меню не могло получить фокус, я не могу (с правильным визуальным внешним видом) контролировать выбранные пункт меню.". Вы видите, выбирая элемент с 'setFocusableWindowState (false);' не выглядит совершенно правильным, по сравнению с тем, как он выглядит с помощью 'setFocusableWindowState (true);'. – Tobbe
@Tobbe. Единственное различие, которое я замечаю при использовании JDK7 в Windows 7, заключается в том, что Border на выбранном элементе не отображается. Я бы предположил, что вы можете исправить это, используя собственный рендерер для JList, который всегда рисует границу, имеет ли компонент фокус или нет. Другой вариант - вызывать 'setFocusableWindowState (true)' после отображения диалогового окна. – camickr
Я быстро общался с ложными/истинными вызовами 'setFocusableWindowState', но не мог заставить его работать правильно. В документе docs указано «Чтобы обеспечить согласованное поведение на разных платформах, установите фокусируемое состояние окна, когда окно невидимо, а затем покажите его» http://docs.oracle.com/javase/7/docs/api/java/awt/Window. html # setFocusableWindowState (boolean) Я использую некоторую (возможно, старую) версию RedHat Enterprise Linux, используя JDK7. – Tobbe