如何让两个 TextArea 在 JavaFX 中一起滚动

How can I make two TextArea scroll together in JavaFX

我尝试了一些方法,但没有用。基本上我试图通过创建一个新的 TextArea 来做到这一点。但我只是想让这两个卷轴相互关联 usersChatArea scroll 和 myChatArea scroll 有什么简单的方法可以让我用滚动条滚动一个,另一个会自动跟随?

这是我的 MainChatController:

package ru.geekbrains.chat.client;
import com.sun.javafx.menu.MenuItemBase;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.NodeOrientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.ResourceBundle;

public class MainChatController {

    public TextArea usersChatArea = new TextArea();
    public TextArea myChatArea = new TextArea();
    public ListView onlineUsers;
    public TextField inputField;
    public Button btnSendMessage;
    public Button btnSendMessageUser;
    public Button btnOpenAboutWindow;


    public void mockAction(ActionEvent actionEvent) {
        System.out.println("MOCK!");
    }

    public void exit(ActionEvent actionEvent) {
        Platform.exit();
    }

    public void showAbout(ActionEvent actionEvent) {

    }

    public void showHelp(ActionEvent actionEvent) throws URISyntaxException, IOException {
        Desktop desktop = Desktop.getDesktop();
        desktop.browse(new URI("https://docs.google.com/document/d/1wr0YEtIc5yZtKFu-KITqYnBtp8KC28v2FEYUANL0YAM/edit?usp=sharing"));
    }


    public void sendMessage(ActionEvent actionEvent) {
        appendTextFromTF();
    }

    public void sendMessageUser(ActionEvent actionEvent) {
        appendTextFromTF2();
    }

    private void appendTextFromTF() {
        int c = 1;
        String msg1 = inputField.getText();
        myChatArea.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
        if (msg1.isEmpty()) return;
        for (int i = 0; i < c ; i++) {
            usersChatArea.appendText(System.lineSeparator());
        }
        myChatArea.appendText( msg1 + " :ME  " + System.lineSeparator());
        c++;
        inputField.clear();
    }

    private void appendTextFromTF2() {
        int b = 1;
        String msg = inputField.getText();
        usersChatArea.setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
        if (msg.isEmpty()) return;
        for (int i = 0; i < b ; i++) {
            myChatArea.appendText(System.lineSeparator());
        }
        b++;
        usersChatArea.appendText("  User: " + msg + System.lineSeparator());
        inputField.clear();
    }

    public void btnOpenAboutWindow(ActionEvent actionEvent) {
        btnOpenAboutWindow.setOnAction(new EventHandler<ActionEvent>() {
                                           public void handle(ActionEvent event) {
                                               try {
                                                   FXMLLoader loader = new FXMLLoader();
                                                   loader.setLocation(getClass().getResource("/about.fxml"));
                                                   Parent root = loader.load();

                                                   Scene scene = new Scene(root);
                                                   Stage stage = new Stage();
                                                   stage.setScene(scene);
                                                   stage.setAlwaysOnTop(true);
                                                   stage.setTitle("About");
                                                   stage.show();
                                               } catch (IOException e) {
                                                   e.printStackTrace();
                                               }
                                           }
                                       }
        );

    }
}

这是我的应用程序:

package ru.geekbrains.chat.client;


import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;



public class App extends Application {

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

    @Override
    public void start(Stage stage) throws Exception {
        FXMLLoader loader = new FXMLLoader();

        loader.setLocation(getClass().getResource("/scene.fxml"));
        Parent root = loader.load();
        MainChatController mainChatController = new MainChatController();


        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setAlwaysOnTop(true);
        stage.setTitle("April Chat");
        stage.show();

    }
}


