2013-09-03 54 views
13

Vì vậy, tôi có một TextArea và khi người dùng dán các đoạn văn vào đó, hoặc chỉ viết vào đó, tôi muốn nó mở rộng theo chiều dọc để hiển thị tất cả văn bản có sẵn. I E. không sử dụng thanh cuộn trong trường văn bản ... giống như những gì xảy ra trên nhiều trang web. Nhiều người dùng, bao gồm cả bản thân tôi, không muốn bị buộc phải chỉnh sửa trong một cửa sổ nhỏ. Chính xác cách thức hoạt động của hộp cập nhật trạng thái Facebook.Làm cách nào để tôi có thể tạo một đoạn TextArea để lấp đầy nội dung, mở rộng phụ huynh trong quá trình này?

Tôi đã thử

myTextArea.autoSize() 

bọc trong một

myTextArea.textProperty().addListener(new ChangeListener()....);

nhưng điều đó không làm việc. Tôi nghĩ rằng nó hạnh phúc tự động kích thước hiện tại của nó.

Bên trái, bên phải & neo hàng đầu được đặt thành neo mẹ là AnchorPane. Tôi đã thử nó với phần dưới kèm theo và không kèm theo. Lý tưởng nhất là tôi muốn phát triển ô neo khi textarea phát triển.

Tôi không ngại đọc TextProperty và tính toán kích thước trình kích hoạt mà tôi tự đặt ... nhưng điều này có vẻ là cách tiếp cận hacky NẾU đã có phương pháp hay nhất. Số lượng các thuộc tính và các đối tượng phụ của javafx đủ daunting rằng nó có vẻ giống như một điểm tốt để đặt câu hỏi ở đây, thay vì cố gắng tìm ra bao nhiêu điểm ảnh font/đoạn văn vv đang chiếm.

Cập nhật:

Vì vậy, tôi nghĩ có lẽ tôi đã overthinking nó, và tất cả những gì cần làm là để chuyển đổi các thanh cuộn ra và phần còn lại sẽ xảy ra. Than ôi, tìm kiếm các lĩnh vực có sẵn và phương pháp cho "di chuyển", "dọc", "vbar" đi kèm với không có gì tôi có thể sử dụng. ScrollTopProperty trông giống như nó cho cái gì khác.

+0

đây là một nóng mẫu nó có thể được achived: https://stackoverflow.com/questions/44141172/javafx-expandable-textfield-sample – kamirru

Trả lời

7

Chờ đợi tốt hơn, tôi sử dụng giải pháp hacky này.

  • tra cứu thanh cuộn dọc của vùng văn bản.
  • làm cho nó minh bạch
  • nghe đến tài sản hữu hình của nó
  • khi cuộn trở nên hữu hình tôi thêm một hàng vào textarea.

Mã:

import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.ObservableList; 
import javafx.geometry.Orientation; 
import javafx.scene.Node; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.control.TextArea; 
import javafx.scene.layout.AnchorPane; 
import javafx.stage.Stage; 

public class GrowGrowTextArea extends Application { 
    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     AnchorPane root = new AnchorPane(); 
     root.setStyle("-fx-padding:20;-fx-background-color:dodgerblue;"); 
     final TextArea textArea = new TextArea(); 
     AnchorPane.setTopAnchor(textArea, 10.0); 
     AnchorPane.setLeftAnchor(textArea, 10.0); 
     AnchorPane.setRightAnchor(textArea, 10.0); 
     root.getChildren().add(textArea); 
     primaryStage.setScene(new Scene(root, 400, 300)); 
     primaryStage.show(); 
     ScrollBar scrollBar = lookupVerticalScrollBar(textArea); 
     scrollBar.setOpacity(0.0); 
     scrollBar.visibleProperty().addListener(new ChangeListener<Boolean>() { 

      @Override 
      public void changed(ObservableValue<? extends Boolean> source, 
           Boolean wasVisible, 
           Boolean isVisible) { 
       if (isVisible) { 
        textArea.setPrefRowCount(textArea.getPrefRowCount() + 1); 
        textArea.requestLayout(); 
       } 
      } 
     }); 

    } 

    private ScrollBar lookupVerticalScrollBar(Node node) { 
     if (node instanceof ScrollBar && ((ScrollBar)node).getOrientation() == Orientation.VERTICAL) { 
      return (ScrollBar) node; 
     } 
     if (node instanceof Parent) { 
      ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable(); 
      for (Node child : children) { 
       ScrollBar scrollBar = lookupVerticalScrollBar(child); 
       if (scrollBar != null) { 
        return scrollBar; 
       } 
      } 
     } 
     return null; 
    } 
} 
+0

Thanx cho đăng tải! Sẽ đánh dấu nó chính xác khi tôi có thời gian để kiểm tra ... mà không phải là tại thời điểm này không may. –

+0

Cảm ơn gontard. Mặc dù như bạn đã nói, nó là một chút hacky ... nhưng cleaver none-the-less. Tôi thấy rằng nó không hoạt động đúng. Nó không mở rộng chính xác nếu có các dòng trống trong vùng văn bản và cũng chờ mở rộng cho đến khi các ký tự được nhập vào dòng cuối cùng. – Travis

