a.disableProperty().bind(b.visibleProperty())导致Java FX 10中的元素渲染无效 [英] a.disableProperty().bind(b.visibleProperty()) causes invalid element rendering in Java FX 10

查看:78
本文介绍了a.disableProperty().bind(b.visibleProperty())导致Java FX 10中的元素渲染无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是Java 10中的回归,请参考错误报告以获取进一步的更新:

This is a regression in Java 10, refer to the bug report for further updates: JDK-8204949

考虑以下Java FX代码,其中b开始不可见: a.disableProperty().bind(b.visibleProperty())

Consider the following Java FX code, where b starts invisible: a.disableProperty().bind(b.visibleProperty())

如果在Java 10 VM上运行了使用此类代码的应用程序,则从第一次显示b时,始终会呈现a就像被禁用一样.

If an application utilizing such code is run on Java 10 VM, then from the first time b becomes visible, a will always be rendered as if it was disabled.

当然,在未真正禁用a的时间内(尽管使用灰色覆盖层进行渲染),您仍然可以与该元素进行交互.例如.您可以在输入控件中编辑文本,单击按钮/链接等,使事件正确传播,等等.

Of course, during the time while a is not really disabled (despite being rendered with a gray overlay), you can still interact with that element. E.g. you can edit text in input controls, click buttons/links and so on, the events get propagated correctly and so on.

如果该应用程序在Java 8 VM上运行,它将按预期运行.

If the application is run on Java 8 VM, it works as expected.

我目前没有EOS Java 9,因此仅在以下位置进行了测试:

I currently do not have the EOS Java 9, so I have only tested on:

  • Windows 10 x64 Pro 1709& 1803
  • Java 8u172 x64(在JDK和JRE上均明确针对可执行文件)
  • Java 10u1 x64(在JDK和JRE上均明确地针对可执行文件)

Java 10的外观示例:

Example of how it looks like with Java 10:

b有机会出现之前的第一次启动时的外观:

How it looks on first start, before b had a chance to become visible:

SSCCE(对于有些晦涩的问题为强制; apropertyProviderbinvalidRenderFieldinvalidRenderButton):

A SSCCE (mandatory for a somewhat obscure problem; a would be propertyProvider, b would be invalidRenderField and invalidRenderButton):

package application;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.VBox;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        System.out.println("Executing start(Stage) in " + Thread.currentThread().getName());
        try {
            TextField invalidRenderField = new TextField();
            Button invalidRenderButton = new Button("Click to reproduce");
            Label propertyProvider = new Label();
            propertyProvider.setVisible(false);
            VBox invalidRenderParent = new VBox(invalidRenderField, invalidRenderButton, propertyProvider);
            TitledPane invalidRenderPane = new TitledPane("Incorrectly rendered elements", invalidRenderParent);
            Accordion root = new Accordion(invalidRenderPane);
            root.setExpandedPane(invalidRenderPane);

            invalidRenderField.disableProperty().bind(propertyProvider.visibleProperty());
            invalidRenderButton.disableProperty().bind(propertyProvider.visibleProperty());
            invalidRenderButton.setOnAction(e -> {
                System.out.println("Executing 1st onAction(ActionEvent) in " + Thread.currentThread().getName());

                propertyProvider.setVisible(true);
                propertyProvider.setText("At this point of time you cannot modify the field or click the button");

                Task<Void> task = new Task<>() {
                    @Override
                    protected Void call() throws Exception {
                        System.out.println("Executing non-JFX code in " + Thread.currentThread().getName());
                        Thread.sleep(3_000L);
                        return null;
                    }
                };
                task.setOnSucceeded(e2 -> {
                    System.out.println("Executing onSuccess(WorkerStateEvent) in " + Thread.currentThread().getName());

                    propertyProvider.setVisible(false);

                    Label infoLabel = new Label("Either click the button below or just select the previous pane within the accordion");
                    Button closePlaceholderButton = new Button("View failure");
                    VBox placeholder = new VBox(infoLabel, closePlaceholderButton);
                    TitledPane placeholderPane = new TitledPane("Placeholder", placeholder);

                    closePlaceholderButton.setOnAction(e3 -> {
                        System.out.println("Executing 2nd onAction(ActionEvent) in " + Thread.currentThread().getName());
                        root.getPanes().remove(placeholderPane);
                        root.setExpandedPane(invalidRenderPane);
                    });

                    root.getPanes().add(1, placeholderPane);
                    root.setExpandedPane(placeholderPane);
                });
                new Thread(task, "WhateverThread").start();
            });

            Scene scene = new Scene(root, 800, 450);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println("Executing main(String[]) in " + Thread.currentThread().getName());
        launch(args);
    }
}

单击单击以复制"一次后的SSCCE输出:

SSCCE output after clicking 'Click to reproduce' once:

Executing main(String[]) in main
Executing start(Stage) in JavaFX Application Thread
Executing 1st onAction(ActionEvent) in JavaFX Application Thread
Executing non-JFX code in WhateverThread
Executing onSuccess(WorkerStateEvent) in JavaFX Application Thread

完全符合预期,JavaFX代码在指定线程上执行.

Which is exactly as expected, JavaFX code executes on the designated thread.

问题是,我是在做错什么和/或缺少明显的事情吗?我似乎找不到任何与此代码不对"的东西,听起来不错,但还是有故障.这是一个错误(我需要lrn2search)吗?

The question is, am I doing something wrong and/or missing something obvious? I can't seem to find anything "wrong" with this code, it seems sound, yet it malfunctions. Is this a bug (and I need to lrn2search)?

总而言之,欢迎任何解决方法的建议.我需要这段代码(或通过变通方法来解决),才能在Java 10上工作,没有任何借口.

All in all, any suggestions for a workaround are welcome. I need this code (or equivalent via a workaround) to work on Java 10, no excuses.

推荐答案

首先,我想确认我正在观察与您相同的行为.

First, I'd just like to confirm that I am observing the same behavior as you.

  • Windows 10 x64 Home
  • Java 1.8.0_172 x64-按预期工作
  • Java 10.0.1 x64-失败(显示为已禁用,但实际上并未禁用)

这似乎是一个错误,您应该这样报告.

This appears to be a bug and you should report it as such.

可能的解决方法

我发现,如果将以下代码添加到所有受影响的节点中,则将正确渲染有问题的节点:

I found that the nodes in question will be rendered correctly if you add to following code to all affected nodes:

node.disableProperty().addListener((observable, oldValue, newValue) -> {
    if (!newValue) { // if no longer disabled
        node.applyCss();
    }
});

如果您有很多可以禁用的节点,并且经受与问题中描述的事件顺序相同的事件,则这可能会变得很乏味.创建某种类型的实用程序方法来处理此问题可能是明智的做法.

This could become tedious if you have a lot of nodes that can be disabled and are subject to the same sequence of events as described in your question. It may be prudent to create some type of utility method to handle this.

修改

我发现使propertyProvider不可见的顺序会影响我提供的解决方法.如果在之后使propertyProvider不可见,则显示新的TitledPane,然后,当您返回其他TitledPane时,TextFieldButton仍被禁用.不是.尚未找到解决方法.

I found that the order of when you make propertyProvider invisible affects the workaround I provided. If you make propertyProvider invisible after you display the new TitledPane then, when you go back to the other TitledPane, the TextField and Button still render as disabled when they are not. Haven't found a way around that yet.

这篇关于a.disableProperty().bind(b.visibleProperty())导致Java FX 10中的元素渲染无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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