Javafx 文本多字着色 [英] Javafx Text multi-word colorization
问题描述
好的,我有一个 ListView 对象.我将它用作服务器的一种控制台窗口.这真的是我能想到的在这样的框中显示彩色文本的唯一方法.到目前为止,这很好用.现在我想要做的是在一个索引或一行上为不同的文本着色.
示例:
listView[0] = "Hello " + "world";
其中Hello"为绿色,world"为蓝色.如果这可以使用 javafx Text 或任何其他方式完成,我想知道如何去做.我使用 Javafx Text 作为主要罪魁祸首,因为您可以使用它进行自定义.
我希望每个人都能理解我在这里想做什么,如果没有,请告诉我,我会尝试改写一下.
解决方案
多亏了jewelsea,我才找到了解决方案.我采用了一些不同的方法,而不是使用细胞工厂.
ListView
ListViewconsoleWindow = new ListView<>();ArrayListconsoleBuffer = FXCollections.observableArrayList();consoleWindow.setItems(consoleBuffer);inputBox.setOnKeyPressed(new EventHandler() {@覆盖公共无效句柄(KeyEvent keyEvent){if (keyEvent.getCode() == KeyCode.ENTER) {consoleBuffer.add(parseInput.parseInputToArray(inputBox.getText()));}consoleWindow.scrollTo(consoleBuffer.size());}});
ConsoleInputParse:
公共类 ConsoleInputParse {私人字符串[] wordList = {};公共 ConsoleInputParse() {}公共流窗格 parseInputToArray(字符串输入){wordList = input.trim().split("[ ]+");返回着色();}公共流窗格着色(){ArrayList<文本>textChunks = new ArrayList<>();FlowPane bundle = new FlowPane();//Todo: 使用正则表达式检查有效词for (String word : wordList) {字符串间隔 = 单词 + " ";开关(字){案例你好": 案例你好":textChunks.add(customize(spaced, "purple"));休息;案例世界":案例世界":textChunks.add(customize(spaced, "blue"));休息;案例堆栈溢出":textChunks.add(customize(spaced, "orange", "Arial Bold", 15));默认:textChunks.add(customize(spaced, "black", "Arial", 13));休息;}}bundle.getChildren().addAll(textChunks);返回包;}公共文本定制(字符串字,字符串颜色){返回 TextBuilder.create().text(word).fill(Paint.valueOf(color)).build();}公共文本自定义(字符串字,字符串颜色,字符串字体){返回 TextBuilder.create().text(word).fill(Paint.valueOf(颜色)).font(Font.font(font, 12)).build();}公共文本定制(字符串字,字符串颜色,字符串字体,int fontSize){返回 TextBuilder.create().text(word).fill(Paint.valueOf(颜色)).font(Font.font(font, fontSize)).build();}}
工作示例"
创建自定义 中,您可以使用 TextFlow
来设置文本样式而不是FlowPane
中不同 Text
实例的组合.
示例代码
fruits.css
/*** Fruits.css - 与 FruitsDisplay.java 和* 确保构建系统将文件复制到输出路径*/.根 {-fx-font-size: 20px;-fx-font-family:Comic Sans MS";}.list-cell {-fx-background-color: 天蓝色;}.水果 {-fx-font-weight:粗体;-fx-font-style:斜体;}.苹果 {-fx-fill:森林绿;}.橘子 {-fx-fill:橙色;}.梨 {-fx-fill:黄金;}
FruitsDisplay.java
import javafx.application.Application;导入 javafx.collections.FXCollections;导入 javafx.scene.*;导入 javafx.scene.control.*;导入 javafx.scene.image.*;导入 javafx.scene.layout.*;导入 javafx.scene.text.Text;导入 javafx.stage.Stage;导入 java.util.*;/*** 使用 FlowPane 在 JavaFX 中创建样式文本的示例*/公共类 FruitsDisplay 扩展了应用程序 {private static final String[]fruits = {apple", orange", pear"};private static final String[]fruitImageLocs = {http://weknowyourdreamz.com/images/apple/apple-02.jpg",http://pic.1fotonin.com/data/wallpapers/165/WDF_2048871.png",http://vignette1.wikia.nocookie.net/pikmin/images/c/cc/Pear-01.jpg"};私人地图<字符串,图像>FruitImages = new HashMap<>();公共静态无效主(字符串 [] args){Application.launch(FruitsDisplay.class);}@覆盖公共无效开始(阶段阶段)抛出异常{stage.setTitle(水果故事");for (int i = 0; i list = new ListView<>(FXCollections.observableArrayList(fruits));list.setCellFactory(listView -> new FruitFlowCell());list.setPrefSize(440, 180);场景场景=新场景(列表);scene.getStylesheets().add(getResource(fruits.css"));stage.setScene(场景);舞台表演();}私人字符串getResource(字符串资源名称){返回 getClass().getResource(resourceName).toExternalForm();}私有类 FruitFlowCell 扩展了 ListCell{static final String FRUIT_PLACEHOLDER = "%f";{setContentDisplay(ContentDisplay.GRAPHIC_ONLY);}@覆盖protected void updateItem(String s, boolean empty) {super.updateItem(s, empty);if (s != null && !"".equals(s) && !isEmpty()) {setGraphic(createFruitFlow(s));} 别的 {设置图形(空);}}私有节点 createFruitFlow(String s) {开关 (s) {案例苹果":return createTextFlow("Eat an", FRUIT_PLACEHOLDER, s, "a day.");案例橙色":return createTextFlow("An ", FRUIT_PLACEHOLDER, s, "有很多维生素.");案例梨":return createTextFlow("A ", FRUIT_PLACEHOLDER, s, "有一个有趣的形状.");默认:返回空;}}私有节点 createTextFlow(String... msg) {FlowPane flow = new FlowPane();boolean isFruit = false;for (String s : msg) {如果(FRUIT_PLACEHOLDER.equals(s)){isFruit = true;继续;}文字文字 = 新文字;如果(是水果){flow.getChildren().addAll(新的 ImageView(fruitImages.get(s)),createSpacer(5));text.getStyleClass().addAll(水果",秒);isFruit = 假;} 别的 {text.getStyleClass().add(普通");}flow.getChildren().add(text);}回流;}私有节点 createSpacer(int width) {HBox 间隔器 = new HBox();spacer.setMinWidth(HBox.USE_PREF_SIZE);间隔器.setPrefWidth(宽度);spacer.setMaxWidth(HBox.USE_PREF_SIZE);回程垫片;}}}
Ok, I have a ListView object. I'm using this as a sort of console window for my server. It was really the only way I could think of to display colorized text in a box like that. Which this works wonderful so far. Now what I want to be able to do is color different text on one index or line.
Example:
listView[0] = "Hello " + "world";
Where "Hello" would be green and "world" would be blue. If this can be done usine javafx Text or any other way I would like to know how to go about it. I'm using Javafx Text as the primary culprit since you can customize so much with it.
I hope everyone can understand what I'm trying to do here, if not, let me know and I'll try to reword it a bit.
SOLUTION
Thanks to jewelsea I was able to figure out a solution. I went with a bit of a different approach with it instead of using a cellfactory.
ListView
ListView<FlowPane> consoleWindow = new ListView<>();
ArrayList<FlowPane> consoleBuffer = FXCollections.observableArrayList();
consoleWindow.setItems(consoleBuffer);
inputBox.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
consoleBuffer.add(parseInput.parseInputToArray(inputBox.getText()));
}
consoleWindow.scrollTo(consoleBuffer.size());
}
});
ConsoleInputParse:
public class ConsoleInputParse {
private String[] wordList = {};
public ConsoleInputParse() {}
public FlowPane parseInputToArray(String input) {
wordList = input.trim().split("[ ]+");
return colorize();
}
public FlowPane colorize() {
ArrayList<Text> textChunks = new ArrayList<>();
FlowPane bundle = new FlowPane();
//Todo: use regex to check for valid words
for (String word : wordList) {
String spaced = word + " ";
switch (word) {
case "Hello": case "hello":
textChunks.add(customize(spaced, "purple"));
break;
case "World": case "world":
textChunks.add(customize(spaced, "blue"));
break;
case "Stack Overflow":
textChunks.add(customize(spaced, "orange", "Arial Bold", 15));
default:
textChunks.add(customize(spaced, "black", "Arial", 13));
break;
}
}
bundle.getChildren().addAll(textChunks);
return bundle;
}
public Text customize(String word, String color) {
return TextBuilder.create().text(word).fill(Paint.valueOf(color)).build();
}
public Text customize(String word, String color, String font) {
return TextBuilder.create()
.text(word)
.fill(Paint.valueOf(color))
.font(Font.font(font, 12)).build();
}
public Text customize(String word, String color, String font, int fontSize) {
return TextBuilder.create()
.text(word)
.fill(Paint.valueOf(color))
.font(Font.font(font, fontSize)).build();
}
}
"Working Example"
Create a custom cellfactory for your ListView and have it generate cells containing a FlowPane with different Text instances, each with different styles. I created a sample to demonstrate this method.
Sample output:
In Java 8 you can you can use the TextFlow
to style your text rather than a combination of different Text
instances in a FlowPane
.
Sample code
fruits.css
/**
* fruits.css - place in same source directory as FruitsDisplay.java and
* ensure the build system copies the file over to the output path
*/
.root {
-fx-font-size: 20px;
-fx-font-family: "Comic Sans MS";
}
.list-cell {
-fx-background-color: azure;
}
.fruit {
-fx-font-weight: bold;
-fx-font-style: italic;
}
.apple {
-fx-fill: forestgreen;
}
.orange {
-fx-fill: orange;
}
.pear {
-fx-fill: gold;
}
FruitsDisplay.java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.util.*;
/**
* Sample of using a FlowPane to create styled text in JavaFX
*/
public class FruitsDisplay extends Application {
private static final String[] fruits = {"apple", "orange", "pear"};
private static final String[] fruitImageLocs = {
"http://weknowyourdreamz.com/images/apple/apple-02.jpg",
"http://pic.1fotonin.com/data/wallpapers/165/WDF_2048871.png",
"http://vignette1.wikia.nocookie.net/pikmin/images/c/cc/Pear-01.jpg"
};
private Map<String, Image> fruitImages = new HashMap<>();
public static void main(String[] args) {
Application.launch(FruitsDisplay.class);
}
@Override
public void start(Stage stage) throws Exception {
stage.setTitle("Fruit Tales");
for (int i = 0; i < fruits.length; i++) {
Image image = new Image(fruitImageLocs[i], 0, 30, true, true);
fruitImages.put(fruits[i], image);
}
ListView<String> list = new ListView<>(FXCollections.observableArrayList(fruits));
list.setCellFactory(listView -> new FruitFlowCell());
list.setPrefSize(440, 180);
Scene scene = new Scene(list);
scene.getStylesheets().add(getResource("fruits.css"));
stage.setScene(scene);
stage.show();
}
private String getResource(String resourceName) {
return getClass().getResource(resourceName).toExternalForm();
}
private class FruitFlowCell extends ListCell<String> {
static final String FRUIT_PLACEHOLDER = "%f";
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
protected void updateItem(String s, boolean empty) {
super.updateItem(s, empty);
if (s != null && !"".equals(s) && !isEmpty()) {
setGraphic(createFruitFlow(s));
} else {
setGraphic(null);
}
}
private Node createFruitFlow(String s) {
switch (s) {
case "apple":
return createTextFlow("Eat an ", FRUIT_PLACEHOLDER, s, " a day.");
case "orange":
return createTextFlow("An ", FRUIT_PLACEHOLDER, s, " has many vitamins.");
case "pear":
return createTextFlow("A ", FRUIT_PLACEHOLDER, s, " has a funny shape.");
default:
return null;
}
}
private Node createTextFlow(String... msg) {
FlowPane flow = new FlowPane();
boolean isFruit = false;
for (String s : msg) {
if (FRUIT_PLACEHOLDER.equals(s)) {
isFruit = true;
continue;
}
Text text = new Text(s);
if (isFruit) {
flow.getChildren().addAll(
new ImageView(fruitImages.get(s)),
createSpacer(5)
);
text.getStyleClass().addAll(
"fruit",
s
);
isFruit = false;
} else {
text.getStyleClass().add("plain");
}
flow.getChildren().add(text);
}
return flow;
}
private Node createSpacer(int width) {
HBox spacer = new HBox();
spacer.setMinWidth(HBox.USE_PREF_SIZE);
spacer.setPrefWidth(width);
spacer.setMaxWidth(HBox.USE_PREF_SIZE);
return spacer;
}
}
}
这篇关于Javafx 文本多字着色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!