【问题标题】:Focus issues with java7 modal dialogs on mac osxmac osx 上 java7 模态对话框的焦点问题
【发布时间】:2012-09-05 09:41:10
【问题描述】:

我一直在验证一个在 mac osx 的小程序上运行的 swing 应用程序。

在此验证过程中,我发现模式对话框存在以下问题:

  1. 当对话框打开并且设置为 setModal(true) 时,它会阻止根窗口的内容,但是如果您单击根窗口上的某个位置,对话框会在它下方,但它应该保留在根窗口的顶部.
  2. 如果对话框有 JTextInputField,即使单击它也不会获得焦点。

所以我创建了一个小程序来显示问题。你能帮我理解这里有什么问题吗?

package com.macosx.tests;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class DialogExample extends JApplet{

    private static final long serialVersionUID = 1L;
    private JPanel panel;
    private JButton openDialogBtn;

    private void doStart() {
        panel = new JPanel();
        panel.setPreferredSize(new Dimension(500,500));

        openDialogBtn = new JButton("open dialog");
        openDialogBtn.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent arg0) {
                ModalDialog dialog = new ModalDialog(panel, true);
                dialog.setVisible(true);
            }

        });
        panel.add(openDialogBtn);
        setContentPane(panel);
    }


    class ModalDialog extends JDialog {
        private static final long serialVersionUID = 1L;

        public ModalDialog(Component parent, boolean modal) {
            Dimension dimensionParentFrame = parent.getSize();
            setSize(new Dimension((parent == null) ? 300 : dimensionParentFrame.width / 2, 75));

            setModal(modal);
            setModalityType(ModalityType.APPLICATION_MODAL);

            JTextField txtField = new JTextField();
            add(txtField, BorderLayout.CENTER);
        }
    }


    @Override
    public void start() {
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    doStart();
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

使用上述创建一个 .jar 文件(test.jar)。完成后,创建一个包含以下内容的 html 文件:

<html>
<head>
<title>Dialog test Applet</title>
</head>
<body>
<applet id="DialogTestApplet" height="800" width="600"
  code="com.macosx.tests.DialogExample"
  archive="test.jar">
</applet>
</div>
</body>
</html>

完成后,运行 html 文件。您将看到一个带有灰色背景和一个按钮的小程序。然后尝试:

  1. 点击按钮打开对话框。之后,单击灰色区域的某处:对话框位于浏览器窗口下方,但它应该保留在顶部,对吧?
  2. 点击按钮打开对话框。之后单击对话框的文本字段并尝试编写一些内容:文本对话框没有获得焦点。

那么,我在这里做错了什么?请问有mac电脑的人可以测试一下吗?

谢谢

规格:

java.vendor    Oracle Corporation
java.version   1.7.0_07
os.name        Mac OS X
os.version     10.7.4

browser        firefox 15

注意:请注意,这仅在小程序在浏览器上运行且仅在 mac osx 上运行时才会发生。

【问题讨论】:

  • 无法在 10.5/1.6 上重现。
  • 对我来说,使用 10.7/1.6.0_33 我仍然看到模态问题(1)但没有看到焦点问题(2)。
  • 类似问题,但在 ubuntu stackoverflow.
  • 我上周报告了这个错误,但我只提到了 mac osx。在这里查看:bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196264。也许您应该投票/评论,看看他们是否对此有所作为。优先级很低,因为他们改变了它......
  • 好消息!我刚刚在oracle中输入了bug的链接。他们与8001161 的其他未解决问题相关。此问题已解决,将在即将推出的 7u14 上提供。

标签: java macos swing applet modal-dialog


【解决方案1】:

我找到了另一种解决方法。当窗口打开时,显示一个选项窗格几毫秒然后关闭它。它将焦点放在选项窗格上,然后返回对话框,允许忽略错误。

将这段代码添加到您的对话框构造函数中,它应该可以工作:

addWindowListener(new WindowAdapter(){
public void windowOpened(WindowEvent e){
    JOptionPane pane = new JOptionPane();
    final JDialog dialog = pane.createDialog("Please Wait");
    Timer timer = new Timer(50, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            dialog.dispose();
        }
    });
timer.setRepeats(false);
timer.start();
dialog.setVisible(true);
}

【讨论】:

  • 你可以试试隐形对话框:final JDialog dialog = new JDialog(); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setUndecorated(true); dialog.setModal(true);
【解决方案2】:

您应该在 ModalDialog 上放置一个“所有者”窗口。为此,您必须在 ModalDialog 构造函数中调用 super(owner),并且您可以使用 SwingUtilities.getWindowAncestor(parent) 检索组件 parent 的父窗口。

【讨论】:

  • 感谢您的建议。我刚试过你提到的,但结果是一样的......
  • @LuisGonçalves 尝试发布 SSCCE 而无需使用小程序。
  • 为什么不直接将代码复制到 Eclipse,然后选择 Run As -> Java Applet。这将运行小程序,您将看到它正在运行。但正如我在注释中提到的:这个问题只发生在我们在浏览器上运行小程序时,这正是我感兴趣的让它工作的方式。
【解决方案3】:
  • 不是 Mac/OSX 用户,但这是 FocusJDialog 的常见问题,

  • 在运行时创建JDialog的情况下还有一个问题,

  • Focus 是异步的,基于来自Native OS 的属性

  • 只创建一次这个JDialog,然后re_use这个container进行另一个操作

  • JDialog#setVisible 也应该被包裹到 invokeLater()

  • 可以通过JTextField#setText(JTextField#getText()) 强制将Focus 包装成invokeLater()

  • Dialog Focus,@camickr 提供的一种很好的解决方法

【讨论】:

  • 我将做一些代码更改以包含 dos 建议,看看它们是否能解决问题。顺便提一下,如果你在 windows 上运行相同的代码,就不会出现任何问题。
  • @Luis Gonçalves 这个常见问题也出现在 Win、**nix 和 OSX 平台上的最复杂的 GUI 中,只有 hack 可以帮助您
  • 你真的在 Windows 上运行过它吗?!因为,如果我在我的 Windows 机器上运行它,我看不到任何问题......
  • 部分同意容器中只有一个JComponents,但我说的是最复杂的GUI(请仔细阅读camickr链接代码中的描述),GUI包含一堆@987654337 @ 并且您需要 setFocusJTextFieldJButton 中的一些,默认情况下是第一个。 JComponent 是 fosusable,重要的线索是 JTextField#setText(JTextField#getText())AncesorListener 是否有效,因为这个问题来自 Java5
  • 如果是复杂的图形用户界面,为什么不适合这个小例子呢?老实说,我认为这是 Mac os x 的 JRE7 中的一个错误。例如,我尝试了 Camickr 使用 JOptionPane 提供的示例。他说:'在这种情况下,如果您运行上述代码,您会注意到焦点位于“是”按钮上'。仅当您运行浏览器的小程序 OUT 时才适用。当您在浏览器上运行小程序时,所创建对话框的任何组件都不会成为焦点。
【解决方案4】:

我确认,我在 OS X 的 JDK7 中运行的旧小程序存在相同的错误。正如海报所提到的,只有在浏览器 (ff) 中运行的小程序才能看到该错误,而不是 appletviewer。

【讨论】:

【解决方案5】:

我可以验证这是 Safari 6 上的 Java 1.7 Update 7+ 和 Mountain Lion 上运行的 Firefox 的问题。奇怪的是,在 Lion 上运行的早期版本的 Safari 上这不是问题,但在旧操作系统上的 Firefox 中却是一个问题。我非常渴望找到解决此问题的方法,因为我的许多 applet 用户都在 Mac 上。我发现的一种解决方法(无论如何都不够)是缩小窗口然后重新打开它。然后文本字段/文本区域变得可编辑。希望我们能找到更好的解决方案来解决这个烦人的要求。

【讨论】:

    【解决方案6】:

    我在 Mac 上使用 Safari 和 Firefox 的 Java 7 update 9 遇到了同样的问题。当我打开一个包含 JTextField 的 JDialog 时,无法访问 JTextField。

    我确实找到了解决方案。我插入了从用户按下“显示对话框按钮”到执行显示按钮的代码的延迟。

    例如:

    ActionListener al = new ActionListener(){
        public void actionPerformed(ActionEvent ae){
            TitleDialog dialog = new TitleDialog(main.findParentFrame()); // My JDialog which contains a JTextField.
            dialog.setVisible(true);
        }
    };
    javax.swing.Timer timer = new javax.swing.Timer(1000, al);
    timer.setRepeats(false);
    timer.start(); 
    

    我的经验是,如果要缩短延迟,解决方案将不起作用。

    如果使用SwingUtilities.invokeLater 而不是javax.swing.Timer,它将无法正常工作。可能SwingUtilities.invokeLater的延迟太短了。

    【讨论】:

      【解决方案7】:

      我发现了另一种解决方法。当从 JavaScript 调用 JDialog 时,它有一个焦点。

      1. 创建一个将显示对话框的小程序方法
      2. 从 JavaScript 调用此方法。

      希望,它会有所帮助。顺便说一句,Java 教程中的 web start 示例也有同样的问题 http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html

      【讨论】:

        【解决方案8】:

        我想使用上面的解决方法(从对话框中打开对话框),但不显示任何对话框。 这是不可见对话框的代码。

        final JDialog dialog = new JDialog();
        dialog.setUndecorated(true);
        dialog.setSize(0, 0);
        dialog.setModal(true);
        dialog.pack();
        

        【讨论】:

          【解决方案9】:

          我找到了解决办法。

          GetDirectory varGetDirectory = new GetDirectory(new JFrame(),true);
          varGetDirectory.setVisible(true);       
          

          GetDirectory 是包含 JFileChooser 的 JDialog。

          奇怪的是,所有的 JDialog 对象都应该使用 new JFrame() 作为父级来调用,否则从一个父级窗口单击,会将顶部模态 JDialog 带到 zOrder 中,并且不知何故它不能再设置在顶部了。

          我的问题和上面一样。当我从另一个 JDialog 创建 JDialog 时,新对话框出现在另一个之后。

          为了把它放在首位,我已经如上所述设置了所有 JDialogs 的父级,它按照预期工作。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-30
            • 2010-10-29
            • 2012-04-12
            • 2016-03-06
            • 2011-01-10
            • 2020-07-20
            相关资源
            最近更新 更多