【问题标题】:give focus to a panel that is not a child of the focused Window?将焦点放在不是焦点窗口子级的面板上?
【发布时间】:2011-09-28 23:42:14
【问题描述】:

我正在使用 Java 创建一个内部工具。这两个由两个JPanels 组成,预计将在两个单独的屏幕上运行。我希望能够单击JButton,它是JFrame A 的一部分,它将向JFrame B 发送键盘操作。

不幸的是,我似乎无法这样做,因为JFrame B 没有焦点,并且我不能使用任何请求Focus 方法,因为JFrame B 不是Focus Window 的孩子( JFrame A 是)。

那么,尽管JFrame B 不是Focus Window 的子对象,但我如何才能给予焦点,或者将Keyboard Events 发送到JFrame B,它会在没有焦点的情况下做出响应?

【问题讨论】:

  • 为什么要这样做?如果您能够向其发送键盘事件,您难道不能让事件侦听器(或按钮操作)执行框架 B 会执行的任何操作吗?
  • 如果两个框架在同一个应用程序中,为什么要向另一个框架发送键盘事件?你在做某种测试自动化吗?
  • 是的,这是为了测试自动化。我也在使用关键事件,因为我试图重用从框架继承的功能,而不是重新发明轮子。

标签: java swing user-interface focus


【解决方案1】:

很难在两个JFrames 之间管理焦点,最好只创建一个JFrame 而其他Top-level Containers 将是JDialogs,创建一个/两个JDialog(s) 并通过删除所有JComponents 来重用它

基本上是这样的:

EventQueue.invokeLater(new Runnable() {

   @Override
     public void run() {
         someComponent.grabFocus();
         someComponent.requestFocus();//or inWindow depends if Swing or Awt
     }
});

