[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-openjfx-dev
Subject:    Re: Usage of Toolkit firePulse
From:       Ryan Jaeb <ryan () jaeb ! ca>
Date:       2015-09-29 0:58:18
Message-ID: CAOrfuJ1KzzbK2N12LqYEUfxd6tfzGH89cEz1x=FYLmbvTsLyNA () mail ! gmail ! com
[Download RAW message or body]

Hi Benjamin,

Yes, it's a NoNodesFoundException using TestFX 3.1.2.

As far as I know, using firePulse() is the only way to guarantee all
previous model changes are rendered in the scene.  I've created an example
to show what I mean:

https://gist.github.com/ryanjaeb/74685a002e2b402e7fac

It's a small example, so I'll post it inline too:

...
public class FirePulseApplication extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        printEnv();

        ListView<String> listView = new ListView<>();

        Scene scene = new Scene(listView, 200, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        for (int i = 1; i < 6; i++) {
            listView.getItems().add("list-item-" + i);
        }

        System.out.println("Before firePulse():");
        printVisibleRowInfo(listView);

        Toolkit.getToolkit().firePulse();

        System.out.println("After firePulse():");
        printVisibleRowInfo(listView);

        Platform.exit();
    }

    private void printVisibleRowInfo(ListView<?> listView) {
        // Item count according to the list model
        System.out.println("  Item count: " + listView.getItems().size());

        // Extract the VirtualFlow so it can be used to determine which
        // list items are rendered in the scene.
        ObservableList<Node> children = listView.getChildrenUnmodifiable();
        VirtualFlow<?> flow = (VirtualFlow<?>) children.get(0);

        IndexedCell<?> firstCell = flow.getFirstVisibleCell();
        System.out.println("  First visible cell: " + firstCell);

        IndexedCell<?> lastCell = flow.getLastVisibleCell();
        System.out.println("  Last visible cell: " + lastCell);
    }

    private void printEnv() {
        String osName = System.getProperty("os.name");
        String jvm = System.getProperty("java.version") +
                " (" + System.getProperty("java.vm.version") +
                " - " + System.getProperty("os.arch") + ")";

        System.out.println("OS: " + osName);
        System.out.println("JVM: " + jvm);
        System.out.println("");
    }
}
...

The output I get when running the example:

...
OS: Windows 8.1
JVM: 1.8.0_40 (25.40-b25 - amd64)

Before firePulse():
  Item count: 5
  First visible cell: null
  Last visible cell: null
After firePulse():
  Item count: 5
  First visible cell: ListViewSkin$2@7820053f[styleClass=cell indexed-cell
list-cell]'list-item-1'
  Last visible cell: ListViewSkin$2@8be9262[styleClass=cell indexed-cell
list-cell]'list-item-5'
...

Until there's a pulse, the nodes that represent the list items don't exist,
so the NoNodesFoundException is expected.

Ryan

On Sun, Sep 27, 2015 at 12:40 AM, Benjamin Gudehus <hastebrot@gmail.com>
wrote:

> Hi Ryan!
>
> >Otherwise the drag(...) command will throw an exception because it
> can't find the node for "list-item-name" (it doesn't exist yet).
>
> Well, this is very interesting. This must be a NoNodesFoundException in
> TestFX 3.
>
> >I don't actually needto call firePulse().  I just need a way to know the
> scene is up to date with a re-validated model.  Is there a better way of
> accomplishing that right now?
>
> TestFX should try to find the Node within the JavaFX Application Thread
> using Platform.runLater(...). Maybe this is a better way than to call
> firePulse(),
>
> --Benjamin
>
> On Thu, Sep 24, 2015 at 12:49 PM, Ryan Jaeb <ryan@jaeb.ca> wrote:
>
>> I use firePulse() in GUI test code.  I'm using TestFX (v3) for testing.
>> Is
>> there a way to ensure model updates are reflected in the scene without
>> using firePulse()?  Consider something like this:
>>
>> ...
>> // TestFX starts us on the main thread.  Maybe I'm using it wrong?
>>
>> CountDownLatch latch = new CountDownLatch(1);
>>
>> Platform.runLater(() -> {
>>     // Add "list-item-name" to an empty list that's used as the model for
>>     // a ListView.
>>     Toolkit.getToolkit().firePulse();
>>     latch.countDown();
>> });
>>
>> try {
>>     latch.await(1, TimeUnit.SECONDS);
>> }
>> catch (InterruptedException e) {
>>     throw new RuntimeException(e);
>> }
>>
>> // TestFX runs this on the application thread.
>> drag("list-item-name").to("trash");
>>
>> assertTrue(list.isEmpty);
>> ...
>>
>> In a case like the above, firePulse() is used to ensure a node (ListCell)
>> for "list-item-name" is added to the scene before continuing with the
>> test.  Otherwise the drag(...) command will throw an exception because it
>> can't find the node for "list-item-name" (it doesn't exist yet).
>>
>> I don't actually needto call firePulse().  I just need a way to know the
>> scene is up to date with a re-validated model.  Is there a better way of
>> accomplishing that right now?
>>
>> Ryan
>>
>>
>> On Wed, Sep 23, 2015 at 5:49 PM, Jonathan Giles <
>> jonathan.giles@oracle.com>
>> wrote:
>>
>> > Hi all,
>> >
>> > Today I am keen to get your help on understanding use of the
>> > Toolkit.getToolkit().firePulse() private API. If you could spare a few
>> > minutes to grep your source directory for any usage of 'firePulse', and
>> > email me your findings, that would be really interesting.
>> >
>> > As a gentle motivational tool I'll conclude by saying that,
>> surprisingly,
>> > this private API is barely used inside the openjfx production code. If
>> you
>> > look at the openjfx unit tests, it is used massively. The question is -
>> how
>> > much is this being used by other community members. If the answer is
>> 'not
>> > much' or less, then this private API may not be made public in JDK 9.
>> Your
>> > feedback therefore is critical!
>> >
>> > Thanks,
>> > -- Jonathan
>> >
>>
>
>
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic