Mac L&F 问题:JTextField.requestFocus() 的不同行为

发布于 2024-08-07 10:42:23 字数 992 浏览 3 评论 0原文

我的 JTextField.requestFocus() 行为存在问题,在 Mac OS X 上似乎有所不同。

这是我的情况:我有一个包含 JList 和 JTextField 的对话框。用户应该在文本字段中编写一个布尔表达式,并且列表包含可能在表达式中输入的所有变量的名称。由于用户需要在单击列表中的变量后继续输入表达式,因此程序会调用 JTextField.requestFocus()。这样,您可以例如从列表中单击“pvalue”,然后键入“<0.05”,而无需单击之间的文本字段。

这一切在我的开发机器(Linux)上运行良好,但我从 Mac 用户那里得到了一个错误报告,点击列表实际上会选择文本字段中的所有文本,很容易意外覆盖之​​前输入的内容。

我怀疑这是 Mac 外观的问题,经过一番搜索后,似乎 Mac 外观确实有一个“Quaqua.TextComponent.autoSelect”属性似乎与此问题相关: http://www.randelshofer.ch/quaqua/guide/jtextcomponent.html

我的一般问题是:

  • 您能否建议解决此问题的方法?

如果范围太宽泛,这些子问题的答案已经很有帮助:

  • 可能的解决方案是更改属性“Quaqua.TextComponent.autoSelect”。我该怎么做?
  • 我什至不确定“Quaqua”是什么。看起来像是定制的外观和感觉。 Mac OS X 的默认外观和风格是什么?它是否有类似于 Quaqua.TextComponent.autoSelect 的属性?
  • 是否有可能仅调整单个组件实例的外观?如果是这样,怎么办?
  • 是否可以在我的 Linux 开发机器上设置 Mac 外观,以便我可以实际确认此错误(以上所有内容实际上都是基于预感和怀疑)?如果是这样,怎么办?

I have a problem with JTextField.requestFocus() behavior that appears to be different on Mac OS X.

Here is my situation: I have a dialog with a JList and a JTextField. The user is supposed to write a boolean expression in the text field, and the list contains the names of all the variables that might be entered in the expression. Because the user is expected to continue entering the expression after clicking on a variable from the list, the program helpfully calls JTextField.requestFocus(). This way you can e.g click "pvalue" from the list and then type " < 0.05" without the need to click on the textfield in between.

This all works fine on my development machine (Linux), but I got a bug report from a Mac user that clicking on the list actually selects all text in the text field, making it easy to accidentally overwrite what was entered before.

I suspected this is a problem with the Mac look-and-feel, after some searching it seems that indeed there is a "Quaqua.TextComponent.autoSelect" property for the mac look-and-feel that seems to be related to this problem: http://www.randelshofer.ch/quaqua/guide/jtextcomponent.html

My general question is:

  • Can you suggest a workaround for this problem?

In case that is too broad, an answer to these subquestions would already be a big help:

  • A possible solution could be to change the property "Quaqua.TextComponent.autoSelect". How do I do that?
  • I'm not even sure what "Quaqua" is. It looks like it is a customized look and feel. What is the default look and feel for Mac OS X? Does it have a property similar to Quaqua.TextComponent.autoSelect?
  • Is there a possibility to tweak look and feel for a single component instance only? If so, how?
  • Is it possible to set the Mac look and feel on my Linux development machine so that I can actually confirm this bug (all the above is really based on hunches and suspicions)? If so, how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

罗罗贝儿 2024-08-14 10:42:23

看来这是 Mac 操作系统的一个错误。 JTextFields 在通过键盘选项卡循环获得焦点时选择其内容。如果插入点位于文本的中间,则插入点将保留,并且不会选择整个文本。

作为解决方法,您可以使用以下内容覆盖此行为,它对我来说效果很好:

textfield.setCaret(new DefaultCaret())。

更多详细信息您可以参考这个

Seems this is a bug of Mac OS. JTextFields select their contents when they gain focus though keyboard tab cycling. If the insertion point is in the middle of the text, the insertion point will remain and the entire text will not be selected.

As a workaround you can override this behavior with the following, it works fine for me:

textfield.setCaret(new DefaultCaret()).

More details you can refer to this and this.

辞旧 2024-08-14 10:42:23

要修改默认行为,您可以在初始化 UI 组件之前将系统属性设置为 false: System.setProperty("Quaqua.TextComponent.autoSelect", "false"); 要修改单个组件,您可以使用 JTextField#putClientProperty("Quaqua.TextComponent.autoSelect", Boolean.FALSE);。

您可以在此处找到其他 MacOS L&F 特定属性:

Quaqua 外观和属性感觉-用户指南

