Hi!

I have a problem with the array of JTextField components. So, the code is shown below and it can be successfully compiled:

txtAdminTextFields = new JTextField[nrOfCols];

...

        tableAttributes.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
        public void columnMarginChanged(ChangeEvent e) {
            for (int i=0; i < nrOfColsFin; i++) {
               txtAdminTextFields[i] = new JTextField();
               txtAdminTextFields[i].setPreferredSize(new Dimension(tableAttributes.getColumn(dbColName[i]).getPreferredWidth(),txtAdminTextFields[i].getPreferredSize().height));
            }
        }
        public void columnAdded(TableColumnModelEvent e) {}
        public void columnRemoved(TableColumnModelEvent e) {}
        public void columnMoved(TableColumnModelEvent e) {}
        public void columnSelectionChanged(ListSelectionEvent e) {}
        });

...

// THE ERROR MESSAGE OCCURS AFTER EXECUTING THE CODE BELOW!
// "Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException"
        for (int i=0; i < nrOfColsFin; i++) {
            if (i != nrOfColsFin) {
               attrPan.add(txtAdminTextFields[i]);
            } else if (i == nrOfColsFin) {
               attrPan.add(txtAdminTextFields[i], "wrap");
            }
        }

Please, help me to solve the problem.

Dani AI

Generated

Root cause and what happened
The array txtAdminTextFields was allocated with a length but its elements were null because the code that called new JTextField() lived inside columnMarginChanged, and that listener never fired before the panel-add loop ran. Calling attrPan.add(null) throws a NullPointerException. Also, TableColumnModelListener.columnMarginChanged only runs when a column margin actually changes (user resize or programmatic change), so it cannot be relied on to create components during initial setup.

Why the posted fix works
Instantiating every JTextField during initialization (before adding them to attrPan) removes the NPE; then the listener is used only to update preferred widths when columns move. That follows ’s suggestion to extract the logic and call it both at init and from the listener, and matches the final code posted by . One small logic bug to note: testing i == nrOfColsFin inside a loop that runs i < nrOfColsFin can never be true — the last index is nrOfColsFin - 1, so special-case checks for the last element need that adjustment.

Extra practical tips and best practices
Run all Swing UI changes on the Event Dispatch Thread (SwingUtilities.invokeLater/invokeAndWait). After adding components call revalidate() and repaint() on the container. Prefer letting MigLayout handle sizing via constraints (grow, fill, wrap) rather than repeatedly calling setPreferredSize; if column widths are needed, compute sizes after the table is realized (for example, after pack()/setVisible or via invokeLater) so getPreferredWidth() returns meaningful values.

Quick troubleshooting checklist

  1. Use a debugger/breakpoints as @cale.macdonald suggested to see which reference is null. 2) Consolidate creation and sizing into one helper and call it from init and from columnMarginChanged (per @JamesCherrill). 3) setName on components can help when inspecting the UI (responds to @FallenPaladin’s control-name observation).

Recommended Answers

All 14 Replies

Where is nrOfColsFin defined?

It is defined in the same procedure:

...

        int nrOfCols = 0;
        if (tabType == 1) {
...
             nrOfCols = 5;
        } else if (tabType == 2) {
...
            nrOfCols = 4;
        }

...

final int nrOfColsFin = nrOfCols;

System.out.println shows that nrOfColsFin is equal to 5.

Where is nrOfColsFin defined?

What is the stack trace when you run this (It will tell you the line it is failing on)? A NPE happens when something hasn't been initialized, so the other cause in your code could be that attrPan hasn't been initialized.

The problem occurs with lines 22-28. I checked it with System.out.println...

Hmm... attrPan is initialised:

private JPanel attrPan = new JPanel(new MigLayout("wrap", "grow, fill"));

Well, the full error message is:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at SystClasses.Form.createAdminTable(Form.java:480)
        at SystClasses.Form.createAdminRightPanel(Form.java:371)
        at SystClasses.Form.createBase(Form.java:189)
        at SystClasses.Form.access$000(Form.java:44)
        at SystClasses.Form$2.actionPerformed(Form.java:143)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:6267)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
        at java.awt.Component.processEvent(Component.java:6032)
        at java.awt.Container.processEvent(Container.java:2041)
        at java.awt.Component.dispatchEventImpl(Component.java:4630)
        at java.awt.Container.dispatchEventImpl(Container.java:2099)
        at java.awt.Component.dispatchEvent(Component.java:4460)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
        at java.awt.Container.dispatchEventImpl(Container.java:2085)
        at java.awt.Window.dispatchEventImpl(Window.java:2478)
        at java.awt.Component.dispatchEvent(Component.java:4460)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Are you sure that columnMarginChanged in your TableColumnModelListener has actually been called before it drops thru into the problem code - or is txtAdminTextFields initialised somewhere else?

Maybe the problem is with attrPan.add(txtAdminTextFields); I am not sure but perhaps I must write something like attrPan.add(txtAdminTextFields.getComponent());??

Well, I've just inserted System.out.println in different places of the code, and I've noticed that the code with 'TableColumnModelListener' is executed successfully.

Are you sure that columnMarginChanged in your TableColumnModelListener has actually been called before it drops thru into the problem code - or is txtAdminTextFields initialised somewhere else?

the code with 'TableColumnModelListener' is executed successfully.

Do you mean the code where the listener is added or do you actually mean that columnMarginChanged has been executed. Have you put a print inside the columnMarginChanged method?

Ok I am no way near as experianced as yourselves with Java, however somthing I am interested in is the dynamic creation of the JTextFields that you are performing. I have done this before in c# and do not see where you are naming the control. In C# each control that is added requires a specific name else an exception is thrown.

Feel free to slap me round the head with a wet kipper if I am way off the mark here.

If you do not have to name it is it because of the table you are creating?

I would fire up a debugger for this. Put 2 breakpoints in the code, one in the for loop and one in the columnMarginChanged event. See which breakpoint is hit first, then in the for loop (the one that throws the NPE) set through line by line and inspect each variable. That should tell you what is null.

Ups, you are right. I've inserted the println inside the ColumnMarginChanged and it has been not executed:

tableAttributes.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
        public void columnMarginChanged(ChangeEvent e) {
            for (int i=0; i < nrOfColsFin; i++) {
               txtAdminTextFields[i] = new JTextField();
               txtAdminTextFields[i].setPreferredSize(new Dimension(tableAttributes.getColumn(dbColName[i]).getPreferredWidth(),txtAdminTextFields[i].getPreferredSize().height));
               System.out.println("Ok");
            }
        }

So, how could I make this code executable?

Do you mean the code where the listener is added or do you actually mean that columnMarginChanged has been executed. Have you put a print inside the columnMarginChanged method?

Suggest you think about extracting that code into an ordinary method then calling it (1) somewhere in your initialisation and (2) in the columnMarginChanged method

Thank you all! Now it works perfectly:

for (int i=0; i < nrOfColsFin; i++) {
               txtAdminTextFields[i] = new JTextField();
        }

        tableAttributes.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
        public void columnMarginChanged(ChangeEvent e) {
            for (int i=0; i < nrOfColsFin; i++) {
               txtAdminTextFields[i].setPreferredSize(new Dimension(tableAttributes.getColumn(dbColName[i]).getPreferredWidth(),txtAdminTextFields[i].getPreferredSize().height));               
            }
        }

Great! Mark this as solved?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.