Initial project
This commit is contained in:
172
src/main/java/com/imyeyu/fx/ui/components/SelectableLabel.java
Normal file
172
src/main/java/com/imyeyu/fx/ui/components/SelectableLabel.java
Normal file
@@ -0,0 +1,172 @@
|
||||
package com.imyeyu.fx.ui.components;
|
||||
|
||||
import com.imyeyu.fx.ui.TimiFXUI;
|
||||
import com.imyeyu.java.ref.Ref;
|
||||
import com.sun.javafx.scene.control.skin.Utils;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Skin;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.skin.TextAreaSkin;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextAlignment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 可选中的标签组件,实际上是无样式文本域,此组件适应布局最大宽度
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2022-01-29 01:24
|
||||
*/
|
||||
public class SelectableLabel extends TextArea implements TimiFXUI, TimiFXUI.Colorful {
|
||||
|
||||
private static final String STYLE_CLASS = "selectable-label";
|
||||
|
||||
private final ObjectProperty<Paint> textFillProperty;
|
||||
private final ObjectProperty<TextAlignment> textAlignmentProperty;
|
||||
|
||||
/** 默认构造 */
|
||||
public SelectableLabel() {
|
||||
this("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造器
|
||||
*
|
||||
* @param text 文本内容
|
||||
*/
|
||||
public SelectableLabel(String text) {
|
||||
super(text);
|
||||
|
||||
textFillProperty = new SimpleObjectProperty<>(BLACK);
|
||||
textAlignmentProperty = new SimpleObjectProperty<>(TextAlignment.LEFT);
|
||||
|
||||
setCursor(Cursor.TEXT);
|
||||
setEditable(false);
|
||||
setWrapText(true);
|
||||
setMaxWidth(Double.MAX_VALUE);
|
||||
setMinSize(Double.MIN_VALUE, Double.MIN_VALUE);
|
||||
setPrefHeight(0);
|
||||
setPrefSize(0, 0);
|
||||
getStyleClass().setAll(STYLE_CLASS, CSS.MINECRAFT);
|
||||
|
||||
focusedProperty().addListener((obs, o, isFocused) -> {
|
||||
if (!isFocused) {
|
||||
deselect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Skin<?> createDefaultSkin() {
|
||||
Skin<?> defaultSkin = super.createDefaultSkin();
|
||||
if (defaultSkin instanceof TextAreaSkin skin) {
|
||||
try {
|
||||
ScrollPane sp = Ref.getFieldValue(skin, "scrollPane", ScrollPane.class);
|
||||
sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
if (sp.getContent() instanceof Region region) {
|
||||
region.heightProperty().addListener((obs, o, newHeight) -> Platform.runLater(() -> {
|
||||
// 需要 runLater,因为是 Region 适应 Skin 变化
|
||||
setPrefHeight(newHeight.doubleValue());
|
||||
}));
|
||||
}
|
||||
Group paragraphNodes = Ref.getFieldValue(skin, "paragraphNodes", Group.class);
|
||||
paragraphNodes.getChildren().addListener((ListChangeListener<Node>) c -> {
|
||||
if (c.next()) {
|
||||
if (c.wasAdded()) {
|
||||
bindTextStyle(c.getAddedSubList());
|
||||
}
|
||||
}
|
||||
});
|
||||
bindTextStyle(paragraphNodes.getChildren());
|
||||
widthProperty().addListener((obs, oldValue, newValue) -> {
|
||||
if (oldValue.doubleValue() < newValue.doubleValue()) {
|
||||
if (paragraphNodes.getChildren().get(0) instanceof Text text) {
|
||||
setPrefHeight(Utils.computeTextHeight(getFont(), getText(), getWidth(), text.getBoundsType()));
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return defaultSkin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定文本样式
|
||||
*
|
||||
* @param list 文本节点,必须是 {@link Text}
|
||||
*/
|
||||
private void bindTextStyle(List<? extends Node> list) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (list.get(i) instanceof Text text) {
|
||||
text.fillProperty().bind(textFillProperty);
|
||||
text.textAlignmentProperty().bind(textAlignmentProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体颜色
|
||||
*
|
||||
* @param textFill 字体颜色
|
||||
*/
|
||||
public void setTextFill(Paint textFill) {
|
||||
this.textFillProperty.set(textFill);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字体颜色
|
||||
*
|
||||
* @return 字体颜色
|
||||
*/
|
||||
public Paint getTextFill() {
|
||||
return textFillProperty.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字体颜色绑定
|
||||
*
|
||||
* @return 字体颜色绑定
|
||||
*/
|
||||
public ObjectProperty<Paint> textFillProperty() {
|
||||
return textFillProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文本对齐方式
|
||||
*
|
||||
* @param textAlignment 文本对齐方式
|
||||
*/
|
||||
public void setTextAlignment(TextAlignment textAlignment) {
|
||||
this.textAlignmentProperty.set(textAlignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文本对齐方式
|
||||
*
|
||||
* @return 文本对齐方式
|
||||
*/
|
||||
public TextAlignment getTextAlignment() {
|
||||
return textAlignmentProperty.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文本对齐方式绑定
|
||||
*
|
||||
* @return 文本对齐方式绑定
|
||||
*/
|
||||
public ObjectProperty<TextAlignment> textAlignmentProperty() {
|
||||
return textAlignmentProperty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user