Проблемы Mac L & F: различное поведение JTextField.requestFocus () - PullRequest
4 голосов
/ 09 октября 2009

У меня проблема с поведением JTextField.requestFocus (), которое в Mac OS X выглядит по-другому.

Вот моя ситуация: у меня есть диалог с JList и JTextField. Пользователь должен написать логическое выражение в текстовом поле, а список содержит имена всех переменных, которые могут быть введены в выражение. Поскольку ожидается, что пользователь продолжит вводить выражение после нажатия на переменную из списка, программа услужливо вызывает JTextField.requestFocus (). Таким образом, вы можете, например, щелкнуть «pvalue» в списке, а затем ввести «<0,05» без необходимости щелкать текстовое поле между ними. </p>

Все это прекрасно работает на моей машине для разработки (Linux), но я получил сообщение об ошибке от пользователя Mac, в котором щелчок по списку фактически выделяет весь текст в текстовом поле, облегчая случайную перезапись того, что было введено ранее.

Я подозревал, что это проблема с внешним видом Mac, после некоторого поиска кажется, что действительно существует свойство "Quaqua.TextComponent.autoSelect" для внешнего вида Mac, которое, похоже, связано с эта проблема: http://www.randelshofer.ch/quaqua/guide/jtextcomponent.html

Мой общий вопрос:

  • Можете ли вы предложить решение этой проблемы?

В случае, если это слишком широкий, ответ на эти подвопросы уже будет большая помощь:

  • Возможным решением может быть изменение свойства "Quaqua.TextComponent.autoSelect". Как я могу это сделать?
  • Я даже не уверен, что такое "Quaqua". Похоже, что это индивидуальный внешний вид. Каков внешний вид по умолчанию для Mac OS X? Есть ли у него свойство, похожее на Quaqua.TextComponent.autoSelect?
  • Есть ли возможность настроить внешний вид только для одного экземпляра компонента? Если да, то как?
  • Можно ли настроить внешний вид Mac на моей машине для разработки Linux, чтобы я мог действительно подтвердить эту ошибку (все вышесказанное действительно основано на догадках и подозрениях)? Если да, то как?

Ответы [ 8 ]

4 голосов
/ 14 июня 2013

Кажется, это ошибка Mac OS. JTextFields выбирает их содержимое, когда они получают фокус при циклическом переключении клавиатуры. Если точка вставки находится в середине текста, точка вставки останется, и весь текст не будет выделен.

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

textfield.setCaret(new DefaultCaret()).

Более подробно вы можете обратиться к это и это .

2 голосов
/ 18 января 2010

Обходной путь может быть (и я не проверял это), чтобы сделать JList, который вставляет имена переменных не сфокусированными. Таким образом, фокус будет оставаться в текстовом поле при нажатии на элемент в списке. Я бы порекомендовал использовать setRequestEnabled(false) на JList, чтобы они по-прежнему могли фокусироваться, если вы нажимаете на них, но щелчок мышью не фокусирует их.

2 голосов
/ 09 октября 2009

Чтобы изменить поведение по умолчанию, вы можете установить системное свойство в false перед инициализацией компонентов пользовательского интерфейса: System.setProperty("Quaqua.TextComponent.autoSelect", "false"); Чтобы изменить один компонент, вы можете использовать JTextField#putClientProperty("Quaqua.TextComponent.autoSelect", Boolean.FALSE);.

Вы можете найти другие специфические свойства MacOS L & F здесь:

Quaqua Look & Feel - Руководство пользователя

1 голос
/ 07 января 2011

Извините, что добавил к старому вопросу, но я только столкнулся с этой проблемой и использовал следующий код, который кажется немного более полным, чем в предыдущем примере:

// JTextField linkedText
final int
  startBefore = linkedText.getSelectionStart(),
  endBefore = linkedText.getSelectionEnd();
linkedText.requestFocus(); // this was the original code line!
SwingUtilities.invokeLater(new Runnable()
{
  public void run()
  {
    linkedText.setSelectionStart(startBefore);
    linkedText.setSelectionEnd(endBefore);
  }
});

