在重量级弹出窗口中,JTextField没有焦点

时间:2018-02-02 13:08:35

标签: java swing popup

我想在弹出窗口中显示文本。当弹出窗口完全覆盖应用程序框架(MediumWeightPopup)时 - 一切正常,但当弹出窗口的一部分在框架外(HeavyWeightPopup)时,它无法聚焦。在这种情况下,插入符号是不可见的,无法输入文本。

这是我的代码:

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class PopupTest {

    public static void main(String[] args) {
        JFrame frm = new JFrame("Popup test");
        JPanel p = new JPanel();
        p.addMouseListener(new MouseAdapter() {
            Popup pop;
            @Override
            public void mouseReleased(MouseEvent e) {
                if (SwingUtilities.isRightMouseButton(e)) {
                    if (pop != null) {
                        pop.hide();
                    }
                    JPanel popupPanel = new JPanel(new BorderLayout());
                    JTextField field = new JTextField(20);
                    popupPanel.add(field);
                    pop = PopupFactory.getSharedInstance().getPopup(p, popupPanel, e.getXOnScreen(), e.getYOnScreen());
                    pop.show();
                    System.out.println("Popup type: " + pop.getClass().getName());
                    System.out.println("Can get focus? " + field.requestFocusInWindow());
                }
            }
        });
        frm.add(p);
        frm.setSize(500, 300);
        frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frm.setLocationRelativeTo(null);
        frm.setVisible(true);
    }
}

右键单击窗口的右边界,我得到一个不可聚焦的文本字段。我在弹出窗口中允许键控制的任何其他组件(例如JTable)也遇到了同样的问题。

如何将组件集中在HeavyWeightPopup中?

2 个答案:

答案 0 :(得分:3)

多年前我也在努力奋斗。我无法弄清楚如何将初始焦点放在弹出窗口上的组件上。以下是我的一些问题/意见:

  

Popup类用于什么?

     

我一直认为Popup应该具有一些基本功能,例如pupup应该在以下时间关闭:

     

a)按下退出键   b)弹出窗口失去焦点

     

弹出类没有提供上述功能,实际上似乎需要一些模糊的代码才能使键盘焦点正常工作。

     

使用JWindow似乎提供与Popup相同的功能。

     

JPopupMenu似乎支持上述两个要求。

     

运行以下程序:

     

a)单击每个按钮   b)单击框架的空白部分

在我看来,无论何时需要“弹出窗口”,都应使用JPopupMenu

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

public class PopupTest extends JFrame
{
    String[] numbers = { "one", "two", "three", "four", "five" };

    public PopupTest()
    {
        getContentPane().setLayout( new FlowLayout() );
        getContentPane().setBackground(Color.YELLOW);

        JButton popup = new JButton("Popup as Popup");
        popup.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                popupPopup(e);
            }
        });
        getContentPane().add(popup);
        JButton window = new JButton("Window as Popup");
        window.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                windowPopup(e);
            }
        });
        getContentPane().add(window);

        JButton menu = new JButton("PopupMenu as Popup");
        menu.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                menuPopup(e);
            }
        });
        getContentPane().add(menu);
    }

    private void popupPopup(ActionEvent e)
    {
        JList list = new JList(numbers);
        list.setSelectedIndex(0);

        PopupFactory factory = PopupFactory.getSharedInstance();
        Popup popup = factory.getPopup(this, list, getLocation().x, getLocation().y+100);
        //popup.show();

        Window window = SwingUtilities.windowForComponent(list);

        if (window != null)
        {
            window.setFocusableWindowState(true);
        }

        popup.show();
        KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(list);
    }

    private void windowPopup(ActionEvent e)
    {
        JList list = new JList(numbers);
        list.setSelectedIndex(0);

        JWindow window = new JWindow(this);
        window.getContentPane().add(list);
        window.pack();
        window.setVisible(true);
        window.setLocation(getLocation().x + 200, getLocation().y+100);

        window.addWindowListener( new WindowAdapter()
        {
            public void windowDeactivated(WindowEvent e)
            {
                System.out.println("deactivated");
            }
        });
    }

    private void menuPopup(ActionEvent e)
    {
        JList list = new JList(numbers);
        list.setSelectedIndex(0);

        JPopupMenu menu = new JPopupMenu();
        menu.add( new JTextField(10) );
        menu.add( list );

        menu.show((Component)e.getSource(), 0, 100);
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new PopupTest();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(500, 200);
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

编辑:

根据Sergiy的回答,这段代码接近工作。 popupPopup()方法的不同之处在于,在窗口可调焦后需要调用show()方法。代码已更新以反映此更改。

答案 1 :(得分:1)

源代码分析为我带来了另一种解决方案

pop = PopupFactory.getSharedInstance().getPopup(p, popupPanel, e.getXOnScreen(), e.getYOnScreen());
// some new stuff
Window win = SwingUtilities.windowForComponent(popupPanel);
if (win instanceof JWindow && win.getType() == Window.Type.POPUP) {
    win.setFocusableWindowState(true);
}
// continue old stuff
pop.show();

所以完整的例子看起来像是

import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class PopupTest {

    public static void main(String[] args) {
        JFrame frm = new JFrame("Popup test");
        JPanel p = new JPanel();
        p.addMouseListener(new MouseAdapter() {
            Popup pop;
            @Override
            public void mouseReleased(MouseEvent e) {
                if (SwingUtilities.isRightMouseButton(e)) {
                    if (pop != null) {
                        pop.hide();
                    }
                    JPanel popupPanel = new JPanel(new BorderLayout());
                    JTextField field = new JTextField(20);
                    popupPanel.add(field);
                    pop = PopupFactory.getSharedInstance().getPopup(p, popupPanel, e.getXOnScreen(), e.getYOnScreen());
                    Window win = SwingUtilities.windowForComponent(popupPanel);
                    if (win instanceof JWindow && win.getType() == Window.Type.POPUP) {
                        win.setFocusableWindowState(true);
                    }
                    pop.show();
                    System.out.println("Popup type: " + pop.getClass().getName());
                    System.out.println("Can get focus? " + field.requestFocusInWindow());
                }
            }
        });
        frm.add(p);
        frm.setSize(500, 300);
        frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frm.setLocationRelativeTo(null);
        frm.setVisible(true);
    }
}

有趣:调用field.requestFocusInWindow()仍然返回false,但是无论如何字段都会获得焦点。

BTW :此解决方案对我来说也更好,因为在我的真实代码中,我从JComboBox获取弹出窗口(我的目标是使用表格创建JTableComboBox弹出窗口和表格顶部的可选过滤字段。)