JavaFx:标题窗格折叠后滚动重置

JavaFx:标题窗格折叠后滚动重置,java,javafx,scroll,tableview,javafx-8,Java,Javafx,Scroll,Tableview,Javafx 8,我正在使用标题窗格s滚动窗格s和表格视图s,我遇到了一个问题,当我折叠标题窗格时,表格视图的水平滚动条会重置 下面是一个代码示例,您可以在其中进行验证: import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.ScrollPane; import javafx.scene.control.Table

我正在使用
标题窗格
s
滚动窗格
s和
表格视图
s,我遇到了一个问题,当我折叠标题窗格时,
表格视图
的水平
滚动条
会重置

下面是一个代码示例,您可以在其中进行验证:

import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableView;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.AnchorPane;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {

    @FXML
    private AnchorPane content;
    @FXML
    private TitledPane titledPane;
    @FXML
    private TableView<Object> tableView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        titledPane.prefHeightProperty().bind(content.heightProperty());
        tableView.prefWidthProperty().bind(content.widthProperty());

        tableView.getColumns().forEach(col -> col.setPrefWidth(300)); // to have enough "space" to scroll

        tableView.setItems(FXCollections.observableArrayList(new Object()));
    }

}
导入javafx.collections.FXCollections;
导入javafx.fxml.fxml;
导入javafx.fxml.Initializable;
导入javafx.scene.control.ScrollPane;
导入javafx.scene.control.TableView;
导入javafx.scene.control.TitledPane;
导入javafx.scene.layout.ancorpane;
导入java.net.URL;
导入java.util.ResourceBundle;
公共类控制器实现可初始化{
@FXML
私人锚烷含量;
@FXML
私有标题窗格标题窗格;
@FXML
私有TableView TableView;
@凌驾
公共void初始化(URL位置、ResourceBundle资源){
titledPane.prefHeightProperty().bind(content.heightProperty());
tableView.prefWidthProperty().bind(content.widthProperty());
tableView.getColumns().forEach(col->col.setPrefWidth(300));//有足够的“空间”滚动
setItems(FXCollections.observearraylist(newobject());
}
}
FXML:



知道如何防止每次折叠窗格时tableview的滚动复位吗

经过一番挖掘,看起来VirtualFlow中的一些布局优化可能是原因所在(如果滚动的内容不是TableView,那么一切似乎都很好,尽管没有进行彻底的分析)

发生的情况是:

  • 折叠期间,标题窗格的内容垂直调整为0
  • 在VirtualFlow的布局中,零高度/宽度是一种特殊情况,除了隐藏所有内容外,什么也不做,包括滚动条
  • 滚动条的visiblilty的内部侦听器将其值重置为0
一个试探性的(读:脏的,可能有不想要的副作用,除了这个快速的大纲之外完全没有测试过!)HackAround是一个定制的TableViewSkin,它试图“记住”最后一个非零值,并在再次可见时重置它

例如:

public class TitledPaneTableScroll extends Application {

    public static class TableViewScrollSkin<T> extends TableViewSkin<T> {

        DoubleProperty hvalue = new SimpleDoubleProperty();

         public TableViewScrollSkin(TableView<T> control) {
            super(control);
            installHBarTweak();
        }

        private void installHBarTweak() {
            // Note: flow and bar could be legally retrieved via lookup 
            // protected api pre-fx9 and post-fx9
            VirtualFlow<?> flow = getVirtualFlow();
            // access scrollBar via reflection 
            // this is my personal reflective access utility method - use your own :)
            ScrollBar bar = (ScrollBar) FXUtils
                    .invokeGetFieldValue(VirtualFlow.class, flow, "hbar");
            bar.valueProperty().addListener((s, o, n) -> {
                if (n.intValue() != 0) {
                    hvalue.set(n.doubleValue());
                    // debugging
                    //  new RuntimeException("who is calling? \n").printStackTrace();
                } 
                //LOG.info("hbar value: " + n + "visible? " + bar.isVisible());
            });

            bar.visibleProperty().addListener((s, o, n) -> {
                if (n) {
                    bar.setValue(hvalue.get());
                } 
            });
        }
    }

    int counter;
    private Parent createContent() {

        TableView<Object> table = new TableView<>(FXCollections.observableArrayList(new Object()) ) {

            @Override
            protected Skin<?> createDefaultSkin() {
                return new TableViewScrollSkin<>(this);
            }

        };
        table.getColumns().addAll(Stream
                .generate(TableColumn::new)
                .limit(10)
                .map(col -> {
                    col.setPrefWidth(50);
                    col.setText("" + counter++);
                    return col;
                })
                .collect(Collectors.toList())); 


        TitledPane titled = new TitledPane("title", table);
        titled.setAnimated(true);

        BorderPane content = new BorderPane(titled);
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent(), 400, 400));
       // stage.setTitle(FXUtils.version());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(TitledPaneTableScroll.class.getName());

}
public类TitledPaneTableScroll扩展应用程序{
公共静态类TableViewScrollSkin扩展了TableViewSkin{
DoubleProperty hvalue=新的SimpleDoubleProperty();
公共TableViewScrollSkin(TableView控件){
超级(控制);
installHBarTweak();
}
私有void installHBart虚弱(){
//注意:可以通过查找合法检索流和条
//fx9之前和fx9之后受保护的api
VirtualFlow流=getVirtualFlow();
//通过反射访问滚动条
//这是我的个人反射访问实用程序方法-使用您自己的:)
滚动条=(滚动条)FXUtils
.invokeGetFieldValue(VirtualFlow.class,流,“hbar”);
bar.valueProperty().addListener((s,o,n)->{
如果(n.intValue()!=0){
hvalue.set(n.doubleValue());
//调试
//新的RuntimeException(“谁在调用?\n”)。printStackTrace();
} 
//LOG.info(“hbar值:+n+“可见?”+bar.isVisible());
});
bar.visibleProperty().addListener((s,o,n)->{
如果(n){
setValue(hvalue.get());
} 
});
}
}
整数计数器;
私有父createContent(){
TableView table=newtableview(FXCollections.observearraylist(new Object())){
@凌驾
受保护的皮肤createDefaultSkin(){
返回新的TableViewScrollSkin(此);
}
};
table.getColumns().addAll(流
.generate(TableColumn::新建)
.限额(10)
.map(列->{
列设置宽度(50);
col.setText(“+计数器++);
返回列;
})
.collect(Collectors.toList());
标题窗格标题=新标题窗格(“标题”,表格);
标题为.setAnimated(true);
边框窗格内容=新边框窗格(标题);
返回内容;
}
@凌驾
public void start(Stage)引发异常{
stage.setScene(新场景(createContent(),400400));
//stage.setTitle(FXUtils.version());
stage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
@抑制警告(“未使用”)
专用静态最终记录器日志=记录器
.getLogger(TitledPaneTableScroll.class.getName());
}

hmm。。。不太明白为什么标题窗格周围有滚动窗格?为什么表的隐式滚动窗格不够好?可以忽略这一点,我只是将代码复制到一个虚拟项目中。在原始版本中,我在
滚动窗格
中有许多
标题窗格
s,这就是它存在的原因,但为了更简单,我删除了它。只是注意到这并不重要-隐式滚动窗格也重置为0。。。可能是一个bug:您希望标题窗格恢复到崩溃前的确切状态,您使用的是哪个版本的Java(Fx)?例如,我没有FXUtils。这只是一个用于反射访问的实用程序类-只需使用您自己的或使用node.lookup:)啊,好的,它使用
queryAA
工作。考虑到它或多或少是一种黑客行为,我必须对它进行测试,以确保它不会导致任何意外的错误,但无论如何,它是一种解决方案,谢谢;)酷-请随意编辑我的
public class TitledPaneTableScroll extends Application {