Появляется для защиты текущей позиции курсора или выбора. (Примечание. Этот код должен уже выполняться в потоке диспетчеризации событий, но в любом случае вам нужен invokeLater, иначе он не работает.)

У меня есть функция «is Mac», поэтому я сделал это в тесте для этого, но, вероятно, это не принесет вреда на всех платформах.

1 голос
/ 11 октября 2009

Хотя использование requestFocusInWindow() действительно рекомендуется для requestFocus(), оно по-прежнему вызывает те же проблемы на Mac (например, выделение полнотекстового поля).

Один из обходных путей, который я получил, заключался в явной установке положения курсора после запроса фокуса:

JTextField.requestFocusInWindow();
JTextField.setCaretPosition(JTextField.getDocument().getLength() - 1);

Обратите внимание, что "-1" необходимо, иначе оно будет продолжать выделять все поле.

Мне любопытно узнать, является ли это решение независимым от платформы. Это испортит желаемое поведение Linux или Windows?

1 голос
/ 09 октября 2009

Я заметил, просматривая JavaDocs, что requestFocus() "не рекомендуется, потому что его поведение зависит от платформы". Вместо этого вы должны использовать requestFocusInWindow() и посмотреть, возникает ли с ним такая же проблема.

requestFocusInWindow является частью подсистемы Focus , представленной в Java 1.4.

Что касается примечания, то у Apple Look and Feel по умолчанию есть хотя бы одно свойство в пространстве имен apple.laf: apple.laf.useScreenMenuBar

Редактировать: Согласно Sun , внешний вид Macintosh доступен только на Mac.

0 голосов
/ 23 декабря 2014

Спасибо, что поделились своими идеями. У меня была та же проблема в моем java-приложении, где в моей системе Windows не было проблем, но в моем Mac OS X Yosemite я не мог изменить ввод. Фокус не останется на JTextField. Благодаря этой теме я смог решить мою проблему.

Если вы измените внешний вид кнопок и полей ввода, вы сохраните фокус и сможете снова печатать. Сброс кадра остается в стандартном виде Mac OS.

Это мой код, который я использую в своем основном методе java. Если вы хотите решить проблему после кода try-catch в вашем основном методе.

public class Venster extends JFrame {

    public static void main(String[] args) {

        //Change L&F for mac
        //Mac JTextField Bug Fix
        try {
            // Set cross-platform Java L&F (also called "Metal")
            UIManager.setLookAndFeel(
                    UIManager.getCrossPlatformLookAndFeelClassName());
        } catch (UnsupportedLookAndFeelException e) {
            System.out.println("L&F not supported" + e.getMessage());

        } catch (ClassNotFoundException e) {
            System.out.println("Fout: " + e.getMessage());
        } catch (InstantiationException e) {
            System.out.println("Fout: " + e.getMessage());
        } catch (IllegalAccessException e) {
            System.out.println("Fout: " + e.getMessage());
        }

        //The app
        JFrame frame = new JFrame();
        frame.setSize(1000, 520);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("10 More Bullets by Frank Peters");
        frame.setContentPane(new SpeelVeld());
        frame.setVisible(true);
        frame.setLocationRelativeTo(null);    //start app in center
    }
}

Soure: http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html

0 голосов
/ 08 октября 2013

Mac выберет содержимое текстового поля, когда поле получит фокус. Вы можете восстановить состояние текстового поля, если прослушиваете событие изменения фокуса.

// JTextField linkedText
// Cache the state of the JTextField prior to requesting focus
final int
  startBefore = linkedText.getSelectionStart(),
  endBefore = linkedText.getSelectionEnd();
linkedText.requestFocus(); // this was the original code line!

// Use a focus listener to listen for the focus change and then
// reset the selected text to protect the cursor position
linkedText.addFocusListener ( new FocusListener()
{
    public void focusGained( FocusEvent event ) {
        linkedText.setSelectionStart( startBefore );
        linkedText.setSelectionEnd( endBefore );
    }

    public void focusLost( FocusEvent event ) {
        // do nothing
    }
} );
...