但是两个 JFrame 之间的事情有点复杂,只是基本的和未完成的示例(基于 old.good.sun.forums.com 的代码)

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PMDialog extends JDialog {

    private static final long serialVersionUID = 1L;
    private boolean modal = false;
    private WindowAdapter parentWindowListener;
    private Window owner;
    private JFrame blockedFrame = new JFrame("Blocked Frame");
    private JFrame noBlockedFrame = new JFrame("No Blocked Frame");

    public PMDialog() {
        noBlockedFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        noBlockedFrame.getContentPane().add(new JButton(new AbstractAction("Test button") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent evt) {
                System.out.println("Non blocked button pushed");
                /*if (blockedFrame.isVisible()) {
                noBlockedFrame.setVisible(false);
                } else {
                blockedFrame.setVisible(true);
                }*/
                noBlockedFrame.setVisible(true);
                blockedFrame.setVisible(true);
            }
        }));
        noBlockedFrame.setSize(200, 200);
        noBlockedFrame.setVisible(true);
        blockedFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        blockedFrame.getContentPane().add(new JButton(new AbstractAction("Test Button") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent evt) {
                final PMDialog pmd = new PMDialog(blockedFrame, "Partial Modal Dialog", true);
                pmd.setSize(200, 100);
                pmd.setLocationRelativeTo(blockedFrame);
                pmd.getContentPane().add(new JButton(new AbstractAction("Test button") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void actionPerformed(ActionEvent evt) {
                        System.out.println("Blocked button pushed");
                        pmd.setVisible(false);
                        blockedFrame.setVisible(false);
                        noBlockedFrame.setVisible(true);
                    }
                }));
                pmd.setDefaultCloseOperation(PMDialog.DISPOSE_ON_CLOSE);
                pmd.setVisible(true);
                System.out.println("Returned from Dialog");
            }
        }));
        blockedFrame.setSize(200, 200);
        blockedFrame.setLocation(300, 0);
        blockedFrame.setVisible(false);
    }

    public PMDialog(JDialog parent, String title, boolean isModal) {
        super(parent, title, false);
        initDialog(parent, title, isModal);
    }

    public PMDialog(JFrame parent, String title, boolean isModal) {
        super(parent, title, false);
        initDialog(parent, title, isModal);
    }

    private void initDialog(Window parent, String title, boolean isModal) {
        owner = parent;
        modal = isModal;
        parentWindowListener = new WindowAdapter() {

            @Override
            public void windowActivated(WindowEvent e) {
                if (isVisible()) {
                    System.out.println("Dialog.getFocusBack()");
                    getFocusBack();
                }
            }
        };
    }

    private void getFocusBack() {
        Toolkit.getDefaultToolkit().beep();
        super.setVisible(false);
        super.pack();
        super.setLocationRelativeTo(owner);
        super.setVisible(true);
        super.toFront();
    }

    @Override
    public void dispose() {
        owner.setEnabled(true);
        owner.setFocusableWindowState(true);
        super.dispose();
    }

    @Override
    @SuppressWarnings("deprecation")
    public void hide() {
        owner.setEnabled(true);
        owner.setFocusableWindowState(true);
        super.hide();
    }

    @Override
    public void setVisible(boolean visible) {
        boolean blockParent = (visible && modal);
        owner.setEnabled(!blockParent);
        owner.setFocusableWindowState(!blockParent);
        super.setVisible(visible);
        if (blockParent) {
            System.out.println("Adding listener to parent ...");
            owner.addWindowListener(parentWindowListener);
            try {
                if (SwingUtilities.isEventDispatchThread()) {
                    System.out.println("EventDispatchThread");
                    EventQueue theQueue = getToolkit().getSystemEventQueue();
                    while (isVisible()) {
                        AWTEvent event = theQueue.getNextEvent();
                        Object src = event.getSource();
                        if (event instanceof ActiveEvent) {
                            ((ActiveEvent) event).dispatch();
                        } else if (src instanceof Component) {
                            ((Component) src).dispatchEvent(event);
                        }
                    }
                } else {
                    System.out.println("OUTSIDE EventDispatchThread");
                    synchronized (getTreeLock()) {
                        while (isVisible()) {
                            try {
                                getTreeLock().wait();
                            } catch (InterruptedException e) {
                                break;
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                System.out.println("Error from EDT ... : " + ex);
            }
        } else {
            System.out.println("Removing listener from parent ...");
            owner.removeWindowListener(parentWindowListener);
            owner.setEnabled(true);
            owner.setFocusableWindowState(true);
        }
    }

    @Override
    public void setModal(boolean modal) {
        this.modal = modal;
    }

    public static void main(String args[]) {
        PMDialog pMDialog = new PMDialog();
    }
}

编辑:对于如何将焦点添加到 JDialog,camickr Dialog Focus 是否有出色的 Woodoo,但 AncestorListener 不是我的 Java 杯,对我来说太抽象了

【讨论】:

    【解决方案2】:

    这是一个 Swing GUI(你没有提到或添加标签到 gui 库)?如果是这样,请考虑使用Key Bindings,与 KeyListeners 相比,它可以更灵活地关注焦点。

    【讨论】:

    • 不幸的是,我看不到如何使用键绑定。我想要的键绑定已经存在并为 Frame B 开发。这个面板实际上是一个更复杂结构的一部分,它继承了我试图从我无法触及的部分框架中利用的功能。我的问题不在于绑定键,而是按下按钮生成我需要的 keyEvents。我知道我可以做到这一点,如果我能把焦点放在我的“B 帧”上
    【解决方案3】:

    没有什么说你不能让Action 向另一个人发送消息。在这个exampleEnter也需要Clear,所以转发ActionEvent。另请注意,每个NumberButton 将两次击键绑定到Click。在您的情况下,您可能必须删除现有绑定,并可能在另一个窗口上调用 toFront()。请注意支持@mKorbel 回答的注意事项。

    【讨论】:

    • hmmm 看起来就像我喜欢你的 Kinetic...,我的懒惰不允许我写出如此复杂的东西,我的最后一个脑细胞因运行此代码而死亡,+1跨度>
    • @mKorbel:谢谢!,对不起脑细胞。 :-) 我欢迎任何批判性见解。可悲的是,KineticModel 充满了邪恶,可变的org.gcs.kinetic.Vector
    • 非常好,如果我说我喜欢,那么一些评论家嗯...原子在 5 或 6 次点击时减少??第一次点击返回 Bals 的初始数量,更大的 Atom 与更小的 Atom 具有相同的动力学加速度,也许对于某人闪烁橙色脂肪边框,但它不会打扰我
    猜你喜欢
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多