globaltcad / swing-tree

A small DSL library for building Swing UIs
MIT License
6 stars 0 forks source link

list.onShow #193

Closed Mazi-S closed 2 weeks ago

Mazi-S commented 1 month ago

I'm not sure if I'm using .onShow() correctly. But shouldn't it be called when the component is shown?

Vars<String> items = Vars.of(String.class);
for (int i = 0; i < 50; i++) {
    items.add("item " + i);
}

Var<String> selection = Var.of("item 42");

of(this).withLayout("wrap, fillx")
    .withPrefSize(300, 200)
    .withBackground(Color.ORANGE)
    .add(GROW_X, scrollPane()
        .add(GROW_X, UI.list(selection, items)
            .onShown(it -> it.getComponent()
                .ensureIndexIsVisible(it.getComponent().getSelectedIndex())
            )
        )
    );
Gleethos commented 1 month ago

Yes it should. But this is currently a simple delegate to ComponentListener::componentShown, so if this does not work in the above scenario then it is a Swing bug.

Mazi-S commented 1 month ago

I looked into it a bit and it seems that ComponentListener::componentShown is pretty useless. Maybe we should consider adding a HierarchyListener and look for DISPLAYABILITY_CHANGED events instead. 🤔

This will be called when the component is actually shown and I would say this is what .onShow() implies.

Gleethos commented 1 month ago

Oh wow.

Of course it doesn't do anything...

Well then let's fix this for Swing. I have never used the HierarchyListener this way, but if you think it might work, give it a shot. The first approach that comes to my mind is a regular component property listener. But this is based on the assumption that a listener is fired in case of the visibility flag changing. So that might also be worth investigating, but I have not yet looked at this in closer detail hover.

Gleethos commented 2 weeks ago

Do you already have an idea how to do this or should I maybe give it a shot?

Mazi-S commented 2 weeks ago

I just had a quick look, but didn't have time for more. You can take it if you want.

Gleethos commented 2 weeks ago

I just took a bit of time to take a closer look and as so often in Swing, the events the ComponentListener is receiving here are kind of right, but all in all pretty incorrect...

What it does is to literally listen to changes to the isVisible flag. So when you bind a property to the visibility, and then toggle its, you will receive show and hide events corresponding to the actual visibility on the screen of the user! So the assumption here was that the visibility flag actually models the visibility of the component on the screen of the user.

But you cannot make these bold assumptions in Swing, oh no.

Because it turns out that isVisible may not actually mean that a component is visible, it just means that it could be, depending on other factors. Or to break it down more clearly:

So what that means in practice is that a component whose visibility flag is set to true, may still have a totally different visibility on screen depending if one of its parents is visible or not!

Gleethos commented 2 weeks ago

I pushed a fix for both onShown and onHidden. Could you take a look at it and tell me if this also works in your scenarios?

Mazi-S commented 2 weeks ago

Thanks for fixing it. Yeah, I saw that inconsistency too, but I guess this is the best we can do. At least we get the right events sometimes. 😅