To modify the default behaviour, you can set the system property to false before initializing the UI components: System.setProperty("Quaqua.TextComponent.autoSelect", "false"); To modify a single component, you can use JTextField#putClientProperty("Quaqua.TextComponent.autoSelect", Boolean.FALSE);.

You can find other MacOS L&F specific properties here:

Quaqua Look & Feel - User Guide

半窗疏影 2024-08-14 10:42:23

解决方法可能是(我还没有测试过)使插入变量名称的 JList 无法获得焦点。这样,当您单击列表中的项目时,焦点将保留在文本字段中。我建议使用 < JList 上的 code>setRequestEnabled(false),这样,如果您使用 Tab 键定位到它们,它们仍然是可聚焦的,但用鼠标单击它们将不会聚焦它们。

A workaround might be (and I haven't tested this) to make the JList that inserts the variable names unfocusable. That way the focus will remain in the text field when you click on an item in the list. I'd recommend to use setRequestEnabled(false) on the JList, so that they are still focusable if you tab to them, but clicking them with the mouse will not focus them.

原野 2024-08-14 10:42:23

很抱歉添加一个老问题,但我刚刚遇到这个问题并使用了以下代码,这似乎比前面的示例更完整一点:

// 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”函数,因此我在测试中执行了此操作,但它可能不会在所有平台上这样做不会造成任何伤害。

Sorry to add to an old question, but I just came across this problem and used the following code, which seems a little more complete than the previous example:

// 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);
  }
});

This appears to protect the current cursor position or selection. (Note: This code must already run in the event dispatch thread, but you need invokeLater anyway or it doesn't work.)

I have an 'is Mac' function, so I did this inside a test for that, but it probably doesn't do any harm to do it on all platforms.

椵侞 2024-08-14 10:42:23

我在查看 JavaDocs 时注意到 requestFocus()“不鼓励,因为它的行为依赖于平台。”您应该使用 requestFocusInWindow( ) 代替,看看是否会出现同样的问题。

requestFocusInWindow 是 焦点子系统 的一部分,在Java 1.4。

顺便说一句,默认的 Apple 外观和感觉在 apple.laf 命名空间中至少有一个属性:apple.laf.useScreenMenuBar

编辑:根据 Sun 的说法,Macintosh 外观仅适用于 Mac。

I noticed when looking through the JavaDocs that requestFocus() "is discouraged because its behavior is platform dependent." You should use requestFocusInWindow() instead and see if the same problem occurs with it.

requestFocusInWindow is part of the Focus subsystem, introduced in Java 1.4.

On a side note, the default Apple Look and Feel has at least one property in the apple.laf namespace: apple.laf.useScreenMenuBar

Edit: According to Sun, the Macintosh look and feel is only available on Macs.

青丝拂面 2024-08-14 10:42:23

虽然确实比 requestFocus() 更鼓励使用 requestFocusInWindow(),但它在 Mac 上仍然会产生相同的问题行为(例如,突出显示全文字段)。

我开始工作的一种解决方法是在请求焦点后显式设置光标位置:

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

请注意“-1”是必要的,否则它将继续突出显示整个字段。

我很想知道这个解决方案是否独立于平台。这是否会破坏所需的 Linux 或 Windows 行为?

While using requestFocusInWindow() is indeed encouraged over requestFocus(), it still produces the same problematic behavior on Macs (e.g., highlighting of full text field).

One workaround I got to work was to explicitly set the cursor position after requesting focus:

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

Note the "-1" is necessary, otherwise it will continue to highlight the entire field.

I'm curious to know if this solution is platform independent. Does this screw up the desired Linux or Windows behavior?

走过海棠暮 2024-08-14 10:42:23

当字段获得焦点时,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
    }
} );

Mac will select the contents of the text field when the field gains focus. You can restore the state of the text field if you listen for the focus change event.

// 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
    }
} );
捶死心动 2024-08-14 10:42:23

感谢您分享您的想法。我在我的 java 应用程序上遇到了同样的问题,在我的 Windows 系统上没有问题,但在我的 Mac OS X Yosemite 上我无法更改输入。焦点不会停留在 JTextField 上。感谢这个线程我能够解决我的问题。

如果您更改按钮和输入框的外观和感觉,您可以保持焦点并可以再次键入。框架的重置保持标准 Mac OS 外观。

这是我在 java main 方法中使用的代码。如果您想通过主方法中的 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
    }
}

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

Thank you for sharing your ideas. I had the same problem on my java application where on my windows system there wasn't a problem, but on my Mac OS X Yosemite I couldn't change the input. The focus wouldn't stay on the JTextField. Thanks to this thread I was able to fix my problem.

If you change the look and feel of the buttons and input boxes you maintain the focus and you can type again. The reset of the frame stays in the standard Mac OS look.

This is my code that I use in my java main methode. If you want to fix the problem past the try-catch code in your main methode.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文