    public static class TableViewScrollSkin<T> extends TableViewSkin<T> {

        DoubleProperty hvalue = new SimpleDoubleProperty();

         public TableViewScrollSkin(TableView<T> control) {
            super(control);
            installHBarTweak();
        }

        private void installHBarTweak() {
            // Note: flow and bar could be legally retrieved via lookup 
            // protected api pre-fx9 and post-fx9
            VirtualFlow<?> flow = getVirtualFlow();
            // access scrollBar via reflection 
            // this is my personal reflective access utility method - use your own :)
            ScrollBar bar = (ScrollBar) FXUtils
                    .invokeGetFieldValue(VirtualFlow.class, flow, "hbar");
            bar.valueProperty().addListener((s, o, n) -> {
                if (n.intValue() != 0) {
                    hvalue.set(n.doubleValue());
                    // debugging
                    //  new RuntimeException("who is calling? \n").printStackTrace();
                } 
                //LOG.info("hbar value: " + n + "visible? " + bar.isVisible());
            });

            bar.visibleProperty().addListener((s, o, n) -> {
                if (n) {
                    bar.setValue(hvalue.get());
                } 
            });
        }
    }

    int counter;
    private Parent createContent() {

        TableView<Object> table = new TableView<>(FXCollections.observableArrayList(new Object()) ) {

            @Override
            protected Skin<?> createDefaultSkin() {
                return new TableViewScrollSkin<>(this);
            }

        };
        table.getColumns().addAll(Stream
                .generate(TableColumn::new)
                .limit(10)
                .map(col -> {
                    col.setPrefWidth(50);
                    col.setText("" + counter++);
                    return col;
                })
                .collect(Collectors.toList())); 


        TitledPane titled = new TitledPane("title", table);
        titled.setAnimated(true);

        BorderPane content = new BorderPane(titled);
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent(), 400, 400));
       // stage.setTitle(FXUtils.version());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(TitledPaneTableScroll.class.getName());

}