非常に複雑JavaFXアプリケーションでは、私は可能なレンダリングのバグに直面しました。最後の2日間、私は次のような単純なアプリケーションにそれを追跡することができます。次SSCCEは、特定の状況では、いくつかのJavaFXコンポーネントが正しくレンダリングされていないことを示しています。その結果、コンボボックスとリストビューは、変更されたコンテンツは表示されません。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TabPane.TabClosingPolicy;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ComboManagedBug extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
// add combo box
ComboBox<String> combo = new ComboBox<>();
combo.setPromptText("Choose a value...");
combo.getItems().setAll("1", "2", "3");
// add list view
ListView<Label> list = new ListView<>();
// add "add" button
Button add = new Button("Add");
add.setOnAction(e -> list.getItems().add(
new Label(combo.getSelectionModel().getSelectedItem())));
// add tab pane
Tab tab1 = new Tab("First", new VBox(combo, add, list));
Tab tab2 = new Tab("Second");
TabPane tabs = new TabPane(tab1, tab2);
tabs.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); // important!
// add "next" and "cancel" buttons at bottom
Button next = new Button("Next");
Button cancel = new Button("Cancel (Triggers refresh)");
HBox buttons = new HBox(next, cancel);
// install tab listener
tabs.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> {
// intention is to show next button only on first tab
boolean firstTab = c == tab1;
next.setVisible(firstTab);
next.setManaged(firstTab); // important!
});
// show
VBox root = new VBox(new VBox(tabs, buttons)); // important!
Scene scene = new Scene(root, 400, 400);
primaryStage.setTitle("ComboBox/ListView Rendering Bug Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
}
再現する手順:
- 起動プログラム
- コンボ値を選択してください - >コンボボックスが示す選択された値 - > OK
- 「追加」をクリック - >の値は、リストビューに追加されますと示されている - > OK
- アクティブに2番目のタブ
- アクティブに最初のタブ
- 以前のものとは異なるもののコンボ値を選択してください- > コンボボックスの値が変更されない- > BUG
- 「追加」をクリック- > リストビューの内容は変更されません- > BUG
- 一番下にある「キャンセル」をクリックします - >このボタンに添加していないリスナーがありませんでしたが、コンボボックスとリストビューの両方が正しい値を示しています。だから、両方の容器は、正しい値が含まれているように見えるが、いくつかのUIのリフレッシュがトリガされるまで、彼らは正しくレンダリングされません。
(「重要」でマークされた)、このバグを再現するには、3つの重要なreqiurementsがあることに注意してください:
- このボタンを非表示にするタブを切り替えるときにトグル「次へ」ボタンの状態を管理(ノードの可視状態と一緒にノードを非表示にする通常の方法を参照のJavaFXを-のsetVisibleがない「非表示」要素ありません)
- TabClosingPolicy.UNAVAILABLE(非常に一般的なケース)
- VBoxの中のVBox(異なるJavaFXのコンポーネントノードをネストするとき、容易に実際の生活の中で起こることができます)。
すでに知られているこのバグがある、と誰もがこのための回避策を知っているのですか?私が試したPlatform.runLater(cancel.fire())と同様のものを、成功せず。
、任意のヒントをピーター、ありがとうございました。
ところで、これとは別に、当社の用途は現在、いくつかの年のためのJavaFX。我々の経験では、それは非常に信頼性が高いとプログラミングJavaFXのは楽しいです。私は、私たちの問題の簡単な解決策があると願っています:)
元の記事のコメントで述べたように、バグがJavaFXの8(オラクル)ではなく、それ以降のバージョン(OpenJFX)は発生しません。私は次の回避策を見つけました:
public static void fixTabRendering(TabPane tabs) {
if (tabs.getTabClosingPolicy() != TabClosingPolicy.UNAVAILABLE) return;
tabs.setTabClosingPolicy(TabClosingPolicy.SELECTED_TAB);
for (Node node : tabs.lookupAll(".tab-close-button")) {
// hide "close" button to imitate TabClosingPolicy.UNAVAILABLE
node.setStyle("-fx-background-color:transparent;-fx-shape:null;-fx-pref-width:0.001");
}
}
このコードは、ステージ(そうでなければ表示した後に実行されるべきであるlookupAll()戻り値ヌルならびにタブペインにタブを追加した後に)。後者は、タブリスナーを経由して実現することができます。
tabs.getTabs().addListener((Change<?> change) ->
Platform.runLater(() -> fixTabRendering(tabs)));
Platform.runLater()はそうでないので、必要とされるlookupAll()は、追加のタブのノードを返さなくてもよいです。
たぶん、この解決策は、誰かを助けることができます:)