11

Vấn đề; chiều cao của textArea là muốn được phát triển hoặc thu nhỏ trong khi văn bản của nó đang thay đổi bằng cách gõ của người dùng hoặc sao chép-dán. Đây là một cách tiếp cận khác:

public class TextAreaDemo extends Application { 

    private Text textHolder = new Text(); 
    private double oldHeight = 0; 

    @Override 
    public void start(Stage primaryStage) { 
     final TextArea textArea = new TextArea(); 
     textArea.setPrefSize(200, 40); 
     textArea.setWrapText(true); 

     textHolder.textProperty().bind(textArea.textProperty()); 
     textHolder.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() { 
      @Override 
      public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) { 
       if (oldHeight != newValue.getHeight()) { 
        System.out.println("newValue = " + newValue.getHeight()); 
        oldHeight = newValue.getHeight(); 
        textArea.setPrefHeight(textHolder.getLayoutBounds().getHeight() + 20); // +20 is for paddings 
       } 
      } 
     }); 

     Group root = new Group(textArea); 
     Scene scene = new Scene(root, 300, 250); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     // See the explanation below of the following line. 
     // textHolder.setWrappingWidth(textArea.getWidth() - 10); // -10 for left-right padding. Exact value can be obtained from caspian.css 
    } 

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

Nhưng nó có nhược điểm; chiều cao của textarea chỉ thay đổi nếu có ngắt dòng (ví dụ: Nhập phím) giữa nhiều dòng, nếu người dùng nhập đủ dài văn bản được bao bọc thành nhiều dòng nhưng chiều cao không thay đổi.

Để workaround nhược điểm này tôi đã thêm dòng này

textHolder.setWrappingWidth(textArea.getWidth() - 10); 

sau primaryStage.show();. Nó hoạt động tốt cho các kiểu chữ dài mà người dùng không phải là dấu ngắt dòng. Tuy nhiên điều này tạo ra một vấn đề khác.Sự cố này xảy ra khi người dùng xóa văn bản bằng cách nhấn "backspace". Vấn đề xảy ra chính xác khi chiều cao textHolder được thay đổi và chiều cao của textArea được đặt thành giá trị mới. IMO nó có thể là một lỗi, không quan sát sâu hơn.

Trong cả hai trường hợp, quá trình sao chép được xử lý đúng cách.

+0

Như bạn đã nói, nó có một vài vấn đề. Mặc dù vào thời điểm này nó là lựa chọn tốt nhất mà tôi đã nhìn thấy. :/ – Travis

+0

điều này thực sự là giải pháp tốt nhất tôi đã thấy cho đến nay. làm cho tôi thực sự ghét javafx rằng một vấn đề rõ ràng như vậy chỉ có các giải pháp hacky. –

+0

anyway, tôi sẽ đề nghị 'textHolder.getLayoutBounds(). GetHeight() * 1.05' khi TextArea của tôi trở nên quá nhỏ nếu có quá nhiều dòng được thêm vào. các '* 1.05' dường như hoàn hảo để lừa. –

1

Tôi gặp sự cố tương tự với việc tạo TextArea mở rộng. Tôi đã tạo TextArea trông giống như TextField và mở rộng theo chiều dọc mỗi khi không có thêm không gian trong dòng. Tôi đã thử nghiệm tất cả các giải pháp mà tôi có thể tìm thấy về chủ đề này trên ngăn xếp và các nguồn khác có sẵn. Tôi tìm thấy vài giải pháp tốt nhưng không đủ tốt.

Sau nhiều giờ chiến đấu, tôi đã tìm ra cách tiếp cận này.

Tôi mở rộng lớp TextArea, ghi đè bố cụcChildren() và thêm người nghe vào chiều cao văn bản.

@Override 
    protected void layoutChildren() { 
    super.layoutChildren(); 
    setWrapText(true); 
    addListenerToTextHeight(); 
    } 

    private void addListenerToTextHeight() { 
    ScrollPane scrollPane = (ScrollPane) lookup(".scroll-pane"); 
    scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER); 
    scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER); 

    StackPane viewport = (StackPane) scrollPane.lookup(".viewport"); 

    Region content = (Region) viewport.lookup(".content"); 

    Text text = (Text) content.lookup(".text"); 
    text.textProperty().addListener(textHeightListener(text)); 
    } 

    private InvalidationListener textHeightListener(Text text) { 
    return (property) -> { 
     // + 1 for little margin 
     double textHeight = text.getBoundsInLocal().getHeight() + 1; 

     //To prevent that our TextArena will be smaller than our TextField 
     //I used DEFAULT_HEIGHT = 18.0 
     if (textHeight < DEFAULT_HEIGHT) { 
     textHeight = DEFAULT_HEIGHT; 
     } 

     setMinHeight(textHeight); 
     setPrefHeight(textHeight); 
     setMaxHeight(textHeight); 
    }; 
    }