JavaFX,TextArea的通用大小取决于内容为“消息泡泡”

时间:2018-04-03 01:20:21

标签: javafx textarea

提前感谢您抽出时间。

目前,我正在为一个足够简单的客户端/服务器应用程序创建JavaFX GUI。 在SplitPane的右侧是GridPane,每当发送或接收消息时,该消息显示在GridPane中的新ROW中,并且消息基本上是ImageView(图像),后跟TextArea。显示发送/接收的消息的字符串。

我的问题是,经过一周多的时间后,我无法弄清楚如何为TextArea中的文本块适当调整TextArea的大小。 在将此问题标记为重复之前,我已经尝试了我能找到的每个实现。 首先,ScrollBar监听解决方案在运行时不起作用,这只在用户输入时才起作用,因此我将其作为我特定问题的潜在解决方案。

我正在使用的解决方案(不起作用)是使用Text对象并获取TextArea的THAT布局边界/高度。 我的TextAreas(充当消息气泡)的宽度相同,我现在指定minWidth为300.0,问题再次出现在高度上。

我的代码如下:

    HBox messageBox = new HBox(10);
    messageBox.setPadding(new Insets(0, 0, 0, 25));

    TextArea textArea = new TextArea();
    textArea.setText(message);
    textArea.setFont(new Font(20));
    textArea.setWrapText(true);
    final Text helper = new Text();
    helper.setText(message);
    helper.setFont(textArea.getFont());
    helper.setWrappingWidth(300.0);
    double width = helper.getLayoutBounds().getWidth();
    double height = helper.getLayoutBounds().getHeight(); 

    textArea.setMinWidth(width);
    textArea.setPrefHeight(height);

    messageBox.getChildren().addAll(imageView, textArea);
    messagePane.add(messageBox, 0, rowCount);
    rowCount++;

请注意,我还尝试将我的助手Text对象放入一个抛弃的窗格,这会产生几乎相同的结果。 最后,我尝试将填充添加到TextArea的setPrefHeight()中,我尝试过MinHeight / MaxHeight组合。

enter image description here 这张照片说明了我的第一个问题,第三条消息在文本块的末尾下面有太多空间,而前面的消息看起来很好,(IMO)。第二张图片显示了我的第二个问题,较大的文本块似乎逐渐减小TextAreas的宽度或者可能是HBox的宽度。在添加这些后续的HBox之前,突出显示的TextArea有足够的空间。

Tgggggggg

有任何解决方案可以满足我的需求吗? 我将非常感激,谢谢你的时间!

基思

1 个答案:

答案 0 :(得分:1)

这不是一项微不足道的任务(除非你找到一个解决方法),我恐怕你不得不以某种方式计算实际的宽度和高度并将其应用到TextArea。我想的方法是通过试错法找到你的魔法数字或者更好地把消息文本添加到Label然后计算它的尺寸(宽度,高度),然后使用它们来设置TextArea。这是一个小例子:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class MessagerTest extends Application {

    private VBox displayPane = new VBox(5);
    private TextArea messageArea = new TextArea();

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

    @Override
    public void start(Stage stage) throws Exception {

        BorderPane mainPane = new BorderPane();
        ScrollPane scrollPane = new ScrollPane(displayPane);

        displayPane.setPadding(new Insets(10));

        displayPane.prefWidthProperty().bind(scrollPane.widthProperty());
        scrollPane.prefWidthProperty().bind(mainPane.widthProperty());
        scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);

        mainPane.setCenter(scrollPane);
        mainPane.setBottom(messageArea);

        mainPane.setPadding(new Insets(10));

        messageArea.setPrefHeight(120);
        messageArea.setFont(Font.font(16));
        messageArea.setWrapText(true);
        messageArea.setPromptText("Type a message here...");
        messageArea.setOnKeyPressed(e -> {
            if (e.getCode() == KeyCode.ENTER && !e.isShiftDown()) {
                sendMessage(messageArea.getText());
                e.consume();
            } else if (e.getCode() == KeyCode.ENTER && e.isShiftDown()) {
                messageArea.appendText(System.lineSeparator());
            }
        });

        mainPane.getStylesheets().add(this.getClass().getResource("messanger.css").toExternalForm());
        stage.setScene(new Scene(mainPane, 450, 600));
        stage.show();

    }

    private void sendMessage(String message) {

        TextArea txtArea = new TextArea(message);
        txtArea.setWrapText(true);

        txtArea.setId("Message");
        txtArea.setEditable(true);

        resizeTextArea(txtArea);

        displayPane.getChildren().add(txtArea);
        messageArea.clear();
    }

    private void resizeTextArea(TextArea txtArea) {
        String text = txtArea.getText();

        double maxWidth = displayPane.getWidth() - 40;

        HBox h = new HBox();
        Label l = new Label(text);
        l.setFont(Font.font(15));
        h.getChildren().add(l);
        Scene s = new Scene(h);
        l.impl_processCSS(true);
        l.applyCss();

        double width = l.prefWidth(-1) + 20;
        double height = l.prefHeight(-1) + 20;

        if (width > maxWidth) {
            txtArea.setMaxWidth(maxWidth);
            txtArea.setMinWidth(maxWidth);
        } else {
            txtArea.setMaxWidth(width);
            txtArea.setMinWidth(width);
        }

        txtArea.setMinHeight(height);
        txtArea.setMaxHeight(height);
    }

}

如果你也想要CSS文件:

#Message {
    -fx-background-color : transparent;
    -fx-font-size : 15px;
    -fx-text-fill: black;
    -fx-display-caret:false;
}

#Message .content:pressed  {
    -fx-background-color: #E5E4E4;
}

#Message .content {
    -fx-background-color: #F1F0F0;
}

.scroll-pane > .viewport {
   -fx-background-color: white;
}

enter image description here

上面的问题是,当你写一切都是一行并让TextArea包装文本时,这会导致实际的标签高度变大,所以在这种情况下你必须稍微调整一下这些值

说实话,我不确定这是否是您可以采取的唯一方法,或者它是否是最佳解决方案。我相信它值得失去鼠标选择的文本并使用Label而不是使用TextArea执行上述操作。