1

I'm trying to simply add a line of text to the listView. I've followed tutorials, asked AI, and followed it exactly to my knowledge. I know I'm doing something wrong.

in my class, my listview is properly connected to the fxml id in scenebuilder

@FXML
ListView<String> list = new ListView<>();

in the method:

public void addToList(){
        list.getItems().add("hi");
        list.getItems().add("hello");
}

it compiles and loads, and I see the listview pane. but none of the items are shown when i call addToList...

The Listview is inside of a scrollpane inside of an Hbox, inside of the main window which is a Vbox.

I know I'm missing something simple and it's frustrating the heck out me.

I'm trying to get anything to show in the listView. anything at all. Im actually trying to pass an array in a bigger program that I've proven is populated by printing the entire array, but I've simplified the code to just add 2 simple strings in an attempt to get anything to show.

Ryan
  • 35
  • 5
  • 5
    It is always a mistake to initialize fields annotated `@FXML`. That annotation explicitly means the field will be initialized by the `FXMLLoader`. – James_D Aug 18 '23 at 23:02
  • 4
    Create and post a [mre]. – James_D Aug 18 '23 at 23:02
  • 4
    "_The Listview is inside of a scrollpane_" – This is odd, especially if the `ListView` is the only content in the `ScrollPane`. In JavaFX, controls such as `ListView` have their own built-in scrolling functionality. – Slaw Aug 18 '23 at 23:38
  • 1
    Start by changing `@FXML ListView list = new ListView<>();` to `@FXML ListView list;`. – SedJ601 Aug 19 '23 at 00:08
  • 2
    ^^ And if you start getting a `NullPointerException` after that change, then that likely means you're either using the wrong controller instance or you forgot to give your list view an appropriate `fx:id` in the FXML file. To get more specific help you should [edit] your question to provide a [mre]. – Slaw Aug 19 '23 at 00:28

1 Answers1

3

Your code for adding items to the list backing the ListView:

list.getItems().add("hi")

… seems correct. So you must have other problems. Unfortunately, you neglected to provide an MCVE, so we cannot diagnose.

As the Comments said, your layout seems suspect. ListView has its own scrolling, so no need to embed in a scroll pane.


Below is a basic example app. This app starts with a ListView with a single value of “bonjour” set in the initialize method of the controller. A button then adds your two items "hi" & "hello" to the list, one every click.

initialize method

The initialize method is part of the JavaFX lifecycle. On a controller class, first the constructor runs. Then the @FXML fields are populated via injection by the JavaFX framework. Lastly the initialize method is automatically called by the JavaFX framework. So within the initialize method we can modify/manipulate the already-instantiated JavaFX controls. In this example app we designate our ObservableList with a single item ("bonjour") to be the backing data of our ListView control.

You can annotate the initialize method with @FXML. Not necessary if the method is marked public. If marked private, the annotation is required. See documentation for @FXML.

Button-click method

The method assigned to react to each click of the button uses your code to retrieve the ObservableList we assigned during initialize, and add your "hi"/"hello" items to that list. Because the list is observable, the JavaFX framework automatically notices the change in our backing data model, and automatically updates the display of the ListView.

Example code

This code is using JavaFX/OpenJFX version 20.0.2, with Java 20.0.2, on macOS Ventura, modified from the JavaFX new-project template provided by IntelliJ 2023.2.1.

A screenshot after having clicked the button three times.

screenshot of example app with a button that adds two items to the ListView

The FXML file:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<VBox alignment="CENTER"
      spacing="20.0"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="work.basil.example.fxlistview.HelloController">
    <padding>
        <Insets bottom="20.0"
                left="20.0"
                right="20.0"
                top="20.0"/>
    </padding>

    <Label fx:id="welcomeText"/>
    <Button text="Add two more items to list"
            onAction="#onClickOfAddButton"/>
    <ListView fx:id="exampleListView"/>
</VBox>

The controller:

package work.basil.example.fxlistview;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;

public class HelloController
{
    @FXML
    private Label welcomeText;

    @FXML
    private ListView < String > exampleListView;

    @FXML
    protected void onClickOfAddButton ( )
    {
        this.addToList ( );
    }

    private final ObservableList < String > observableList = FXCollections.observableArrayList ( "bonjour" );

    public void addToList ( )
    {
        exampleListView.getItems ( ).add ( "hi" );
        exampleListView.getItems ( ).add ( "hello" );
    }

    @FXML
    private void initialize ( )
    {
        this.exampleListView.setItems ( this.observableList );
    }
}

The Application subclass:

package work.basil.example.fxlistview;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloApplication extends Application
{
    @Override
    public void start ( Stage stage ) throws IOException
    {
        FXMLLoader fxmlLoader = new FXMLLoader ( HelloApplication.class.getResource ( "hello-view.fxml" ) );
        Scene scene = new Scene ( fxmlLoader.load ( ) , 320 , 600 );
        stage.setTitle ( "Hello!" );
        stage.setScene ( scene );
        stage.show ( );
    }

    public static void main ( String[] args )
    {
        launch ( );
    }
}

These Questions helped me here:

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • The private vs public stuff you mention with regards to [@FXML](https://openjfx.io/javadoc/17/javafx.fxml/javafx/fxml/doc-files/introduction_to_fxml.html#fxml_annotation) is described in the linked documentation. Basically, if you make methods or fields public, you don’t need the `@FXML` annotation, because the reflection mechanism in the loader can use the stuff without the annotation. – jewelsea Aug 19 '23 at 07:13
  • To me, the `initialize()` method is an internal implementation detail. It isn’t (and shouldn’t be) invoked from anywhere except by the `FXMLLoader` when the FXML is loaded. So it should be `private`, just from the usual encapsulation considerations. – James_D Aug 19 '23 at 12:23
  • 1
    Here's a Q&A related to jewelsea's and James_D's comments: [Access modifiers in JavaFx and @FXML](https://stackoverflow.com/q/61044743/6395627). – Slaw Aug 19 '23 at 16:14
  • 1
    Thanks for the Comments. All three have been adopted into the Answer. – Basil Bourque Aug 20 '23 at 04:33