错误的组件(在单独的 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
调用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()
作为一个总体思路。
您可能还想看看How to Use the Focus Subsystem 以获得更好的理解,也许还有更多的想法
【讨论】:
感谢您花时间回答我的问题!您帮助我了解了问题所在,对此我表示感谢。另一方面,我无法理解最后一段代码将如何发挥作用。特别是 newCase.focusPrimaryField() 调用。据我了解,您将 focusPrimaryField() 方法添加到 PnlNewCase 类,但我不知道最后一个片段应该在哪里。 FrmMain ? 这个想法是延迟请求焦点,直到你可以更好地保证在屏幕上建立 ui 的时间 这里的重要部分是建立的UI(组件被添加,如果可能的话,在屏幕上实现)。您可以在setVisible
之前添加对focusPrimaryField
的调用,它“可能”工作,但如果可能的话,在setVisible
调用之后添加它可能会更安全
因为我的结构是选项卡创建、主面板附加、上下文面板附加,所以我尝试在选项卡创建过程结束时添加对focusPrimaryField(在 PnlNewCase 中找到)的调用对应于返回根调用,但它没有工作。我可能无法准确理解您建议我对您发布的内容做什么。此外,我还求助于一些年长且经验丰富的同行,他们建议我使用自定义遍历策略,我尝试过但没有采用。以上是关于错误的组件(在单独的 JPanel 类中)获得焦点的主要内容,如果未能解决你的问题,请参考以下文章
如何在另一个类中的 JPanel 类中实现 ActionListener?
小程序---- input获得焦点时placeholder重影BUG
当 UITextField 获得焦点时,从 UITableViewCell 继承类中更改 UITableViewCell 的高度