错误的组件(在单独的 JPanel 类中)获得焦点

Posted

技术标签:

【中文标题】错误的组件(在单独的 JPanel 类中)获得焦点【英文标题】:Wrong Component (in seperate JPanel class) gets focus 【发布时间】:2018-03-29 23:49:18 【问题描述】:

我正在开发一个具有以下结构的应用程序:

    FrmMain(其中包含我要添加“布局”面板的面板) PnlNewCase(设置为接收区域特定面板的“布局”面板) PnlNewCaseNotes(添加到 PnlNewCase 的面板之一) PnlNewPartsSelection我存在的祸根

我的想法是,每当我在 PnlNewPartsSelection 中创建一个新页面时,只要它被实例化,就将焦点放在一个特定的 JTextField (tfNom) 上,但每当我尝试这样做时,焦点就会完全设置到另一个 JTextField (tfAddressDetails)。

What I want in focus (in blue) vs what gets focus (in red)

我已经尝试调试整个事情,但无法确定需要做什么。我也尝试使用更简单的代码重现该问题,但在这种情况下它可以工作。两者之间唯一显着的区别是简化代码仅由 JFrame 和 JPanel 组成,而更复杂的代码包含: JFrame -> JTabbedPane -> Jpanel -> Jpanel 所以我想知道这是否没有链接到 JTabedPane以某种方式与 JPanel 或 JPanel 与 JPanel 交互。

以下是我正在使用的方法的概要,希望可以帮助人们弄清楚发生了什么。

JFrame FrMain:

private void btnNewRepActionPerformed(java.awt.event.ActionEvent evt) 
    tabs.addTab("R" + tabNo++, p);
    tabs.setSelectedIndex(tabNo);

JPanel PnlNewCase:

public PnlNewCase(boolean isNewRep) 
    initComponents();
    checkRepStatus(isNewRep);



private void checkRepStatus(boolean isNewRep) 
    if (isNewRep) 
        btnNewNote.setVisible(false);
        PnlNewCaseNotes p1 = new PnlNewCaseNotes();
        pnlNotes.add(p1);
        PnlNewPartsSelection p2 = new PnlNewPartsSelection();      
        JTextField t = p2.getTfNom();
        pnlPartsCustomer.add(p2);
        t.requestFocusInWindow();
        validate();
    

JPanel PnlNewCaseNotes:

public PnlNewCaseNotes() 
    initComponents();

JPanel PnlNewPartsSelection:

public PnlNewPartsSelection() 
    initComponents();


/* A bunch of method calls to add place holders */

public JTextField getTfNom() 
    return tfNom;

如果需要,我也可以发布每个类的代码(我只是认为这应该足够了)。

期待你们的 cmets :)

【问题讨论】:

当您呼叫t.requestFocusInWindow() 时,屏幕上不太可能出现PnlNewCase 的实体,这会使呼叫静音。你需要先在 UI 上实现PnlNewCase,然后再进行重定向控制。也许在你打电话给add(和revalidate/repaint)之后,打电话给requestFocusInWindow ...你可能会发现你需要使用SwingUtilities.invokeLater才能让它工作 【参考方案1】:

退后一步,浏览您的代码。假设您正在做类似的事情

add(new PnlNewCase(true));

如果您浏览代码,您会发现它调用:

PnlNewCase 构造函数(为实例字段分配默认值) initComponents checkRepStatus。此时您开始构建代码并调用t.requestFocusInWindow 调用addPnlNewCase 的新实例传递给容器

这就是核心问题。当您调用t.requestFocusInWindow 时,组件本身或它所附加到的容器都没有添加到 UI 中,因此无法为该字段提供焦点。

相反,将组件添加到 UI,然后将焦点请求到该字段。由于框架的方式,您可能会发现您还需要使用SwingUtilities.invokeLater 来使焦点起作用

也许做一些类似...

    public class PnlNewCase extends JPanel 

        private PnlNewPartsSelection p2;

        public PnlNewCase(boolean isNewRep) 
            //...
        

        private void checkRepStatus(boolean isNewRep) 
            if (isNewRep) 
                //...
                p2 = new PnlNewPartsSelection();
                //...
                //t.requestFocusInWindow();
            
        

        public void focusPrimaryField() 
            SwingUtilities.invokeLater(new Runnable() 
                @Override
                public void run() 
                    p2.getTfNom().requestFocusInWindow();
                
            );
        
    

然后你可以简单地做类似...

PnlNewCase newCase = new PnlNewCase(true);
add(newCase);
revalidate();
repaint();
newCase.focusPrimaryField()

作为一个总体思路。

您可能还想看看How to Use the Focus Subsystem 以获得更好的理解,也许还有更多的想法

【讨论】:

感谢您花时间回答我的问题!您帮助我了解了问题所在,对此我表示感谢。另一方面,我无法理解最后一段代码将如何发挥作用。特别是 newCase.focusPrimaryField() 调用。据我了解,您将 focusPrimaryField() 方法添加到 PnlNewCase 类,但我不知道最后一个片段应该在哪里。 FrmMain ? 这个想法是延迟请求焦点,直到你可以更好地保证在屏幕上建立 ui 的时间 这里的重要部分是建立的UI(组件被添加,如果可能的话,在屏幕上实现)。您可以在setVisible 之前添加对focusPrimaryField 的调用,它“可能”工作,但如果可能的话,在setVisible 调用之后添加它可能会更安全 因为我的结构是选项卡创建、主面板附加、上下文面板附加,所以我尝试在选项卡创建过程结束时添加对focusPrimaryField(在 PnlNewCase 中找到)的调用对应于返回根调用,但它没有工作。我可能无法准确理解您建议我对您发布的内容做什么。此外,我还求助于一些年长且经验丰富的同行,他们建议我使用自定义遍历策略,我尝试过但没有采用。

以上是关于错误的组件(在单独的 JPanel 类中)获得焦点的主要内容,如果未能解决你的问题,请参考以下文章

将单独类中的多个组件添加到另一个类中的 JFrame

如何在另一个类中的 JPanel 类中实现 ActionListener?

小程序---- input获得焦点时placeholder重影BUG

C#如何在中间层类中抛出异常时获得控制焦点

当 UITextField 获得焦点时,从 UITableViewCell 继承类中更改 UITableViewCell 的高度

组件化2 创建选项卡对象