这是我的 FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<VBox prefHeight="500" prefWidth="650" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ru.geekbrains.chat.client.MainChatController">
    <children>
        <MenuBar>
            <Menu text="File">
                <MenuItem onAction="#mockAction" text="Item1" />
                <MenuItem onAction="#mockAction" text="Item2" />
                <MenuItem onAction="#mockAction" text="Item3" />
                <MenuItem onAction="#mockAction" text="Item4" />
                <MenuItem onAction="#exit" text="Exit" />
            </Menu>
            <Menu text="Edit">
                <MenuItem onAction="#mockAction" text="Item1" />
                <MenuItem onAction="#mockAction" text="Item2" />
                <MenuItem onAction="#mockAction" text="Item3" />
                <MenuItem onAction="#mockAction" text="Item4" />
                <MenuItem onAction="#mockAction" text="Item5" />
            </Menu>
            <Menu text="View">
                <MenuItem onAction="#mockAction" text="Item1" />
                <MenuItem onAction="#mockAction" text="Item2" />
                <MenuItem onAction="#mockAction" text="Item3" />
                <MenuItem onAction="#mockAction" text="Item4" />
                <MenuItem onAction="#mockAction" text="Item5" />
            </Menu>
            <Menu text="Help">
                <MenuItem onAction="#mockAction" text="Item1" />
                <MenuItem onAction="#mockAction" text="Item2" />
                <MenuItem onAction="#mockAction" text="Item3" />
                <MenuItem onAction="#showHelp" text="Help" />
                <MenuItem onAction="#showAbout" text="About" />

            </Menu>

        </MenuBar>
        <Button fx:id="btnOpenAboutWindow" onAction="#btnOpenAboutWindow" prefHeight="20.0" prefWidth="50.0" text="ABOUT">
            <HBox.margin>
                <Insets left="5.0" right="5.0" />
            </HBox.margin>
         <font>
            <Font size="10.0" />
         </font>
        </Button>

        <HBox prefHeight="471.0" prefWidth="705.0" VBox.vgrow="ALWAYS">
            <TextArea fx:id="usersChatArea" editable="false" nodeOrientation="LEFT_TO_RIGHT" prefHeight="461.0" prefWidth="250.0" style="-fx-border-color: white;" styleClass="usersChatArea" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
            <HBox.margin>
               <Insets left="3.0" />
            </HBox.margin>
            <padding>
               <Insets right="3.0" />
            </padding>

            <font>
               <Font size="18.0" />
            </font></TextArea>
            <TextArea fx:id="myChatArea" editable="false" nodeOrientation="RIGHT_TO_LEFT" prefHeight="461.0" prefWidth="256.0" style="-fx-border-color: white" styleClass="myChatArea" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
            <font>
               <Font size="18.0" />
            </font></TextArea>

            <ListView fx:id="onlineUsers" prefHeight="461.0" prefWidth="289.0">
                <HBox.margin>
                    <Insets left="5.0" right="5.0" />
                </HBox.margin>
            </ListView>
            <padding>
                <Insets bottom="5.0" top="5.0" />
            </padding>

        </HBox>
        <HBox>
            <TextField fx:id="inputField" onAction="#sendMessage" prefHeight="70.0" prefWidth="487.0" HBox.hgrow="ALWAYS">
                <HBox.margin>
                    <Insets left="5.0" right="5.0" />
                </HBox.margin>
            <font>
               <Font size="24.0" />
            </font>
            </TextField>
            <Button fx:id="btnSendMessage" onAction="#sendMessage" prefHeight="70.0" prefWidth="124.0" text="SEND">
                <HBox.margin>
                    <Insets left="5.0" right="5.0" />
                </HBox.margin>
            </Button>
            <Button fx:id="btnSendMessageUser" onAction="#sendMessageUser" prefHeight="70.0" prefWidth="127.0" text="SEND USER ">
                <HBox.margin>
                    <Insets left="5.0" right="5.0" />
                </HBox.margin>
            </Button>
            <padding>
                <Insets bottom="5.0" top="5.0" />
            </padding>
        </HBox>
    </children>
</VBox>

这是我的主要

package ru.geekbrains.chat.client;

public class Main {
    public static void main(String[] args) {
        App.main(args);
    }
}

A TextArea 具有您可以使用的这两个属性:

DoubleProperty scrollLeftProperty()

The number of pixels by which the content is horizontally scrolled.

DoubleProperty scrollTopProperty()

The number of pixels by which the content is vertically scrolled (docs).

下面一些简单的双向绑定可能足以满足您的需求:

// binding for horizontal scroll bar positions:
textArea1.scrollLeftProperty().bindBidirectional(textArea2.scrollLeftProperty());

// vertical:
textArea1.scrollTopProperty().bindBidirectional(textArea2.scrollTopProperty());