toFront()抛出UnsupportedOperationException [英] toFront() throwing UnsupportedOperationException

查看:83
本文介绍了toFront()抛出UnsupportedOperationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个StackPane,无论添加什么内容,我选择的节点始终位于最前面(而不是要注意添加顺序,也不必记住在toFront()上调用该特定节点,只要添加了任何内容.)

I want to create a StackPane where, whatever is added, a node of my choice is always at the front (rather than having to be careful about the order I add things in, or remembering to call toFront() on that particular node whenever anything is added.)

为此,我只是将一个侦听器放在相关的StackPane对象的子列表上,这样,只要发生任何更改,它都会在相关的节点上调用toFront(),例如:

In order to do this, I simply place a listener on the child list of the relevant StackPane object, so that whenever anything changes, it calls toFront() on the relevant node, for example:

public class Test extends Application {

    @Override
    public void start(Stage stage) {
        StackPane root = new StackPane();
        final Rectangle r1 = new Rectangle(50, 50);
        root.getChildren().add(r1);
        root.getChildren().addListener(new ListChangeListener<Node>() {
            @Override
            public void onChanged(ListChangeListener.Change<? extends Node> change) {
                try {
                    while(change.next()) {
                        if(change.wasAdded()) {
                            r1.toFront();
                        }
                    }
                }
                catch(Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        root.getChildren().add(new Rectangle(50, 50));

        stage.setScene(new Scene(root));
        stage.show();
    }
}

在Java 7中,这很好用.但是,在JFX8(最新下载的最新版本)中,它失败并显示以下内容:

In Java 7, this works just fine. However, in JFX8 (latest build downloaded just now), it fails with the following:

java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableList.add(Collections.java:1374)
        at javafx.collections.ListChangeBuilder.nextRemove(ListChangeBuilder.java:208)
        at javafx.collections.ObservableListBase.nextRemove(ObservableListBase.java:150)
        at javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:181)
        at com.sun.javafx.collections.VetoableListDecorator.remove(VetoableListDecorator.java:284)
        at com.sun.javafx.collections.VetoableListDecorator.remove(VetoableListDecorator.java:209)
        at javafx.scene.Parent.impl_toFront(Parent.java:624)
        at javafx.scene.Node.toFront(Node.java:1713)
        at test.Test$1.onChanged(Test.java:34)
        at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:315)
        at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:72)
        at com.sun.javafx.collections.VetoableListDecorator$1.onChanged(VetoableListDecorator.java:77)
        at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:315)
        at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:72)
        at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
        at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
        at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
        at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
        at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
        at java.util.AbstractList.add(AbstractList.java:108)
        at com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:200)
        at test.Test.start(Test.java:41)
        at com.sun.javafx.application.LauncherImpl$8.run(LauncherImpl.java:837)
        at com.sun.javafx.application.PlatformImpl$7.run(PlatformImpl.java:331)
        at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:297)
        at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:294)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:294)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
        at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
        at java.lang.Thread.run(Thread.java:744)

是的,test.Test$1.onChanged(Test.java:34)确实是指r1.toFront();.

这被认为是错误,还是我试图通过这种方式实现目标而违反了我不知道的某些规则?我确实想知道在执行onChanged()方法时列表是否仍在更改,并且toFront()还会更改列表内容,因此是例外-但是onChanged()的Javadoc明确指出:

Is this to be considered a bug, or am I breaking some rule I'm unaware of by trying to achieve things this way? I did wonder whether the list was still being changed while the onChanged() method was executing, and toFront() would also change the list contents, hence the exception - but the Javadoc to onChanged() clearly says:

之后被称为对ObservableList的更改.

Called after a change has been made to an ObservableList.

(粗体是我的.)

在这一点上,我可以确定这是一个错误,因此相关的错误报告为

At this point I'm more certain that it's a bug, so the related bug report is here.

推荐答案

似乎不允许您在事件处理程序内修改(JavaFX)列表,该事件处理程序当前正在处理同一列表的另一个(先前)修改事件.尽管这似乎是合理的,但这不是不言而喻的,因此在这种情况下应该有一个更明显的例外.

It seems that you are not allowed to modify a (JavaFX) list inside an event handler that is currently handling another (previous) modification event of the same list. Although this seems reasonable it is not self-evident, so there should be a more obvious exception in that case.

不幸的是,非偷看异常在JavaFX中非常常见.

Unfortunately non-speeking exceptions are very common in JavaFX.

幸运的是,解决方案/解决方案非常简单:通过Platform.runLater()调用您的修改代码(此处为r1.toFront),这将延迟您的修改在发生原始事件之后发生:

Fortunately the solution/workaround is pretty easy: Call your modifying code (here: r1.toFront) by Platform.runLater(), it will delay your modification to happen after the originating event:

root.getChildren().addListener(new ListChangeListener<Node>() {
    @Override
    public void onChanged(ListChangeListener.Change<? extends Node> change) {
        Platform.runLater(new Runnable() {
            public void run() { r1.toFront(); }                 
        });
    }
});

侧面注释:toFront不执行任何操作(如果组件已经在前面).这样可以防止无限循环.但是,由于在文档中没有明确提及,因此您可能不依赖于此.

Sidenote: toFront does nothing, if the component is already at front. This prevents infinite loops. Nevertheless, as this is not explicitely mentioned in the documentation, you might not rely on that.

这篇关于toFront()抛出UnsupportedOperationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