2

I am trying to set a button as the default button using a simple code as:

mainPanel.getRootPane().setDefaultButton(sendButton);

But getRootPane() returns null. I am using IntelliJ Idea Form designer and my code is just basically that line in the class constructor, just after 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 adds some hidden code, but I can't see how this code could be changing things.

My objective is just to set a default button in the form, so Enter will always activate this button.

PS: I am new to Swing, but not to Java.


EDIT:

All the hidden code as requested:

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;
    }
}
Michel Feinstein
  • 13,416
  • 16
  • 91
  • 173
  • Ok, I will generate the hidden code and post it in here – Michel Feinstein Nov 17 '14 at 16:27
  • 1
    Note that [getRootPane](https://docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#getRootPane--) may return `null` -> **Returns:** `the JRootPane that contains this component, or null if no JRootPane is found`, so this should be no surprise. If you expect to have one then you have to show the code where `mainPanel` is constructed. – A4L Nov 17 '14 at 16:43
  • Ok, I just posted all the code...thanks! – Michel Feinstein Nov 17 '14 at 17:03

1 Answers1

5
public static void main(String[] args) {
    ...
    frame.setContentPane(new TestSwing().mainPanel);
    ...
}

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

You are getting the root pane before you add the panel to the frame. The order of operations here is:

  1. new TestSwing() is called.
  2. Instance initializer runs and mainPanel is created.
  3. Attempt to get root pane from mainPanel inside the constructor.
  4. Add mainPanel to the frame after construction completes.

So, you need to refactor this so you are getting the root pane after adding the panel to the frame. In other words, don't do it in the constructor for TestSwing. It just doesn't really make sense to do that anyway. It makes the order of operations more difficult to understand.

Just for example:

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() {                
}

Also, you should read the Swing tutorials, especially 'Initial Threads'. You need to wrap your GUI creation (the stuff in main) within a call to invokeLater so it is executed on the Swing event thread.


As far as style goes, the official tutorials picture a GUI created this way:

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);
    }
}

I usually do it this way because I just think it's nice and tidy:

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);
    }
}

It could be done any number of ways. The point is that it's better to have your creation code logically grouped in a uniform way. If you are doing some of it in main, some of it in an instance initializer, some of it in a constructor, etc, it becomes difficult to follow. Also in this particular case, a root pane is actually a property of the JFrame so it seems logical to me to put it with the JFrame configuration.

If you are using a GUI builder I suppose it is more difficult to manage because you cannot group the components in classes.

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • I am using IntelliJ Idea to easy things up, the `main()` code is practically auto-generated as in here: https://www.jetbrains.com/idea/help/creating-and-disposing-of-a-forms-runtime-frame.html ..... and I tried to put the default button code in `main()`, but since `sendButton`is not static, it says "Non-static field 'sendButton' cannot be referenced from a static context" ... it says this even with your runnable code – Michel Feinstein Nov 17 '14 at 17:28
  • Ok, I fixed it using: TestSwing testSwing = new TestSwing(); frame.setContentPane(testSwing.mainPanel); frame.getRootPane().setDefaultButton(testSwing.sendButton); are there better options? – Michel Feinstein Nov 17 '14 at 17:34
  • Also, do you know when this `{ $$$setupUI$$$(); }` is called? I am not sure how it behaves inside this class...in another auto-generated code it appeared as the first line of the constructor, but now it changed... – Michel Feinstein Nov 17 '14 at 17:37
  • The IntelliJ example is incorrect. They should really know better. *"Non-static field [...] cannot be referenced from a static context*" This means you were trying to access it like `TestSwing.mainPanel`. *"are there better options?"* This is all just really a matter of style. I personally implement `Runnable` and create the JFrame inside `run` so I don't go through an object reference. (See this [recent answer of mine](http://stackoverflow.com/a/26976902/2891664) for an example.) – Radiodef Nov 17 '14 at 17:39
  • *"when { $$$setupUI$$$(); } is called?"* It's an instance initializer block. It's called before the constructor. – Radiodef Nov 17 '14 at 17:40
  • Interesting....so how would you do the default button in this case? I created the frame inside the runnable as you suggested, and then I called the constructor and saved the created instance and used it to access the `sendButton` instance inside that instance form a static perspective (since the runnable was created by main which is static – Michel Feinstein Nov 17 '14 at 17:46
  • And technically I should say, an instance initializer block is merged *in to* the constructor. It is run *after* the superclass constructor(s) and *before* the constructor of `this`. https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html – Radiodef Nov 17 '14 at 17:46
  • The way you are doing the default button seems fine. Honestly if you are just learning this stuff you shouldn't worry *too* much about it. – Radiodef Nov 17 '14 at 17:48
  • Yeah, but I like to learn it in the way things should be done, so later when I have to do some serious code I know how serious code should look like :) – Michel Feinstein Nov 17 '14 at 17:56
  • Well I edited a little bit which I hope helps. I do want to plug [this answer](http://stackoverflow.com/questions/26972637/add-and-remove-button-dynamically-in-swing-frame/26976902#26976902) again because it is a good example of programming logical layout groups by hand. When you are programming a much larger application things will get bonkers if you are not organizing your components this way. Either creating small subclasses or helper factory methods. Basically in 'serious' code you would likely not program the whole GUI in a single block. – Radiodef Nov 17 '14 at 18:42
  • I see, many many thanks for the complete answer! (now I am just strugling to make some key bidings haha) – Michel Feinstein Nov 17 '14 at 18:47
  • Glad to help. If you need help with a new problem of course you can ask a new question. ; ) If you are trying to use KeyListener you should probably use input map bindings instead. https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html – Radiodef Nov 17 '14 at 19:03
  • That's exactly what I am using, but I didn't read the documentation since I am in a hurry, when I get back home I will see if I can make it work ... Thanks again! – Michel Feinstein Nov 17 '14 at 19:05
  • @Radiodef I understand the OP's confusion with the instance initializers. Many of the GUI builders create a God object with nested initializers for each component to keep the initialization order in scope with the EDT ... it's quite a mess trying to refactor those instances into separate classes... – Edward J Beckett Jan 29 '15 at 22:19