【问题标题】:Java Swing getRootPane() returns nullJava Swing getRootPane() 返回 null
【发布时间】:2014-11-17 16:12:35
【问题描述】:

我正在尝试使用以下简单代码将按钮设置为默认按钮:

mainPanel.getRootPane().setDefaultButton(sendButton);

但是getRootPane() 返回null。我正在使用 IntelliJ Idea Form 设计器,我的代码基本上就是类构造函数中的那一行,就在 main 之后:

 public static void main(String[] args) {
    JFrame frame = new JFrame("TestSwing");
    frame.setContentPane(new TestSwing().mainPanel);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setMinimumSize(new Dimension(700, 700));
    frame.pack();
    frame.setVisible(true);
}

public TestSwing() {                
    mainPanel.getRootPane().setDefaultButton(sendButton);
}

IntelliJ 添加了一些隐藏代码,但我看不出这些代码如何改变事物。

我的目标只是在表单中设置一个默认按钮,因此Enter 将始终激活此按钮。

PS:我是 Swing 新手,但不是 Java。


编辑:

按要求隐藏所有代码:

package com.testswing;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;


public class TestSwing {
    private JPanel mainPanel;
    private JTextArea messageTextArea;
    private JTextPane chatTextPane;
    private JCheckBox autoCheckbox;
    private JButton newChatButton;
    private JButton sendButton;
    private JTextField textField1;
    private JTextField textField2;

    public static void main(String[] args) {
        JFrame frame = new JFrame("TestSwing");
        frame.setContentPane(new TestSwing().mainPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(700, 700));
        frame.pack();
        frame.setVisible(true);
    }

