This article is the 14th day of JavaFX Advent Calendar 2016. Yesterday was @ sk44_'s "Set native icon with javafx-maven-plugin". Tomorrow is @ khasunuma's "Notes on calling Payara Micro API from JavaFX".
When implementing an editor in JavaFX, have you ever felt unsatisfied with the subtleties of expressiveness and extensibility of the standard TextArea?
--Font adjustment is difficult & all characters must be in the same font --Line numbers cannot be displayed by default --Syntax highlighting is not possible
In this article, I will introduce the library "RichTextFX" that I would like to recommend to those who want to make a tool with an editor function with JavaFX or who have made it.
A library developed by Tomas Mikula that provides rich text editing components. You can find demo code and usage in the GitHub repository.
BSD 2-Clause License and GPLv2 Classpath Exception Dual License.
Since javafx.scene.text.TextFlow is used, JDK 8 or higher Is required.
The environment used in this introduction is as follows.
Java SE | 1.8.0_102 |
---|---|
OS | Windows 10 |
Gradle | 3.0 |
Use Groovy's FizzBuzz as a very simple code.
FizzBuzz.groovy
(1..100)
.collect{it % 15 == 0 ? "FizzBuzz" : it % 3 ==0 ? "Fizz" : it % 5 == 0 ? "Buzz" : it}
.forEach{print it + ", "}
Add the following line to dependencies.
build.gradle
dependencies {
+ compile 'org.fxmisc.richtext:richtextfx:0.7-M2'
......
}
It is implemented as completely separate from the standard TextArea and is not compatible. be careful.
<?import org.fxmisc.richtext.CodeArea?>
Please note that Tooltip cannot be used.
- <TextArea fx:id="scripterInput" prefHeight="550.0" prefWidth="500.0">
- <tooltip><Tooltip text="input script." /></tooltip>
- </TextArea>
+ <CodeArea fx:id="scripterInput" prefHeight="550.0" prefWidth="500.0" />
The Controller class also needs to be modified.
-import javafx.scene.control.TextArea;
+import org.fxmisc.richtext.CodeArea;
TextArea and CodeArea are not compatible and need to be replaced.
@FXML
- public TextArea scripterInput;
+ public CodeArea scripterInput;
@FXML
- public TextArea scripterOutput;
+ public CodeArea scripterOutput;
Please note that the method names are also different.
- scripterOutput.setText(result);
+ scripterOutput.replaceText(result);
In its original state, there is no code highlighting, no line number display, and no wrapping.
Next, let's display the line number.
+import org.fxmisc.richtext.LineNumberFactory;
For each CodeArea object, specify ParagraphGraphicFactory as shown below.
Set line number display with setParagraphGraphicFactory
scripterOutput.setParagraphGraphicFactory(LineNumberFactory.get(scripterInput));
The line numbers are displayed like this.
If you try to break the line, the number of lines is displayed as much as the line break.
If it exceeds 100 lines, it will be displayed properly in 3 digits.
CodeArea requires a little implementation, but it can be highlighted with a specific format / keyword. A feature of this library is asynchronous highlighting. You can highlight your edits in real time. The implementation uses ReactFX, a library of Reactive Streams developed by the same Tomas Mikula.
An implementation example in the programming language Java is provided below.
https://github.com/TomasMikula/RichTextFX/blob/master/richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/JavaKeywordsAsync.java
Since it's a big deal, let's implement an example in Groovy this time.
It seems that there are 57 types below. If you are an expert, please point out if you make a mistake.
Groovy's keywords
abstract
as
assert
boolean
break
byte
case
catch
char
class
const
continue
def
default
do
double
else
enum
extends
false
final
finally
float
for
goto
if
implements
import
in
instanceof
int
interface
long
native
new
null
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
threadsafe
throw
throws
transient
true
try
void
volatile
while
Save this in a text file.
This time, Official sample is used as it is. I will use it.
CSS for keywords
.keyword {
-fx-fill: purple;
-fx-font-weight: bold;
}
.semicolon {
-fx-font-weight: bold;
}
.paren {
-fx-fill: firebrick;
-fx-font-weight: bold;
}
.bracket {
-fx-fill: darkgreen;
-fx-font-weight: bold;
}
.brace {
-fx-fill: teal;
-fx-font-weight: bold;
}
.string {
-fx-fill: blue;
}
.comment {
-fx-fill: cadetblue;
}
.paragraph-box:has-caret {
-fx-background-color: #f2f9fc;
}
You can put this CSS file anywhere, but this time it's right under src / main / resources.
First, define a class that has a method that is commonly used in the highlighting implementation. High from demo code JavaKeywordsAsync.java Extract only the part to be processed, and define only the common processing as an abstract class.
https://github.com/toastkidjp/javafx_advent2015/blob/v2016/src/main/java/jp/toastkid/highlight/Highlight.java
A method that executes asynchronous processing. The application calls this method.
Inherit the Highlight class above to create a class that highlights the Groovy grammar.
https://github.com/toastkidjp/javafx_advent2015/blob/v2016/src/main/java/jp/toastkid/highlight/GroovyHighlight.java
This method reads keywords from the keyword file prepared earlier and builds a regular expression for code highlighting. Regular expressions other than keywords are predefined. You can create a Highlight class for each language by modifying the following for each language.
Regular expression for code highlighting
private static final String PAREN_PATTERN = "\\(|\\)";
private static final String BRACE_PATTERN = "\\{|\\}";
private static final String BRACKET_PATTERN = "\\[|\\]";
private static final String SEMICOLON_PATTERN = "\\;";
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";
A method that gets the CodeArea text and converts it into a code highlighting format.
Add the following to the last line of the initialize method.
initialize()
new GroovyHighlight(scripterInput).highlight();
In addition, add the URI of the keyword coloring CSS file you prepared earlier to the stylesheets of the Scene object.
src/main/Directly under resources"keywords.css"To stylesheets
final ObservableList<String> stylesheets = thisStage.getScene().getStylesheets();
stylesheets.add(getClass().getClassLoader().getResource("keywords.css").toExternalForm());
This completes the preparation.
Try entering the FizzBuzz code below.
FizzBuzz
int i = 0
(1..100)
.collect{it % 15 == 0
? "FizzBuzz"
: it % 3 ==0
? "Fizz"
: it % 5 == 0
? "Buzz"
: it
}
.forEach{print it + ", "}
As you can see, ints are reddish, comments are light green, and string literals enclosed in "are blue.
I have put some simple implementation examples of other code highlights in the repository below, so if you are interested, please have a look (the application itself is not included).
https://github.com/toastkidjp/simple_highlight
I've recommended RichTextFX so far, but I wrote this article before embedding it in the actual application, and I noticed a bug that can not be overlooked later, so I will add it.
First, take a look at the image below. A window with three text areas lined up is displayed, and you can enter "next to" in the text area on the left (CodeArea of RichTextFX) to display conversion candidates.
Did you feel any discomfort? Yes, the entered text and conversion candidates are displayed in the upper left of the screen. It's pretty stupid ... This is RichTextFX's text control class [javafx.scene.control.TextInputControl](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/ It seems that the cause is that control / TextInputControl.html) is not implemented. ~~ I wonder if the author didn't need to enter multi-byte characters …… ~~
Of course, that was not the case, and the person who pointed out and proposed improvement measures created the issue.
How to insert text using an Input Method #146
Looking at the above issue, it was said that "I implemented InputMethodRequests and solved it", so I thought I would try if it could be improved, and I implemented it here [EditorInputMethodRequests](https://github. com / toastkidjp / RichTextFX_verification / blob / verification / src / main / java / jp / toastkid / rtfx_verification / EditorInputMethodRequests.java). It was fairly easy to implement using the getCaretBounds () method added in 1.0.0 of SNAPSHOT.
codeArea.setInputMethodRequests(new EditorInputMethodRequests(improved));
Well, rather than that, implement contents of setOnInputMethodTextChanged It was harder, but ...
codeArea.setOnInputMethodTextChanged(this::handleInputMethodEvent);
The central text area is where these fixes are applied. This
The input text is displayed properly at the caret position, and conversion candidates are also displayed below it. At last, it is a level that can be used as a minimum editor.
I thought that wasn't the case.
The text area on the right is the JavaFX standard TextArea. The uncertain part of the input text is underlined and the range of conversion candidates is highlighted with a blue background. It is difficult to put it to practical use unless it reaches this level, but we have not been able to implement the functions so far. If you are interested, it may be interesting to try it by referring to the code of the following 3 classes.
To use RichTextFX 1.0.0-SNAPSHOT as of February 6, 2017, add `` `https://oss.sonatype.org/content/repositories/snapshots/``` in the repositories of build.gradle. It is necessary to add the repository specification of.
build.gradle
repositories {
mavenCentral()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
https://github.com/toastkidjp/RichTextFX_verification/tree/verification
According to @ nodamushi's article "JavaFX 9 is getting better" of JavaFX Advent Calendar 2016, JavaFX 9 It seems that the implementation of TextArea that can display line numbers is possible only with the standard API. Expectations rise.
We have just briefly introduced RichTextFX, a library that helps you implement rich text editing capabilities in JavaFX. The official repository contains a variety of demo code that couldn't be introduced this time, such as an XML editor and font resizing. If you are developing a Markdown editor or HTML editor, or if you want to put sample code in a presentation tool developed in JavaFX, you may want to consider introducing this library.
RichTextFX CSS Reference Guide https://github.com/TomasMikula/RichTextFX/wiki/RichTextFX-CSS-Reference-Guide
-Differences corrected this time -Whole code modified this time