【问题标题】:What text input component last had the focus?哪个文本输入组件最后获得焦点?
【发布时间】:2011-08-05 20:05:27
【问题描述】:

假设我有一个 Java 应用程序,其中包含多个可以输入文本的组件。现在假设此应用程序还有一个对话框,可让您将单个字符(如从“编辑”菜单中选择“插入”时出现的 Word 中的对话框)插入到这些组件中。您希望它将字符插入最后一个具有焦点的文本组件中。

但是你怎么知道哪个文本组件最后获得了焦点呢?

我可以手动跟踪这一点,方法是让每个文本组件在获得焦点时向应用程序报告,然后让应用程序将新字符插入到最后获得焦点的任何组件中。

但这一定是一个常见问题(考虑工具栏中的粘贴按钮——它如何知道将其粘贴到何处?)。 Swing 中是否已经内置了一些东西,可以让您处理最后一个具有焦点的文本组件?还是我需要自己写?

【问题讨论】:

    标签: java swing text focus


    【解决方案1】:

    Swing 中是否已经内置了一些东西,可以让您获得最后一个获得焦点的文本组件的句柄?

    您创建了一个扩展 TextAction 的 Action。 TextAction 类有一个方法可以让您获取最后一个具有焦点的文本组件。

    编辑:

    您可以创建自己的动作并做任何您想做的事情。然后可以将 Action 添加到任何 JMenuItem 或 JButton。例如:

    class SelectAll extends TextAction
    {
        public SelectAll()
        {
            super("Select All");
        }
    
        public void actionPerformed(ActionEvent e)
        {
            JTextComponent component = getFocusedComponent();
            component.selectAll();
        }
    }
    

    如果您只想在文本字段的插入符号位置插入一个字符,那么您可能只是这样做

    component.replaceSelection(...);
    

    编辑 2:

    我不明白这个答案有什么困惑。这是一个简单的例子:

    1. 选择一些文字
    2. 用鼠标点击复选框
    3. 制表符或使用鼠标单击“剪切”按钮

    当调用 Action 时,文本字段当前没有焦点并不重要。 TextAction 跟踪最后一个具有焦点的文本组件。

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class TextActionTest extends JFrame
    {
        JTextField textField = new JTextField("Select Me");
        JTabbedPane tabbedPane;
    
        public TextActionTest()
        {
            add(textField, BorderLayout.NORTH);
            add(new JCheckBox("Click Me!"));
            add(new JButton(new CutAction()), BorderLayout.SOUTH);
        }
    
        public static void main(String[] args)
        {
            TextActionTest frame = new TextActionTest();
            frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
            frame.pack();
            frame.setLocationRelativeTo( null );
            frame.setVisible(true);
         }
    
        class CutAction extends TextAction
        {
            public CutAction()
            {
                super("Click to Cut Text");
            }
    
            public void actionPerformed(ActionEvent e)
            {
                JTextComponent component = getFocusedComponent();
    //          JTextComponent component = getTextComponent(e);
                component.cut();
            }
        }
    }
    

    【讨论】:

    • 在某处是否有关于此的更多详细信息?看起来 DefaultEditorKit.InsertContentAction 可能是我需要的,但是上面的 javadoc 不是很有帮助。
    • 这很有帮助。但是如何将 Action 添加到 JButton 中?
    • @Paul Reiners - 使用方法addActionListener( new "concrete listener")
    • 那是添加ActionListener,不是添加Action。您可以将 Action 添加到 JMenu,但不能添加到 JButton。
    • 当然可以使用带有 JButton 的 Action。查看 API。您是否在方法名称或构造函数中搜索过任何带有“动作”的内容?不要忘记父类。
    【解决方案2】:

    我从未直接这样做过,但您可以查看 FocusEvents 和 Focus Subsystem

    希望焦点子系统中有一些东西可以触发您可以监听的事件。

    【讨论】:

      【解决方案3】:

      您可以为每个文本组件注册一个FocusListenerFocusEvent 对象引用了最后一个具有焦点的组件。

      【讨论】:

      • 不——除了最琐碎的应用程序之外,你当然不想在任何事情上这样做;-)
      【解决方案4】:

      就像@lesmana 建议的那样(为此+1)。 这里有一个示例,它显示在 focusLost 上,焦点侦听器返回先前聚焦的组件。

      import java.awt.event.FocusEvent;
      import java.awt.event.FocusListener;
      import javax.swing.JComponent;
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.JTextField;
      
      public class Focusing
      {
          public static void main(String[] args)
          {
              JPanel p = new JPanel();
              JTextField tf1 = new JTextField(6);
              tf1.setName("tf1");
              p.add(tf1);
              JTextField tf2 = new JTextField(6);
              tf2.setName("tf2");
              p.add(tf2);
              FocusListener fl = new FocusListener()
              {
                  @Override
                  public void focusGained(FocusEvent e)
                  {
                      System.out.println("focusGained e.getSource().c=" + ((JComponent) e.getSource()).getName());
                  }
      
                  @Override
                  public void focusLost(FocusEvent e)
                  {
                      System.out.println("focusLost e.getSource().c=" + ((JComponent) e.getSource()).getName());
                  }
              };
              tf1.addFocusListener(fl);
              tf2.addFocusListener(fl);
              JPanel contentPane = new JPanel();
              contentPane.add(p);
              JFrame f = new JFrame();
              f.setContentPane(contentPane);
              f.setSize(800, 600);
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              f.setVisible(true);
          }
      }
      

      一切顺利,波罗。

      【讨论】:

      • -1,最后一段基本上是在询问“对粘贴功能的内置支持如何工作”。这并没有回答问题,并且已经给出了答案。无需尝试重​​新发明轮子。
      • @camickr 我不认为你的观点是有效的,考虑到最后一段“Swing 中是否已经内置了一些东西,可以让你处理最后一个具有焦点的文本组件?”。我的示例展示了如何获取最后获得焦点的文本组件。因此,它至少回答了部分问题。另外,我看不到我是如何重新发明轮子的?我只是展示了解决相同问题的不同方法。在我看来,这样做并没有什么不好。
      • 您仍然没有抓住问题的重点。问题是 Swing 如何处理“粘贴”操作,因为您不必在每个文本组件上添加 FocusListener 即可获得默认行为。发帖人希望对他的特殊处理采用相同的方法。 Swing 被设计为使用 Actions,而文本组件被设计为使用 TextAction 的。您正在尝试使用 TextAction 的 FocusListener 重新创建轮子。
      • 我投了反对票,因为您的回答是在我的回答之后给出的,这表明您没有阅读我的回答或理解我的回答,并且您不了解 Swing 的工作原理。如果您在我之前发过帖子,我会就更好的方法发表评论,希望每个人都能学到新的东西。
      • @camickr 我明白你的意思。我只是想在这里展示一种不同的方法。我不同意你对我的知识、思想的大胆陈述。我认为,既然你有听众为什么不使用它们,它们并没有被弃用或其他任何东西。我同意您的方法更好,因为它更易于重用。我仍然可以看到情况,您完全正确,不是针对该用户的特定问题,使用侦听器将是唯一的选择。万事如意
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多