加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

JavaFX Tableview和ScrollPane滚动问题

发布时间:2020-05-25 13:47:30 所属栏目:Java 来源:互联网
导读:我从2年前开始使用 JavaFX.现在我正在使用 JavaFX创建像控件一样的电子表格.为了创建控件,我使用TableView和ScrollPane以及用于Spreadsheet Row标题的ListView控件,因为JavaFX不提供对行标题的支持.除了一件事我滚动表,最初表时,一切正常和scrollpane行同步滚

我从2年前开始使用 JavaFX.现在我正在使用 JavaFX创建像控件一样的电子表格.为了创建控件,我使用TableView和ScrollPane以及用于Spreadsheet Row标题的ListView控件,因为JavaFX不提供对行标题的支持.除了一件事我滚动表,最初表时,一切正常和scrollpane行同步滚动,但在一些滚动后它的开始不匹配.我已经附加了相同的屏幕截图.

1)没有滚动的初始屏幕

2)滚动后的屏幕

以下是我在pastebin中粘贴的此控件的代码段.

1)Cells.java

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Cells extends Application {

    public void start(Stage stage) {
        stage.setScene(new Scene(new SpreadSheet(100,26)));
        stage.setTitle("Cells");
        stage.setWidth(400);
        stage.setHeight(400);
        stage.show();
    }

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

}

2)SpreadSheet.java

import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.HBox;


public class SpreadSheet extends HBox {

    public SpreadSheet(int height,int width) {
        super();
        Model model = new Model(height,width);

        TableView<ObservableList<Model.Cell>> table = new TableView<>();
        table.setEditable(true);
        table.setItems(model.getCellsAsObservableList());

        for (char w = 'A'; w < 'A'+width; w++) {
            TableColumn<ObservableList<Model.Cell>,String> column = new TableColumn<>(w+"");
            column.setSortable(false);
            column.setMinWidth(50);
            column.setCellFactory(TextFieldTableCell.forTableColumn());
            final char w0 = w;
            column.setCellValueFactory(param -> param.getValue().get(w0-'A').text);
            column.setOnEditStart(event -> {
                int row = event.getTablePosition().getRow();
                int col = event.getTablePosition().getColumn();
                Model.Cell c = model.getCells()[row][col];
                c.setShowUserData(true);
            });

            column.setOnEditCommit(event -> {
                int row = event.getTablePosition().getRow();
                int col = event.getTablePosition().getColumn();
                Model.Cell c = model.getCells()[row][col];
                System.out.println("Hello");
                c.userData.set(event.getNewValue());
                c.setShowUserData(false);
            });
            table.getColumns().add(column);
        }

        ListView<String> rowHeaders = new ListView<>();
        rowHeaders.getItems().add("");
        for (int i = 0; i < height; i++) {
            rowHeaders.getItems().add(i+"");
            }
        ScrollPane scrolledRowHeaders = new ScrollPane(rowHeaders);
        scrolledRowHeaders.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrolledRowHeaders.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);


        table.getChildrenUnmodifiable().addListener((ListChangeListener<Node>) c -> {
            ScrollBar vbarTable = (ScrollBar) table.lookup(".scroll-bar:vertical");
            ScrollBar vbarRowHeaders = (ScrollBar) scrolledRowHeaders.lookup(".scroll-bar:vertical");

            if (vbarRowHeaders != null && vbarTable != null)
                vbarTable.valueProperty().bindBidirectional(vbarRowHeaders.valueProperty());


        });

        getChildren().addAll(scrolledRowHeaders,table);

    }
}

3)Model.java

import java.util.List;

import javafx.beans.binding.Binding;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

class Model {

    private Cell[][] cells;

    Model(int height,int width) {
        cells = new Cell[height][width];
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                cells[i][j] = new Cell();
            }
        }
    }

    public Cell[][] getCells() {
        return cells;
    }

    public ObservableList<ObservableList<Cell>> getCellsAsObservableList() {
        ObservableList<ObservableList<Cell>> cs = FXCollections.observableArrayList();
        for (int i = 0; i < cells.length; i++) {
            cs.add(FXCollections.observableArrayList());
            for (int j = 0; j < cells[i].length; j++) {
                cs.get(i).add(cells[i][j]);
            }
        }
        return cs;
    }

    class Cell {

        public final StringProperty userData = new SimpleStringProperty("");
        public final StringProperty text = new SimpleStringProperty("");
        ObservableValue<Double>[] toArray(List<ObservableValue<Double>> l) {
              return l.toArray(new ObservableValue[l.size()]);
        }
        // Has same problem
//        public ObservableValue<Double> value = EasyBind.map(userData,Parser::parse)
//                .flatMap(f -> Bindings.createObjectBinding(() -> f.eval(Model.this),toArray(f.getReferences(Model.this))));
        // Has same problem
        public ObservableValue<Double> value =
                Bindings.createObjectBinding(() -> {
                    System.out.println(System.currentTimeMillis());
                    Formula f = Parser.parse(userData.get());
                    ObservableValue<Double>[] fs = toArray(f.getReferences(Model.this));
                    Binding<Double> d = Bindings.createObjectBinding(() -> {
                        double v = f.eval(Model.this);
//                        text.set(String.valueOf(v));
                        return v;
                    },fs);
                    d.addListener((v,o,n) -> {
                        // ???
                    });
                    return d.getValue();
                },userData);


        public void setShowUserData(Boolean b) {
            if (b)  text.setValue(userData.get());
            else text.setValue(String.valueOf(value.getValue()));
        }

    }
}

