A reoccuring question in stackoverflow is how to present:
- Large amounts of editable text
- Display text paragraphs with words in different colors, sizes, … and optionally make them editable
In the following post I’d like to shade some light into this area of JavaFX and propose solutions allowing you to deal with them efficiently using runtime components developed as part of e(fx)clipse.
First of all to represent text the basic JavaFX classes you need to be aware of are:
javafx.scene.text.Text: Allows you to render a text chunk with a given color, font-size, font-family, …
javafx.scene.text.TextFlow: Allows you to layout text nodes mixed with other content like images, shapes, …
So the first conclusion we could draw from this information is that to display styled text we create a
Text elements with different color & font settings into it, embed the
TextFlow into a
ScrollPane and are done.
If you implement this you get something like this:
I’ve written more on this at https://tomsondev.bestsolution.at/2013/02/14/experimenting-with-textflow-from-javafx8/
Mission accomplished? Almost until you notice that performance for big amounts of styled text are horrendous because the complete text has to be renderer although you only see 60 lines! Other problems: E.g. you don’t have a cursor so selecting and copying lines from the text are not possible. Bottom line: We need to get smarter but before we do so we look into editing of text.
There are 3 main built-in controls to edit text:
javafx.scene.control.TextField: Edit a single line of text
javafx.scene.control.TextArea: Edit multi line text
javafx.scene.web.HTMLEditor: Edit styled text with the help of WebView
HTMLEditor solves a very special usecase so I’m not looking into it in this post.
TextField is only for one line so there’s only
TextArea left for larger chunks of text but
TextArea has multiple draw backs:
- You can not have different styled areas the complete text has to have one font, color, …
- It is totally inefficient because for rendering it uses 1 big
Text-Object, for a few lines this is ok but if you have text with more than thousand lines you’ll run into troubles
To sum up: JavaFX comes by default with NO control that allows you edit & display large text.
Text editing extensions coming with e(fx)clipse
Displaying small amount of styled text
In the upcoming 1.2.0 release we’ll provide you
org.eclipse.fx.ui.controls.styledtext.StyledString which implements the
CharSequence interface and a static helper which allows to generate a scenegraph node from it.
Useage looks like this:
StyledString s = new StyledString(); s.appendSegment("This","default-text"); s.appendSegment("is bold","bold-text"); s.appendSegment("and red","red-text"); s.appendSegment("and bold & red","bold-text","red-text"); Node n = Util.toNode(s); // ...
The 2nd, 3rd, … argument are CSS-Styleclasses!
Displaying and editing large amounts of text
While the above method is easy to use it is not solving the problem for large texts (styled or not) nor does it help you with editing, … in fact it simply uses the
TextFlow approach hiding the details from you.
To solve the problem of editing and displaying large text we need a control who virtualizes the Text-Elements to display and only the lines visible in the UI are part of the Scenegraph. Implementing something like this is not hard but it also is not needed because JavaFX comes with controls who work like this: All
*View controls like
TreeView are virtual in the sense that they only create as many
TreeCell, … as you see on screen.
Based upon this knowledge we implemented a
StyledTextArea which has a similar API than
SWT-StyledText to display and edit large styled texts, rendering 100,000 lines of code works in no time!
Useage is as simple as:
StyledTextArea t = new StyledTextArea(); t.getStylesheets().add(getClass().getResource("test.css").toExternalForm()); t.getContent().setText("This is a styled text!\nThis is the 2nd line with data\nBlaBla"); t.setStyleRanges( new StyleRange("text-highlight",0,30,null,null) , new StyleRange("text-highlight",34,5,null,null) );