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

Java 错误的组件(在单独的JPanel类中)获得焦点,java,swing,focus,components,setfocus,Java,Swing,Focus,Components,Setfocus,我正在开发一个具有以下结构的应用程序: FrmMain(其中包含我要添加“布局”面板的面板) PnlNewCase(设置为接收区域特定面板的“布局”面板) PnlNewCaseNotes(添加到PnlNewCase的面板之一) pnlnewparts选择(我存在的祸根) 我的想法是,每当我在PnlNewPartsSelection中创建一个新页面时,每当它被实例化时,我都会聚焦一个特定的JTextField(tfNom),但每当我尝试这样做时,焦点都会被设置为另一个JTextField(tfAd

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

  • FrmMain(其中包含我要添加“布局”面板的面板)
  • PnlNewCase(设置为接收区域特定面板的“布局”面板)
  • PnlNewCaseNotes(添加到PnlNewCase的面板之一)
  • pnlnewparts选择(我存在的祸根)
  • 我的想法是,每当我在PnlNewPartsSelection中创建一个新页面时,每当它被实例化时,我都会聚焦一个特定的JTextField(tfNom),但每当我尝试这样做时,焦点都会被设置为另一个JTextField(tfAddressDetails)

    我已经试着调试了整件事,但还不能确定需要做什么。我还尝试使用一个更简单的代码重现这个问题,但在这种情况下,它是有效的。两者之间唯一值得注意的区别是,简化的代码只包含一个JFrame和一个JPanel,而更复杂的代码包含:JFrame->JTabbedPane->JPanel->JPanel,所以我想知道这是否与JTabedPane-to-JPanel或JPanel-to-JPanel的交互联系在一起

    下面是我正在使用的方法的概要,我希望这些方法能帮助人们弄清楚到底发生了什么

    JFRMAIN:

    private void btnNewRepActionPerformed(java.awt.event.ActionEvent evt) {
        tabs.addTab("R" + tabNo++, p);
        tabs.setSelectedIndex(tabNo);
    }
    
    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();
        }
    }
    
    public PnlNewCaseNotes() {
        initComponents();
    }
    
    public PnlNewPartsSelection() {
        initComponents();
    }
    
    /* A bunch of method calls to add place holders */
    
    public JTextField getTfNom() {
        return tfNom;
    }
    
    JPanel PnlNewCase:

    private void btnNewRepActionPerformed(java.awt.event.ActionEvent evt) {
        tabs.addTab("R" + tabNo++, p);
        tabs.setSelectedIndex(tabNo);
    }
    
    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();
        }
    }
    
    public PnlNewCaseNotes() {
        initComponents();
    }
    
    public PnlNewPartsSelection() {
        initComponents();
    }
    
    /* A bunch of method calls to add place holders */
    
    public JTextField getTfNom() {
        return tfNom;
    }
    
    JPanel pnlnewcase注释:

    private void btnNewRepActionPerformed(java.awt.event.ActionEvent evt) {
        tabs.addTab("R" + tabNo++, p);
        tabs.setSelectedIndex(tabNo);
    }
    
    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();
        }
    }
    
    public PnlNewCaseNotes() {
        initComponents();
    }
    
    public PnlNewPartsSelection() {
        initComponents();
    }
    
    /* A bunch of method calls to add place holders */
    
    public JTextField getTfNom() {
        return tfNom;
    }
    
    JPanel pnlnewparts选择:

    private void btnNewRepActionPerformed(java.awt.event.ActionEvent evt) {
        tabs.addTab("R" + tabNo++, p);
        tabs.setSelectedIndex(tabNo);
    }
    
    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();
        }
    }
    
    public PnlNewCaseNotes() {
        initComponents();
    }
    
    public PnlNewPartsSelection() {
        initComponents();
    }
    
    /* A bunch of method calls to add place holders */
    
    public JTextField getTfNom() {
        return tfNom;
    }
    
    如果需要,我也可以发布每个类的代码(我只是认为这应该足够了)


    期待您的评论:)

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

    add(new PnlNewCase(true));
    
    如果您浏览代码,您会发现它调用:

    • PnlNewCase
      构造函数(为实例字段指定默认值)
      • initComponents
        • checkRepStatus
          。此时,您开始构建代码并调用
          t.requestFocusInWindow
    • 调用
      add
      PnlNewCase
      的新实例传递到容器
    这就是核心问题所在。调用
    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()
    
    然后你可以做一些简单的事情,比如

        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()
    
    总的来说


    您可能还想看一看,以便更好地理解,也许还有更多的想法

    调用
    t.requestFocusInWindow()
    时,
    PnlNewCase
    不太可能在屏幕上显示物理属性,这会使调用静音。您需要首先在UI上实现
    PnlNewCase
    ,然后重定向控件。可能在您调用
    add
    (和
    revalidate
    /
    repaint
    )之后,调用
    requestFocusInWindow
    。。。您可能会发现您需要使用
    SwingUtilities.invokeLater
    使其正常工作。感谢您花时间回答我的问题!你帮助我了解了问题所在,我为此感谢你。另一方面,我很难理解最后一段代码是如何发挥作用的。特别是newCase.focusPrimaryField()调用。据我所知,您将focusPrimaryField()方法添加到PnlNewCase类中,但我不知道最后一个片段应该在哪里。FrmMain?我们的想法是延迟请求焦点,直到您能够更好地保证在屏幕上建立ui。这里的重要部分是建立ui(添加组件,如果可能,在屏幕上实现)。您可以在
    setVisible
    之前添加对
    focusPrimaryField
    的调用,它“可能”会起作用,但在
    setVisible
    调用之后添加它可能更安全,如果可能的话。我的结构是制表符创建、主面板追加、上下文面板追加,我已经尝试添加对focusPrimaryField的调用(在PnlNewCase中找到)在制表符创建过程结束时,这将对应于返回根调用,但它没有起作用。我可能很难理解你到底建议我如何处理你发布的内容。此外,我还向一些经验更丰富的同龄人求助,他们建议我使用自定义遍历策略,我已经尝试过了,但没有成功。