    public TestSwing() {
        mainPanel.getRootPane().setDefaultButton(sendButton);
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        mainPanel = new JPanel();
        mainPanel.setLayout(new com.intellij.uiDesigner.core.GridLayoutManager(5, 2, new Insets(15, 15, 15, 15), -1, -1));
        mainPanel.setMinimumSize(new Dimension(500, 500));
        messageTextArea = new JTextArea();
        messageTextArea.setLineWrap(true);
        mainPanel.add(messageTextArea, new com.intellij.uiDesigner.core.GridConstraints(1, 0, 3, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_BOTH, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, new Dimension(100, 100), null, null, 0, false));
        chatTextPane = new JTextPane();
        chatTextPane.setEditable(false);
        mainPanel.add(chatTextPane, new com.intellij.uiDesigner.core.GridConstraints(0, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_BOTH, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, new Dimension(500, 500), new Dimension(150, 50), null, 0, false));
        autoCheckbox = new JCheckBox();
        autoCheckbox.setLabel("Auto");
        autoCheckbox.setText("Auto");
        mainPanel.add(autoCheckbox, new com.intellij.uiDesigner.core.GridConstraints(1, 1, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_NONE, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        newChatButton = new JButton();
        newChatButton.setText("New");
        mainPanel.add(newChatButton, new com.intellij.uiDesigner.core.GridConstraints(2, 1, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_NONE, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        sendButton = new JButton();
        sendButton.setText("Send");
        mainPanel.add(sendButton, new com.intellij.uiDesigner.core.GridConstraints(3, 1, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_NONE, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new com.intellij.uiDesigner.core.GridLayoutManager(1, 4, new Insets(0, 0, 0, 0), -1, -1));
        mainPanel.add(panel1, new com.intellij.uiDesigner.core.GridConstraints(4, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_BOTH, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label1 = new JLabel();
        label1.setText("Text To Auto Send:");
        panel1.add(label1, new com.intellij.uiDesigner.core.GridConstraints(0, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST, com.intellij.uiDesigner.core.GridConstraints.FILL_NONE, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        textField1 = new JTextField();
        panel1.add(textField1, new com.intellij.uiDesigner.core.GridConstraints(0, 1, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST, com.intellij.uiDesigner.core.GridConstraints.FILL_HORIZONTAL, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
        final JLabel label2 = new JLabel();
        label2.setText("Text To Auto Copare:");
        panel1.add(label2, new com.intellij.uiDesigner.core.GridConstraints(0, 2, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST, com.intellij.uiDesigner.core.GridConstraints.FILL_NONE, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        textField2 = new JTextField();
        panel1.add(textField2, new com.intellij.uiDesigner.core.GridConstraints(0, 3, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST, com.intellij.uiDesigner.core.GridConstraints.FILL_HORIZONTAL, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return mainPanel;
    }
}

【问题讨论】:

  • 好,我会生成隐藏代码贴在这里
  • 请注意,getRootPane 可能会返回 null -> 返回: the JRootPane that contains this component, or null if no JRootPane is found,所以这应该不足为奇。如果您希望有一个,那么您必须显示构造 mainPanel 的代码。
  • 好的,我刚刚发布了所有代码...谢谢!

标签: java swing intellij-idea


【解决方案1】:
public static void main(String[] args) {
    ...
    frame.setContentPane(new TestSwing().mainPanel);
    ...
}

public TestSwing() {                
    mainPanel.getRootPane().setDefaultButton(sendButton);
}

在将面板添加到框架之前,您将获得根面板。这里的操作顺序是:

  1. new TestSwing() 被调用。
  2. 实例初始化程序运行并创建mainPanel
  3. 尝试从构造函数中的mainPanel 获取根窗格。
  4. 构造完成后将mainPanel 添加到框架中。

因此,您需要对其进行重构,以便在将面板添加到框架后获得根面板。换句话说,不要在TestSwing 的构造函数中这样做。无论如何,这样做没有任何意义。它使操作顺序更难理解。

举例:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            ...
            TestSwing testSwing = new TestSwing();
            frame.setContentPane(testSwing.mainPanel);
            frame.getRootPane().setDefaultButton(testSwing.sendButton);
            ...
        }
    });
}

public TestSwing() {                
}

另外,您应该阅读 Swing 教程,尤其是 'Initial Threads'。您需要将您的 GUI 创建(main 中的内容)包装在对 invokeLater 的调用中,以便在 Swing 事件线程上执行。


就风格而言,官方教程描绘了一个这样创建的 GUI:

class Example {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame();
        // setup
        frame.setVisible(true);
    }
}

我通常这样做,因为我只是觉得它很好而且整洁:

class Example implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Example());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame();
        // setup
        frame.setVisible(true);
    }
}

可以通过多种方式完成。关键是最好让您的创建代码以统一的方式进行逻辑分组。如果您在main 中执行一些操作,其中一些在实例初始化程序中执行,其中一些在构造函数中执行,等等,就变得难以理解。同样在这种特殊情况下,根窗格实际上是 JFrame 的一个属性,因此对我来说将它与 JFrame 配置放在一起似乎是合乎逻辑的。

如果您使用的是 GUI 构建器,我想管理起来会更加困难,因为您无法将组件分组到类中。

【讨论】:

  • 我正在使用 IntelliJ Idea 来简化操作,main() 代码实际上是自动生成的,如下所示:jetbrains.com/idea/help/… ..... 我尝试将默认按钮代码放入main(),但由于 sendButton 不是静态的,它说“不能从静态上下文引用非静态字段 'sendButton'”......即使使用您的可运行代码也会这样说
  • 好的,我修复了它:TestSwing testSwing = new TestSwing(); frame.setContentPane(testSwing.mainPanel); frame.getRootPane().setDefaultButton(testSwing.sendButton);有更好的选择吗?
  • 另外,你知道这个{ $$$setupUI$$$(); } 什么时候被调用吗?我不确定它在这个类中的表现如何......在另一个自动生成的代码中,它作为构造函数的第一行出现,但现在它改变了......
  • IntelliJ 示例不正确。他们真的应该知道得更好。 "非静态字段 [...] 不能从静态上下文中引用" 这意味着您试图像 TestSwing.mainPanel 一样访问它。 “有更好的选择吗?” 这只是风格问题。我个人实现Runnable 并在run 内创建JFrame,所以我不通过对象引用。 (有关示例,请参阅此 recent answer of mine。)
  • "什么时候调用 { $$$setupUI$$$(); }?" 这是一个实例初始化块。它在构造函数之前调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-04
  • 2019-08-25
  • 2016-05-28
  • 2016-03-08
  • 2015-12-09
  • 1970-01-01
相关资源
最近更新 更多