如何让两个 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());
我尝试了一些方法,但没有用。基本上我试图通过创建一个新的 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());