4)Parser.java

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Parser {

    private static Parser instance = new Parser();
    private static Tokenizer tokenizer;
    static {
        tokenizer = new Tokenizer();
        tokenizer.add("[a-zA-Z_]d+",Token.CELL);
        tokenizer.add("[a-zA-Z_]w*",Token.IDENT);
        tokenizer.add("-?d+(.d*)?",Token.DECIMAL);
        tokenizer.add("=",Token.EQUALS);
        tokenizer.add(",",Token.COMMA);
        tokenizer.add(":",Token.COLON);
        tokenizer.add("(",Token.OPEN_BRACKET);
        tokenizer.add(")",Token.CLOSE_BRACKET);
    }

    public static Formula parse(String formulaString) {
        return instance.parseFormula(formulaString);
    }


    String formulaString;
    LinkedList<Token> tokens;
    Token lookahead;

    private Parser() {}

    private Formula parseFormula(String formulaString) {
        this.formulaString = formulaString;

        try {
            tokenizer.tokenize(formulaString.replaceAll("s+",""));
        } catch (ParseError e) {
            System.out.println(e.getMessage());
        }
        this.tokens = tokenizer.getTokens();
        if (tokens.isEmpty()) return Formula.Empty;
        lookahead = this.tokens.getFirst();

        return formula();
    }

    private Formula formula() {
        switch(lookahead.token) {
            case Token.DECIMAL:
                String n = lookahead.sequence;
                nextToken();
                return new Number(Double.parseDouble(n));
            case Token.EQUALS:
                nextToken();
                return expression();
            case Token.EPSILON:
                return Formula.Empty;
            default:
                return new Textual(formulaString);
        }
    }

    private Formula expression() {
        switch(lookahead.token) {
            case Token.CELL:
                int c = lookahead.sequence.charAt(0) - 'A';
                int r = Integer.parseInt(lookahead.sequence.substring(1));
                nextToken();
                if (lookahead.token == Token.COLON) { // Range
                    nextToken();
                    if (lookahead.token == Token.CELL) {
                        int c2 = lookahead.sequence.charAt(0) - 'A';
                        int r2 = Integer.parseInt(lookahead.sequence.substring(1));
                        nextToken();
                        return new Range(new Coord(r,c),new Coord(r2,c2));
                    } else {
                        throw new ParseError("Incorrect Range: " + lookahead.sequence);
                    }
                } else {
                    return new Coord(r,c);
                }
            case Token.DECIMAL:
                Double d = Double.parseDouble(lookahead.sequence);
                nextToken();
                return new Number(d);
            case Token.IDENT:
                return application();
            default:
                throw new ParseError("Incorrect Expression: " + lookahead.sequence);
        }
    }

    private Formula application() {
        String opName = lookahead.sequence;
        nextToken();
        if (lookahead.token != Token.OPEN_BRACKET)
            throw new ParseError("No opening bracket: " + opName);
        nextToken();
        List<Formula> args = new ArrayList<Formula>();
        while (true) {
            if (lookahead.token == Token.EPSILON)
                throw new ParseError("No closing bracket");
            args.add(expression());
            if (lookahead.token == Token.COMMA) nextToken();
            if (lookahead.token == Token.CLOSE_BRACKET)
                return new Application(opName,args);
        }
    }

    private void nextToken() {
        tokens.pop();
        if (tokens.isEmpty()) lookahead = new Token(Token.EPSILON,"");
        else lookahead = tokens.getFirst();
    }

}

class ParseError extends RuntimeException {

    ParseError(String message) {
        super(message);
    }

}

class Token {

    public static final int EPSILON = 0;
    public static final int EQUALS = 1;
    public static final int IDENT = 2;
    public static final int DECIMAL = 3;
    public static final int OPEN_BRACKET = 4;
    public static final int CLOSE_BRACKET = 5;
    public static final int COMMA = 6;
    public static final int COLON = 7;
    public static final int CELL = 8;

    public final int token;
    public final String sequence;

    public Token(int token,String sequence) {
        this.token = token;
        this.sequence = sequence;
    }

}

class Tokenizer {

    private LinkedList<TokenInfo> tokenInfos;
    private LinkedList<Token> tokens;

    public Tokenizer() {
        tokenInfos = new LinkedList<TokenInfo>();
        tokens = new LinkedList<Token>();
    }

    public void add(String regex,int token) {
        tokenInfos.add(new TokenInfo(Pattern.compile("^("+regex+")"),token));
    }

    public void tokenize(String s) {
        tokens.clear();
        while (!s.equals("")) {
            boolean match = false;
            for (TokenInfo info : tokenInfos) {
                Matcher m = info.regex.matcher(s);
                if (m.find()) {
                    match = true;
                    String tok = m.group().trim();
                    tokens.add(new Token(info.token,tok));
                    s = m.replaceFirst("");
                    break;
                }
            }
            if (!match) throw new ParseError("Unexpected char in input: " + s);
        }
    }

    public LinkedList<Token> getTokens() {
        return tokens;
    }

    private static class TokenInfo {

        public final Pattern regex;
        public final int token;

        public TokenInfo(Pattern regex,int token) {
            super();
            this.regex = regex;
            this.token = token;
        }

    }

}

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读