Compare commits

...

8 Commits

Author SHA1 Message Date
118c3f68c1 Merge pull request 'v0.0.3' (#2) from dev into master
Reviewed-on: #2
2026-05-12 03:36:19 +00:00
Timi
dbb39b3d2f v0.0.3
All checks were successful
CI/CD / build-deploy (pull_request) Successful in 37s
2026-05-12 11:35:55 +08:00
Timi
6eb36f4c59 add ci.yml 2026-05-12 11:11:22 +08:00
6fe5c476c0 Merge pull request 'v0.0.3' (#1) from dev into master
Reviewed-on: #1
2026-05-12 03:04:28 +00:00
Timi
9d605993c8 v0.0.3 2026-05-11 21:40:48 +08:00
Timi
88f3e135ff v0.0.3 2026-05-11 21:38:37 +08:00
Timi
6837781383 feat: add info/warn/error methods to LabelTips 2026-01-14 14:57:13 +08:00
Timi
68f39aa834 update timi-inject 2026-01-14 14:54:15 +08:00
55 changed files with 941 additions and 823 deletions

111
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,111 @@
name: CI/CD
on:
pull_request:
branches:
- master
types:
- closed
jobs:
build-deploy:
runs-on: act_runner_java
if: ${{ github.event.pull_request.merged == true }}
env:
JAVA_HOME: /usr/lib/jvm/java-25-openjdk
steps:
- name: Checkout code
run: |
git clone ${{ github.server_url }}/${{ github.repository }}.git .
git checkout ${{ github.sha }}
- name: Set up environment
run: |
echo "PR #${{ github.event.number }} merged into master"
echo "Source branch: ${{ github.event.pull_request.head.ref }}"
echo "Target branch: ${{ github.event.pull_request.base.ref }}"
- name: Run tests
run: |
echo "Running test suite..."
- name: Build project
run: |
mvn -B -DskipTests clean package source:jar javadoc:jar
- name: Deploy to Nexus
if: success()
run: |
if [ -z "${{ secrets.NEXUS_USERNAME }}" ] || [ -z "${{ secrets.NEXUS_PASSWORD }}" ]; then
echo "Missing secrets.NEXUS_USERNAME or secrets.NEXUS_PASSWORD"
exit 1
fi
mkdir -p ~/.m2
cat > ~/.m2/settings.xml <<EOF
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>timi-nexus</id>
<username>${{ secrets.NEXUS_USERNAME }}</username>
<password>${{ secrets.NEXUS_PASSWORD }}</password>
</server>
</servers>
</settings>
EOF
version=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version)
artifact_id=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.artifactId)
main_jar="target/${artifact_id}-${version}.jar"
sources_jar="target/${artifact_id}-${version}-sources.jar"
javadoc_jar="target/${artifact_id}-${version}-javadoc.jar"
if [ ! -f "$main_jar" ] || [ ! -f "$sources_jar" ] || [ ! -f "$javadoc_jar" ]; then
echo "Missing build artifacts in target"
exit 1
fi
mvn -B deploy:deploy-file \
-Dfile="$main_jar" \
-Dsources="$sources_jar" \
-Djavadoc="$javadoc_jar" \
-DpomFile="./pom.xml" \
-Durl="https://nexus.imyeyu.com/repository/maven-releases/" \
-DrepositoryId="timi-nexus" \
-Dhttps.protocols=TLSv1.2 \
-Djdk.tls.client.protocols=TLSv1.2
- name: Create release
if: ${{ success() && startsWith(github.event.pull_request.title, 'v') }}
env:
GITEA_TOKEN: ${{ secrets.RUNNER_TOKEN }}
GITEA_SERVER_URL: ${{ github.server_url }}
GITEA_REPOSITORY: ${{ github.repository }}
RELEASE_TAG: ${{ github.event.pull_request.title }}
RELEASE_TARGET: ${{ github.sha }}
run: |
if [ -z "$GITEA_TOKEN" ]; then
echo "Missing secrets.RUNNER_TOKEN"
exit 1
fi
api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases"
payload=$(cat <<EOF
{
"tag_name": "$RELEASE_TAG",
"name": "$RELEASE_TAG",
"target_commitish": "$RELEASE_TARGET",
"draft": false,
"prerelease": false
}
EOF
)
response=$(curl -sS -X POST "$api_url" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "$payload")
release_id=$(echo "$response" | grep -o '"id":[0-9]*' | head -n 1 | grep -o '[0-9]*')
if [ -z "$release_id" ] || echo "$response" | grep -q '"message"'; then
echo "Create release failed: $response"
exit 1
fi
echo "Release created: id=$release_id"
for asset_path in target/*.jar; do
asset_name=$(basename "$asset_path")
curl -sS -X POST "$api_url/$release_id/assets?name=$asset_name" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary @"$asset_path"
done

5
.gitignore vendored
View File

@@ -1,3 +1,8 @@
/.serena
/.codex*
/AGENTS.md
/logs
target/ target/
!.mvn/wrapper/maven-wrapper.jar !.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/ !**/src/main/**/target/

2
.idea/misc.xml generated
View File

@@ -8,7 +8,7 @@
</list> </list>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_25" project-jdk-name="temurin-25" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

147
pom.xml
View File

@@ -6,60 +6,179 @@
<groupId>com.imyeyu.fx.ui</groupId> <groupId>com.imyeyu.fx.ui</groupId>
<artifactId>timi-fx-ui</artifactId> <artifactId>timi-fx-ui</artifactId>
<version>0.0.1</version> <version>0.0.3</version>
<properties> <properties>
<maven.test.skip>true</maven.test.skip> <fx.version>25.0.3</fx.version>
<maven.compiler.source>21</maven.compiler.source> <skipTests>true</skipTests>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.imyeyu.fx.ui.examples.TimiFXExamples</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/assembly/examples.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>build-examples-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<configuration>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<outputDirectory>${project.build.directory}/delombok</outputDirectory>
<addOutputDirectory>false</addOutputDirectory>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.12.0</version>
<configuration>
<sourcepath>${project.build.directory}/delombok</sourcepath>
<encoding>UTF-8</encoding>
<charset>UTF-8</charset>
<docencoding>UTF-8</docencoding>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>timi_nexus</id>
<url>https://nexus.imyeyu.com/repository/maven-releases/</url>
</repository>
</distributionManagement>
<repositories>
<repository>
<id>timi_nexus</id>
<url>https://nexus.imyeyu.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.imyeyu.fx</groupId> <groupId>com.imyeyu.fx</groupId>
<artifactId>timi-fx</artifactId> <artifactId>timi-fx</artifactId>
<version>0.0.1</version> <version>0.0.5</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.imyeyu.fx.icon</groupId> <groupId>com.imyeyu.fx.icon</groupId>
<artifactId>timi-fx-icon</artifactId> <artifactId>timi-fx-icon</artifactId>
<version>0.0.1</version> <version>0.0.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.imyeyu.lang</groupId> <groupId>com.imyeyu.lang</groupId>
<artifactId>timi-lang</artifactId> <artifactId>timi-lang</artifactId>
<version>0.0.1</version> <version>0.0.4</version>
</dependency> </dependency>
<!-- 演示程序依赖 -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.36</version> <version>1.18.46</version>
<scope>test</scope>
</dependency> </dependency>
<!-- 演示程序依赖 -->
<dependency> <dependency>
<groupId>com.imyeyu.network</groupId> <groupId>com.imyeyu.network</groupId>
<artifactId>timi-network</artifactId> <artifactId>timi-network</artifactId>
<version>0.0.1</version> <version>0.0.10</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.imyeyu.config</groupId> <groupId>com.imyeyu.config</groupId>
<artifactId>timi-config</artifactId> <artifactId>timi-config</artifactId>
<version>0.0.1</version> <version>0.0.3</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.11.0</version> <version>2.14.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.imyeyu.inject</groupId> <groupId>com.imyeyu.inject</groupId>
<artifactId>timi-inject</artifactId> <artifactId>timi-inject</artifactId>
<version>0.0.1</version> <version>0.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.32</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

33
src/assembly/examples.xml Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.1 https://maven.apache.org/xsd/assembly-2.1.1.xsd">
<id>examples</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.testOutputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<scope>test</scope>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</unpackOptions>
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -47,15 +47,15 @@ public class ScreenIdentify extends Stage implements TimiFXUI {
while (c.next()) { while (c.next()) {
if (c.wasAdded()) { if (c.wasAdded()) {
List<? extends Identify> list = c.getAddedSubList(); List<? extends Identify> list = c.getAddedSubList();
for (int i = 0; i < list.size(); i++) { for (Identify identify : list) {
Rectangle2D r2d = list.get(i).screen.getBounds(); Rectangle2D r2d = identify.screen.getBounds();
list.get(i).show(this, r2d.getMinX() + 80, r2d.getMinY() + 80); identify.show(this, r2d.getMinX() + 80, r2d.getMinY() + 80);
} }
} }
if (c.wasRemoved()) { if (c.wasRemoved()) {
List<? extends Identify> list = c.getRemoved(); List<? extends Identify> list = c.getRemoved();
for (int i = 0; i < list.size(); i++) { for (Identify identify : list) {
list.get(i).hide(); identify.hide();
} }
} }
} }

View File

@@ -12,6 +12,7 @@ import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.layout.TilePane; import javafx.scene.layout.TilePane;
import javafx.stage.Popup; import javafx.stage.Popup;
import lombok.Getter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -26,6 +27,8 @@ import java.util.Map;
*/ */
public class CheckBoxPicker<T> extends TextField implements TimiFXUI { public class CheckBoxPicker<T> extends TextField implements TimiFXUI {
/** 数据列表 */
@Getter
private final ObservableList<T> items; private final ObservableList<T> items;
private final CheckBoxListPopup<T> checkBoxListPopup; private final CheckBoxListPopup<T> checkBoxListPopup;
@@ -65,15 +68,6 @@ public class CheckBoxPicker<T> extends TextField implements TimiFXUI {
return checkBoxListPopup.selectedItems; return checkBoxListPopup.selectedItems;
} }
/**
* 获取数据列表
*
* @return 数据列表
*/
public ObservableList<T> getItems() {
return items;
}
/** /**
* 复选框列表弹窗 * 复选框列表弹窗
* *
@@ -142,8 +136,8 @@ public class CheckBoxPicker<T> extends TextField implements TimiFXUI {
if (c.wasRemoved()) { if (c.wasRemoved()) {
// 移除 // 移除
List<? extends T> list = c.getRemoved(); List<? extends T> list = c.getRemoved();
for (int i = 0; i < list.size(); i++) { for (T t : list) {
root.getChildren().remove(cache.get(list.get(i))); root.getChildren().remove(cache.get(t));
} }
} }
} }

View File

@@ -40,13 +40,13 @@ public class ContextMenu extends javafx.scene.control.ContextMenu {
} }
private void updateMinWidth(List<MenuItem> items) { private void updateMinWidth(List<MenuItem> items) {
for (int i = 0; i < items.size(); i++) { for (MenuItem item : items) {
if (items.get(i) instanceof Menu menu) { if (item instanceof Menu menu) {
if (!menu.getProperties().containsKey(NOT_EXTENDS_FLAG)) { if (!menu.getProperties().containsKey(NOT_EXTENDS_FLAG)) {
boolean isItemsMenu = false; // 为 true 时表示子菜单是一般菜单项,继续应用最小宽度 boolean isItemsMenu = false; // 为 true 时表示子菜单是一般菜单项,继续应用最小宽度
ObservableList<MenuItem> subItems = menu.getItems(); ObservableList<MenuItem> subItems = menu.getItems();
for (int j = 0; j < subItems.size(); j++) { for (MenuItem subItem : subItems) {
if (subItems.get(j).getClass().equals(MenuItem.class)) { if (subItem.getClass().equals(MenuItem.class)) {
isItemsMenu = true; isItemsMenu = true;
break; break;
} }
@@ -56,7 +56,7 @@ public class ContextMenu extends javafx.scene.control.ContextMenu {
} }
} }
} else { } else {
items.get(i).setStyle(STYLE_TEMPLATE.formatted(getMinWidth(), getMinWidth())); item.setStyle(STYLE_TEMPLATE.formatted(getMinWidth(), getMinWidth()));
} }
} }
} }

View File

@@ -22,6 +22,7 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import lombok.Getter;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
@@ -36,7 +37,8 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
private static final String STYLE_CLASS = "date-time-picker"; private static final String STYLE_CLASS = "date-time-picker";
/** 选择器 */ /** 日期选择器 */
@Getter
private final DatePicker datePicker; private final DatePicker datePicker;
/** 当前值 */ /** 当前值 */
@@ -270,13 +272,4 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
public LongProperty valueProperty() { public LongProperty valueProperty() {
return value; return value;
} }
/**
* 获取日期选择器
*
* @return 日期选择器
*/
public DatePicker getDatePicker() {
return datePicker;
}
} }

View File

@@ -115,7 +115,7 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
menuRefresh.disableProperty().bind(Bindings.createBooleanBinding(() -> { menuRefresh.disableProperty().bind(Bindings.createBooleanBinding(() -> {
List<TreeItem<File>> items = getSelectionModel().getSelectedItems(); List<TreeItem<File>> items = getSelectionModel().getSelectedItems();
// 没有选择、多选、选的不是文件时禁用 // 没有选择、多选、选的不是文件时禁用
return items == null || items.size() != 1 || items.get(0).getValue().isFile(); return items == null || items.size() != 1 || items.getFirst().getValue().isFile();
}, getSelectionModel().selectedItemProperty())); }, getSelectionModel().selectedItemProperty()));
menuRefresh.setOnAction(e -> refreshItem(getSelectionModel().getSelectedItem())); menuRefresh.setOnAction(e -> refreshItem(getSelectionModel().getSelectedItem()));
@@ -126,8 +126,8 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
if (items.isEmpty()) { if (items.isEmpty()) {
return true; return true;
} }
for (int i = 0; i < items.size(); i++) { for (TreeItem<File> item : items) {
if (roots.contains(items.get(i).getValue())) { if (roots.contains(item.getValue())) {
return true; return true;
} }
} }
@@ -168,8 +168,8 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
}); });
// 默认磁盘根目录 // 默认磁盘根目录
for (int i = 0; i < roots.size(); i++) { for (File root : roots) {
getRoots().add(new FileItem(roots.get(i))); getRoots().add(new FileItem(root));
} }
} }
@@ -237,8 +237,8 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
@Override @Override
protected TreeItem<File> call() { protected TreeItem<File> call() {
List<File> items = files.stream().map(TreeItem::getValue).toList(); List<File> items = files.stream().map(TreeItem::getValue).toList();
for (int i = 0; i < items.size(); i++) { for (File file : items) {
IO.destroy(items.get(i)); IO.destroy(file);
} }
// 查找最高级节点刷新 // 查找最高级节点刷新
int l = Integer.MAX_VALUE; int l = Integer.MAX_VALUE;
@@ -319,16 +319,16 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
parent = new File("./").getAbsoluteFile(); parent = new File("./").getAbsoluteFile();
} }
do { do {
selectDeque.add(0, parent); selectDeque.addFirst(parent);
} while ((parent = parent.getParentFile()) != null); } while ((parent = parent.getParentFile()) != null);
if (TimiJava.isNotEmpty(selectDeque)) { if (TimiJava.isNotEmpty(selectDeque)) {
ObservableList<TreeItem<File>> roots = getRoots(); ObservableList<TreeItem<File>> roots = getRoots();
for (int i = 0; i < roots.size(); i++) { for (TreeItem<File> root : roots) {
roots.get(i).setExpanded(false); root.setExpanded(false);
if (roots.get(i).getValue().equals(selectDeque.get(0))) { if (root.getValue().equals(selectDeque.getFirst())) {
selectDeque.remove(0); selectDeque.removeFirst();
roots.get(i).setExpanded(true); root.setExpanded(true);
if (TimiJava.isEmpty(selectDeque)) { if (TimiJava.isEmpty(selectDeque)) {
break; break;
} }
@@ -439,13 +439,13 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
// 过滤 // 过滤
list: list:
for (int i = 0; i < fileList.size(); i++) { for (File file : fileList) {
for (int j = 0; j < itemFilters.size(); j++) { for (CallbackArgReturn<File, Boolean> itemFilter : itemFilters) {
if (!itemFilters.get(j).handler(fileList.get(i))) { if (!itemFilter.handler(file)) {
continue list; continue list;
} }
} }
fileItems.add(new FileItem(fileList.get(i))); fileItems.add(new FileItem(file));
} }
} }
return fileItems; return fileItems;
@@ -453,11 +453,11 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
getChildren().setAll(items); getChildren().setAll(items);
if (TimiJava.isNotEmpty(selectDeque)) { if (TimiJava.isNotEmpty(selectDeque)) {
File file = selectDeque.remove(0); File file = selectDeque.removeFirst();
for (int i = 0; i < items.size(); i++) { for (FileItem item : items) {
if (items.get(i).getValue().equals(file)) { if (item.getValue().equals(file)) {
if (items.get(i).getValue().isDirectory()) { if (item.getValue().isDirectory()) {
items.get(i).setExpanded(true); item.setExpanded(true);
} }
break; break;
} }

View File

@@ -120,8 +120,6 @@ public class IconPicker extends TextField implements TimiFXUI {
*/ */
private static class IconPickerPopup extends Stage { private static class IconPickerPopup extends Stage {
private static final String SEARCH_API = "https://api.timiserver.imyeyu.net/icon/search/label";
final ToggleGroup group; final ToggleGroup group;
final List<ToggleIcon> icons; final List<ToggleIcon> icons;
final Map<String, Character> nameMapping = TimiFXIcon.getNameMapping(); final Map<String, Character> nameMapping = TimiFXIcon.getNameMapping();

View File

@@ -6,6 +6,8 @@ import javafx.beans.property.StringProperty;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar; import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import lombok.Getter;
import lombok.Setter;
/** /**
* 标签进度。如果继承进度组件使用反射注入标签组件时,在设置标签文本会导致标签消失 * 标签进度。如果继承进度组件使用反射注入标签组件时,在设置标签文本会导致标签消失
@@ -13,17 +15,19 @@ import javafx.scene.layout.StackPane;
* @author 夜雨 * @author 夜雨
* @since 2022-08-09 10:48 * @since 2022-08-09 10:48
*/ */
@Getter
public class LabelProgressBar extends StackPane { public class LabelProgressBar extends StackPane {
private static final String STYLE_CLASS = "label-progress-bar"; private static final String STYLE_CLASS = "label-progress-bar";
/** 标签 */ /** 标签组件 */
protected final Label label; protected final Label label;
/** 进度 */ /** 进度组件 */
protected final ProgressBar bar; protected final ProgressBar bar;
/** 标签转换 */ /** 标签转换回调,进度变换时触发回调 */
@Setter
protected CallbackArgReturn<Double, String> converter; protected CallbackArgReturn<Double, String> converter;
/** 默认构造 */ /** 默认构造 */
@@ -73,15 +77,6 @@ public class LabelProgressBar extends StackPane {
return label.textProperty(); return label.textProperty();
} }
/**
* 获取标签组件
*
* @return 标签组件
*/
public Label getLabel() {
return label;
}
/** /**
* 设置进度值 * 设置进度值
* *
@@ -108,31 +103,4 @@ public class LabelProgressBar extends StackPane {
public DoubleProperty progressProperty() { public DoubleProperty progressProperty() {
return bar.progressProperty(); return bar.progressProperty();
} }
/**
* 获取进度组件
*
* @return 进度组件
*/
public ProgressBar getBar() {
return bar;
}
/**
* 获取标签转换回调
*
* @return 转换回调
*/
public CallbackArgReturn<Double, String> getConverter() {
return converter;
}
/**
* 设置标签转换回调,进度变换时触发回调
*
* @param converter 标签转换回调
*/
public void setConverter(CallbackArgReturn<Double, String> converter) {
this.converter = converter;
}
} }

View File

@@ -0,0 +1,313 @@
package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.utils.Time;
import javafx.animation.PauseTransition;
import javafx.application.Platform;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.control.Label;
import javafx.scene.paint.Paint;
import javafx.util.Duration;
/**
* 提示标签,可以临时显示提示内容,经过指定时间后自动恢复原内容。
* <p>
* 此组件是线程安全的,可以从任意线程调用 {@link #tips(String)} 方法。
* 如果在提示期间再次调用 tips 方法,会重置计时器并显示新的提示内容,
* 恢复时仍然恢复为最初的原始内容。
* </p>
*
* <pre>{@code
* LabelTips label = new LabelTips("默认内容");
* label.tips("操作成功!"); // 使用默认 3 秒
* label.tips("保存完成!", 5000); // 指定 5 秒
* }</pre>
*
* @author 夜雨
* @since 2025-01-14
*/
public class LabelTips extends Label implements TimiFXUI.Colorful {
/** 默认提示持续时间(毫秒) */
public static final long DEFAULT_DURATION = Time.S * 5;
/** 信息提示颜色 */
public static final Paint INFO_TEXT_FILL = BLUE;
/** 警告提示颜色 */
public static final Paint WARN_TEXT_FILL = ORANGE;
/** 错误提示颜色 */
public static final Paint ERROR_TEXT_FILL = RED;
/** 提示持续时间(毫秒) */
protected LongProperty duration;
/** 原始内容,提示结束后恢复 */
private volatile String originalText;
/** 原始颜色,提示结束后恢复 */
private volatile Paint originalTextFill;
/** 定时器,用于恢复原内容 */
private PauseTransition transition;
/** 同步锁 */
private final Object lock = new Object();
/** 默认构造器 */
public LabelTips() {
this("");
}
/**
* 标准构造器
*
* @param text 标签初始文本
*/
public LabelTips(String text) {
super(text);
this.duration = new SimpleLongProperty(DEFAULT_DURATION);
}
/**
* 显示提示内容,使用默认持续时间
*
* @param content 提示内容
*/
public void tips(String content) {
tips(content, duration.get());
}
/**
* 显示提示内容,指定持续时间
*
* @param content 提示内容
* @param millis 持续时间(毫秒)
*/
public void tips(String content, long millis) {
tips(content, Duration.millis(millis));
}
/**
* 显示提示内容,指定持续时间
*
* @param content 提示内容
* @param duration 持续时间
*/
public void tips(String content, Duration duration) {
tips(content, duration, null);
}
/**
* 显示提示内容,指定持续时间与颜色
*
* @param content 提示内容
* @param duration 持续时间
* @param textFill 文本颜色
*/
public void tips(String content, Duration duration, Paint textFill) {
if (Platform.isFxApplicationThread()) {
doTips(content, duration, textFill);
} else {
Platform.runLater(() -> doTips(content, duration, textFill));
}
}
/**
* 显示信息提示内容,使用默认持续时间
*
* @param content 提示内容
*/
public void info(String content) {
info(content, duration.get());
}
/**
* 显示信息提示内容,指定持续时间
*
* @param content 提示内容
* @param millis 持续时间(毫秒)
*/
public void info(String content, long millis) {
info(content, Duration.millis(millis));
}
/**
* 显示信息提示内容,指定持续时间
*
* @param content 提示内容
* @param duration 持续时间
*/
public void info(String content, Duration duration) {
tips(content, duration, INFO_TEXT_FILL);
}
/**
* 显示警告提示内容,使用默认持续时间
*
* @param content 提示内容
*/
public void warn(String content) {
warn(content, duration.get());
}
/**
* 显示警告提示内容,指定持续时间
*
* @param content 提示内容
* @param millis 持续时间(毫秒)
*/
public void warn(String content, long millis) {
warn(content, Duration.millis(millis));
}
/**
* 显示警告提示内容,指定持续时间
*
* @param content 提示内容
* @param duration 持续时间
*/
public void warn(String content, Duration duration) {
tips(content, duration, WARN_TEXT_FILL);
}
/**
* 显示错误提示内容,使用默认持续时间
*
* @param content 提示内容
*/
public void error(String content) {
error(content, duration.get());
}
/**
* 显示错误提示内容,指定持续时间
*
* @param content 提示内容
* @param millis 持续时间(毫秒)
*/
public void error(String content, long millis) {
error(content, Duration.millis(millis));
}
/**
* 显示错误提示内容,指定持续时间
*
* @param content 提示内容
* @param duration 持续时间
*/
public void error(String content, Duration duration) {
tips(content, duration, ERROR_TEXT_FILL);
}
/**
* 执行提示逻辑,必须在 FX 线程调用
*
* @param content 提示内容
* @param duration 持续时间
*/
private void doTips(String content, Duration duration, Paint textFill) {
synchronized (lock) {
// 停止之前的定时器
if (transition != null) {
transition.stop();
}
// 仅在首次调用时保存原始内容
if (originalText == null) {
originalText = getText();
originalTextFill = getTextFill();
}
// 设置提示内容
setText(content);
if (textFill != null) {
setTextFill(textFill);
} else {
setTextFill(originalTextFill);
}
// 创建定时器
transition = new PauseTransition(duration);
transition.setOnFinished(e -> {
synchronized (lock) {
setText(originalText);
setTextFill(originalTextFill);
originalText = null;
originalTextFill = null;
transition = null;
}
});
transition.play();
}
}
/**
* 立即恢复原始内容,取消正在进行的提示
*/
public void restore() {
if (Platform.isFxApplicationThread()) {
doRestore();
} else {
Platform.runLater(this::doRestore);
}
}
/**
* 执行恢复逻辑,必须在 FX 线程调用
*/
private void doRestore() {
synchronized (lock) {
if (transition != null) {
transition.stop();
transition = null;
}
if (originalText != null) {
setText(originalText);
setTextFill(originalTextFill);
originalText = null;
originalTextFill = null;
}
}
}
/**
* 检查当前是否正在显示提示
*
* @return 如果正在显示提示返回 true
*/
public boolean isTipping() {
synchronized (lock) {
return originalText != null;
}
}
/**
* 获取默认提示持续时间
*
* @return 持续时间(毫秒),默认 {@value #DEFAULT_DURATION}
*/
public long getDuration() {
return duration.get();
}
/**
* 设置默认提示持续时间
*
* @param millis 持续时间(毫秒)
*/
public void setDuration(long millis) {
this.duration.set(millis);
}
/**
* 获取持续时间属性
*
* @return 持续时间属性
*/
public LongProperty durationProperty() {
return duration;
}
}

View File

@@ -16,6 +16,7 @@ import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup; import javafx.scene.control.ToggleGroup;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import lombok.Getter;
import java.util.List; import java.util.List;
@@ -27,7 +28,8 @@ import java.util.List;
*/ */
public class Navigation extends ScrollPane implements TimiFXUI { public class Navigation extends ScrollPane implements TimiFXUI {
/** 导航列表 */ /** 导航数据列表 */
@Getter
protected final ObservableList<ToggleButton> items; protected final ObservableList<ToggleButton> items;
/** 已选中监听 */ /** 已选中监听 */
@@ -62,7 +64,7 @@ public class Navigation extends ScrollPane implements TimiFXUI {
selectedItem.set(btn); selectedItem.set(btn);
} }
}); });
ObservableList<Node> childrens = root.getChildren(); ObservableList<Node> children = root.getChildren();
// 响应 TimiFXUI // 响应 TimiFXUI
items.addListener((ListChangeListener<ToggleButton>) c -> { items.addListener((ListChangeListener<ToggleButton>) c -> {
@@ -70,54 +72,54 @@ public class Navigation extends ScrollPane implements TimiFXUI {
if (c.wasAdded()) { if (c.wasAdded()) {
// 添加 // 添加
List<? extends ToggleButton> list = c.getAddedSubList(); List<? extends ToggleButton> list = c.getAddedSubList();
for (int i = 0; i < list.size(); i++) { for (ToggleButton toggleButton : list) {
list.get(i).setMaxWidth(Double.MAX_VALUE); toggleButton.setMaxWidth(Double.MAX_VALUE);
list.get(i).getStyleClass().setAll(CSS.MINECRAFT, "navigation-button"); toggleButton.getStyleClass().setAll(CSS.MINECRAFT, "navigation-button");
list.get(i).addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN); toggleButton.addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN);
if (list.get(i).getProperties().get("OWNER") instanceof TitledPane pane) { if (toggleButton.getProperties().get("OWNER") instanceof TitledPane pane) {
// 存在所属组 // 存在所属组
if (!childrens.contains(pane)) { if (!children.contains(pane)) {
// 未添加组 // 未添加组
childrens.add(pane); children.add(pane);
} }
if (pane.getContent() instanceof VBox box) { if (pane.getContent() instanceof VBox box) {
box.getChildren().add(list.get(i)); box.getChildren().add(toggleButton);
} }
} else { } else {
// 单独项 // 单独项
if (!childrens.isEmpty()) { if (!children.isEmpty()) {
if (childrens.get(childrens.size() - 1) instanceof TitledPane) { if (children.getLast() instanceof TitledPane) {
// 上一项是组导航,添加上边框 // 上一项是组导航,添加上边框
list.get(i).getStyleClass().add("after-group"); toggleButton.getStyleClass().add("after-group");
} }
} }
childrens.add(list.get(i)); children.add(toggleButton);
} }
// 归组 // 归组
group.getToggles().add(list.get(i)); group.getToggles().add(toggleButton);
} }
return; return;
} }
if (c.wasRemoved()) { if (c.wasRemoved()) {
// 移除 // 移除
List<? extends ToggleButton> list = c.getRemoved(); List<? extends ToggleButton> list = c.getRemoved();
for (int i = 0; i < list.size(); i++) { for (ToggleButton toggleButton : list) {
if (list.get(i).getProperties().get("OWNER") instanceof TitledPane pane) { if (toggleButton.getProperties().get("OWNER") instanceof TitledPane pane) {
// 存在所属组 // 存在所属组
if (pane.getContent() instanceof VBox box) { if (pane.getContent() instanceof VBox box) {
box.getChildren().remove(list.get(i)); box.getChildren().remove(toggleButton);
if (box.getChildren().isEmpty()) { if (box.getChildren().isEmpty()) {
// 该组已没有列表项 // 该组已没有列表项
childrens.remove(box); children.remove(box);
} }
} }
} else { } else {
// 单独项 // 单独项
childrens.remove(list.get(i)); children.remove(toggleButton);
} }
// 从组移除 // 从组移除
group.getToggles().remove(list.get(i)); group.getToggles().remove(toggleButton);
} }
} }
} }
@@ -185,9 +187,9 @@ public class Navigation extends ScrollPane implements TimiFXUI {
pane.setExpanded(isExpanded); pane.setExpanded(isExpanded);
pane.getStyleClass().add("group-pane"); pane.getStyleClass().add("group-pane");
for (int i = 0; i < buttons.length; i++) { for (ToggleButton button : buttons) {
buttons[i].getProperties().put("OWNER", pane); button.getProperties().put("OWNER", pane);
items.add(buttons[i]); items.add(button);
} }
return pane; return pane;
} }
@@ -231,13 +233,4 @@ public class Navigation extends ScrollPane implements TimiFXUI {
public ObjectProperty<ToggleButton> selectedItem() { public ObjectProperty<ToggleButton> selectedItem() {
return selectedItem; return selectedItem;
} }
/**
* 获取导航数据列表
*
* @return 导航数据列表
*/
public ObservableList<ToggleButton> getItems() {
return items;
}
} }

View File

@@ -56,7 +56,7 @@ public class NumberField extends TextField {
addEventFilter(KeyEvent.KEY_PRESSED, e -> isBackSpace = e.getCode() == KeyCode.BACK_SPACE); addEventFilter(KeyEvent.KEY_PRESSED, e -> isBackSpace = e.getCode() == KeyCode.BACK_SPACE);
setTextFormatter(new TextFormatter<>(c -> { setTextFormatter(new TextFormatter<>(c -> {
String newText = c.getControlNewText(); String newText = c.getControlNewText();
if (!newText.equals("")) { if (TimiJava.isNotEmpty(newText)) {
if (newText.equals("+") || newText.equals("-")) { if (newText.equals("+") || newText.equals("-")) {
return c; return c;
} }

View File

@@ -45,7 +45,7 @@ public class ProgressSlider extends Slider implements TimiFXUI {
pb.progressProperty().bind(valueProperty().subtract(minProperty()).divide(maxProperty().subtract(minProperty()))); pb.progressProperty().bind(valueProperty().subtract(minProperty()).divide(maxProperty().subtract(minProperty())));
pb.prefWidthProperty().bind(track.widthProperty()); pb.prefWidthProperty().bind(track.widthProperty());
pb.setMouseTransparent(true); pb.setMouseTransparent(true);
track.getChildren().add(0, pb); track.getChildren().addFirst(pb);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -90,7 +90,7 @@ public class SelectableLabel extends TextArea implements TimiFXUI, TimiFXUI.Colo
bindTextStyle(paragraphNodes.getChildren()); bindTextStyle(paragraphNodes.getChildren());
widthProperty().addListener((obs, oldValue, newValue) -> { widthProperty().addListener((obs, oldValue, newValue) -> {
if (oldValue.doubleValue() < newValue.doubleValue()) { if (oldValue.doubleValue() < newValue.doubleValue()) {
if (paragraphNodes.getChildren().get(0) instanceof Text text) { if (paragraphNodes.getChildren().getFirst() instanceof Text text) {
setPrefHeight(Utils.computeTextHeight(getFont(), getText(), getWidth(), text.getBoundsType())); setPrefHeight(Utils.computeTextHeight(getFont(), getText(), getWidth(), text.getBoundsType()));
} }
} }
@@ -108,8 +108,8 @@ public class SelectableLabel extends TextArea implements TimiFXUI, TimiFXUI.Colo
* @param list 文本节点,必须是 {@link Text} * @param list 文本节点,必须是 {@link Text}
*/ */
private void bindTextStyle(List<? extends Node> list) { private void bindTextStyle(List<? extends Node> list) {
for (int i = 0; i < list.size(); i++) { for (Node node : list) {
if (list.get(i) instanceof Text text) { if (node instanceof Text text) {
text.fillProperty().bind(textFillProperty); text.fillProperty().bind(textFillProperty);
text.textAlignmentProperty().bind(textAlignmentProperty); text.textAlignmentProperty().bind(textAlignmentProperty);
} }

View File

@@ -47,6 +47,7 @@ import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.shape.Path; import javafx.scene.shape.Path;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import lombok.Getter;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -61,28 +62,36 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
private static final String STYLE_CLASS = "text-area-editor"; private static final String STYLE_CLASS = "text-area-editor";
/** 主要控制区,此面板在 {@link #header} 的中部 */ /** 控制区面板,此面板在 */
@Getter
protected final HBox ctrl; protected final HBox ctrl;
/** 顶部控制区 */ /** 顶部控制区面板 */
@Getter
protected final BorderPane header; protected final BorderPane header;
/** 撤销按钮 */ /** 撤销按钮 */
@Getter
protected final IconButton undo; protected final IconButton undo;
/** 重做按钮 */ /** 重做按钮 */
@Getter
protected final IconButton redo; protected final IconButton redo;
/** 复制按钮 */ /** 复制按钮 */
@Getter
protected final IconButton copy; protected final IconButton copy;
/** 剪切按钮 */ /** 剪切按钮 */
@Getter
protected final IconButton cut; protected final IconButton cut;
/** 粘贴按钮 */ /** 粘贴按钮 */
@Getter
protected final IconButton paste; protected final IconButton paste;
/** 换行按钮 */ /** 换行按钮 */
@Getter
protected final ToggleIcon wrap; protected final ToggleIcon wrap;
/** 显示行号 */ /** 显示行号 */
@@ -269,7 +278,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
Group paragraphNodes = Ref.getClassFieldValue(skin, TextAreaSkin.class, "paragraphNodes", Group.class); Group paragraphNodes = Ref.getClassFieldValue(skin, TextAreaSkin.class, "paragraphNodes", Group.class);
Callback lineNumberParser = () -> { Callback lineNumberParser = () -> {
wraps.clear(); wraps.clear();
if (isWrapText() && paragraphNodes.getChildren().get(0) instanceof Text text) { if (isWrapText() && paragraphNodes.getChildren().getFirst() instanceof Text text) {
// 计算段落被渲染换行数 // 计算段落被渲染换行数
double wrappingWidth = scrollPane.getWidth() - 12; double wrappingWidth = scrollPane.getWidth() - 12;
for (int i = 0, l = getParagraphs().size(); i < l; i++) { for (int i = 0, l = getParagraphs().size(); i < l; i++) {
@@ -319,78 +328,6 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
return skin; return skin;
} }
/**
* 获取控制区面板,此面板在 {@link #getHeader()} 的中部
*
* @return 控制区面板
*/
public HBox getCtrl() {
return ctrl;
}
/**
* 获取顶部控制区面板
*
* @return 顶部控制区面板
*/
public BorderPane getHeader() {
return header;
}
/**
* 获取撤销按钮
*
* @return 撤销按钮
*/
public IconButton getUndo() {
return undo;
}
/**
* 获取重做按钮
*
* @return 重做按钮
*/
public IconButton getRedo() {
return redo;
}
/**
* 获取复制按钮
*
* @return 复制按钮
*/
public IconButton getCopy() {
return copy;
}
/**
* 获取剪切按钮
*
* @return 剪切按钮
*/
public IconButton getCut() {
return cut;
}
/**
* 获取粘贴按钮
*
* @return 粘贴按钮
*/
public IconButton getPaste() {
return paste;
}
/**
* 获取换行按钮
*
* @return 换行按钮
*/
public ToggleIcon getWrap() {
return wrap;
}
/** /**
* 获取是否显示行号 * 获取是否显示行号
* *
@@ -767,7 +704,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
@Override @Override
protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) { protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {
getChildren().get(0).resizeRelocate(contentX, contentY, contentWidth, contentHeight); getChildren().getFirst().resizeRelocate(contentX, contentY, contentWidth, contentHeight);
} }
} }
} }

View File

@@ -16,6 +16,8 @@ import javafx.scene.control.skin.TextFieldSkin;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
import lombok.Getter;
import lombok.Setter;
/** /**
* 复杂文本域编辑器 {@link TextAreaEditor} 的文本框显示方式,需要时弹出文本域编辑器 * 复杂文本域编辑器 {@link TextAreaEditor} 的文本框显示方式,需要时弹出文本域编辑器
@@ -25,10 +27,13 @@ import javafx.stage.Stage;
*/ */
public class TextAreaEditorField extends TextField implements TimiFXUI { public class TextAreaEditorField extends TextField implements TimiFXUI {
/** 显示编辑器事件 */ /** 显示编辑器回调事件,触发时窗体并未显示 */
@Getter
@Setter
private CallbackArg<Stage> onShowEditorEvent; private CallbackArg<Stage> onShowEditorEvent;
/** 编辑器窗 */ /** 编辑器窗 */
@Getter
private final EditorStage editorStage; private final EditorStage editorStage;
/** 标题 */ /** 标题 */
@@ -93,33 +98,6 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
return skin; return skin;
} }
/**
* 获取显示编辑器回调事件
*
* @return 显示编辑器回调事件
*/
public CallbackArg<Stage> getOnShowEditorEvent() {
return onShowEditorEvent;
}
/**
* 设置显示编辑器回调事件,触发时窗体并未显示
*
* @param onShowEditorEvent 显示编辑器回调事件
*/
public void setOnShowEditorEvent(CallbackArg<Stage> onShowEditorEvent) {
this.onShowEditorEvent = onShowEditorEvent;
}
/**
* 获取编辑器的弹窗
*
* @return 编辑器弹窗
*/
public EditorStage getEditorStage() {
return editorStage;
}
/** /**
* 获取编辑器标题 * 获取编辑器标题
* *

View File

@@ -125,7 +125,7 @@ public class TextFlower extends TextFlow implements TimiFXUI {
* @return 本实例 * @return 本实例
*/ */
public TextFlower asLink(String link) { public TextFlower asLink(String link) {
Node text = getChildren().remove(getChildren().size() - 1); Node text = getChildren().removeLast();
if (text instanceof Text t) { if (text instanceof Text t) {
getChildren().add(new XHyperlink(t.getText(), link)); getChildren().add(new XHyperlink(t.getText(), link));
} }
@@ -199,11 +199,11 @@ public class TextFlower extends TextFlow implements TimiFXUI {
static Style fromMatcher(String matcher) { static Style fromMatcher(String matcher) {
Style[] values = values(); Style[] values = values();
for (int i = 0; i < values.length; i++) { for (Style value : values) {
String[] matches = values[i].matches; String[] matches = value.matches;
for (int j = 0; j < matches.length; j++) { for (String match : matches) {
if (matches[j].equalsIgnoreCase(matcher)) { if (match.equalsIgnoreCase(matcher)) {
return values[i]; return value;
} }
} }
} }
@@ -315,10 +315,10 @@ public class TextFlower extends TextFlow implements TimiFXUI {
} else { } else {
Text text = new Text(value.substring(sp + 1).trim()); Text text = new Text(value.substring(sp + 1).trim());
String[] styles = value.substring(0, sp).trim().split(" "); String[] styles = value.substring(0, sp).trim().split(" ");
for (int i = 0; i < styles.length; i++) { for (String s : styles) {
Style style = Style.fromMatcher(styles[i]); Style style = Style.fromMatcher(s);
if (style == null) { if (style == null) {
text.setFill(Paint.valueOf(styles[i])); text.setFill(Paint.valueOf(s));
} else { } else {
if (style == Style.UNDERLINE) { if (style == Style.UNDERLINE) {
text.setUnderline(true); text.setUnderline(true);

View File

@@ -1,6 +1,5 @@
package com.imyeyu.fx.ui.components; package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import com.sun.javafx.scene.control.LabeledText; import com.sun.javafx.scene.control.LabeledText;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
@@ -57,7 +56,7 @@ public class TitleLabel extends Label implements TimiFXUI {
line.setHeight(1); line.setHeight(1);
line.fillProperty().bind(lineColor); line.fillProperty().bind(lineColor);
line.translateYProperty().bind(heightProperty().multiply(.5).subtract(1)); line.translateYProperty().bind(heightProperty().multiply(.5).subtract(1));
Node node = skin.getChildren().get(0); Node node = skin.getChildren().getFirst();
if (node instanceof LabeledText text) { if (node instanceof LabeledText text) {
line.widthProperty().bind(Bindings.createDoubleBinding(() -> { line.widthProperty().bind(Bindings.createDoubleBinding(() -> {
double textWidth = text.getLayoutBounds().getWidth(); double textWidth = text.getLayoutBounds().getWidth();
@@ -69,11 +68,11 @@ public class TitleLabel extends Label implements TimiFXUI {
}, spacing, text.layoutBoundsProperty())); }, spacing, text.layoutBoundsProperty()));
} }
skin.getChildren().addListener((ListChangeListener<Node>) c -> { skin.getChildren().addListener((ListChangeListener<Node>) c -> {
if (skin.getChildren().get(0) != line) { if (skin.getChildren().getFirst() != line) {
skin.getChildren().add(0, line); skin.getChildren().addFirst(line);
} }
}); });
skin.getChildren().add(0, line); skin.getChildren().addFirst(line);
} }
return defaultSkin; return defaultSkin;
} }
@@ -81,7 +80,7 @@ public class TitleLabel extends Label implements TimiFXUI {
/** /**
* 获取当前分割线颜色 * 获取当前分割线颜色
* *
* @return 分割线颜色,默认 {@link TimiFX.Colorful#BORDER} * @return 分割线颜色,默认 {@link TimiFXUI.Colorful#BORDER}
*/ */
public Paint getLineColor() { public Paint getLineColor() {
return lineColor.get(); return lineColor.get();

View File

@@ -18,6 +18,7 @@ import javafx.scene.layout.StackPane;
import javafx.stage.Screen; import javafx.stage.Screen;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import lombok.Getter;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import java.awt.Image; import java.awt.Image;
@@ -54,10 +55,16 @@ public final class TrayFX implements TimiFXUI {
/** 菜单寄主窗体 */ /** 菜单寄主窗体 */
private final Stage stage; private final Stage stage;
/** 根节点,修改这个节点的内容可以完全自定义右键菜单内容 */
@Getter
private final StackPane root; private final StackPane root;
/** 菜单进行修改 */
@Getter
private final ContextMenu menu; private final ContextMenu menu;
/** 托盘对象 */ /** 托盘对象 */
@Getter
private final SystemTray tray; private final SystemTray tray;
/** 文本提示 */ /** 文本提示 */
@@ -70,6 +77,7 @@ public final class TrayFX implements TimiFXUI {
private final ObjectProperty<Image> icon; private final ObjectProperty<Image> icon;
/** 托盘图标 */ /** 托盘图标 */
@Getter
private TrayIcon trayIcon; private TrayIcon trayIcon;
private final List<CallbackArg<Stage>> showMenuListeners; private final List<CallbackArg<Stage>> showMenuListeners;
@@ -157,30 +165,12 @@ public final class TrayFX implements TimiFXUI {
* @param menu 菜单 * @param menu 菜单
*/ */
public void addMenu(int sort, MenuItem... menu) { public void addMenu(int sort, MenuItem... menu) {
for (int i = 0; i < menu.length; i++) { for (MenuItem menuItem : menu) {
menu[i].getProperties().put(SORT_KEY, sort); menuItem.getProperties().put(SORT_KEY, sort);
} }
this.menu.getItems().addAll(menu); this.menu.getItems().addAll(menu);
} }
/**
* 获取菜单进行修改(添加菜单建议通过 {@link #addMenu(int, MenuItem...)},可以手动排序
*
* @return 菜单
*/
public ContextMenu getMenu() {
return menu;
}
/**
* 获取根节点,修改这个节点的内容可以完全自定义右键菜单内容
*
* @return 根节点
*/
public StackPane getRoot() {
return root;
}
/** /**
* 显示图标到托盘 * 显示图标到托盘
* *
@@ -209,8 +199,8 @@ public final class TrayFX implements TimiFXUI {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
Platform.runLater(() -> { Platform.runLater(() -> {
for (int i = 0; i < clickListeners.size(); i++) { for (CallbackArg<MouseEvent> clickListener : clickListeners) {
clickListeners.get(i).handler(e); clickListener.handler(e);
} }
if (SwingUtilities.isRightMouseButton(e)) { if (SwingUtilities.isRightMouseButton(e)) {
Point p = e.getLocationOnScreen(); Point p = e.getLocationOnScreen();
@@ -224,8 +214,8 @@ public final class TrayFX implements TimiFXUI {
menu.setY(p.getY()); menu.setY(p.getY());
menu.show(stage); menu.show(stage);
stage.sizeToScene(); stage.sizeToScene();
for (int i = 0; i < showMenuListeners.size(); i++) { for (CallbackArg<Stage> showMenuListener : showMenuListeners) {
showMenuListeners.get(i).handler(stage); showMenuListener.handler(stage);
} }
} }
}); });
@@ -374,22 +364,4 @@ public final class TrayFX implements TimiFXUI {
public void addShowMenuListener(CallbackArg<Stage> listener) { public void addShowMenuListener(CallbackArg<Stage> listener) {
showMenuListeners.add(listener); showMenuListeners.add(listener);
} }
/**
* 获取托盘图标
*
* @return 托盘图标
*/
public TrayIcon getTrayIcon() {
return trayIcon;
}
/**
* 获取托盘对象
*
* @return 托盘对象
*/
public SystemTray getTray() {
return tray;
}
} }

View File

@@ -11,6 +11,9 @@ import javafx.scene.Cursor;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.awt.Desktop; import java.awt.Desktop;
import java.io.IOException; import java.io.IOException;
@@ -30,6 +33,7 @@ public abstract class VersionLabel<T> extends VBox implements TimiFXUI, TimiFXUI
* @author 夜雨 * @author 夜雨
* @since 2022-11-27 16:13 * @since 2022-11-27 16:13
*/ */
@AllArgsConstructor
protected enum Status { protected enum Status {
/** 一般 */ /** 一般 */
@@ -44,23 +48,12 @@ public abstract class VersionLabel<T> extends VBox implements TimiFXUI, TimiFXUI
/** 错误 */ /** 错误 */
ERROR(RED); ERROR(RED);
Color textColor; final Color textColor;
Status(Color textColor) {
this.textColor = textColor;
}
/**
* 设置该状态的文本颜色
*
* @param textColor 颜色
*/
public void setTextColor(Color textColor) {
this.textColor = textColor;
}
} }
/** 更新链接 */ /** 更新链接 */
@Setter
@Getter
protected String updateURL; protected String updateURL;
/** 版本标签 */ /** 版本标签 */
@@ -150,7 +143,7 @@ public abstract class VersionLabel<T> extends VBox implements TimiFXUI, TimiFXUI
@Override @Override
protected void onException(Throwable e) { protected void onException(Throwable e) {
version.setText(TimiFXUI.MULTILINGUAL.textArgs("version.fail", nowVersion)); version.setText(TimiFXUI.MULTILINGUAL.text("version.fail"));
version.setOnMouseClicked(event -> checkVersion(nowVersion)); version.setOnMouseClicked(event -> checkVersion(nowVersion));
e.printStackTrace(); e.printStackTrace();
} }
@@ -187,22 +180,4 @@ public abstract class VersionLabel<T> extends VBox implements TimiFXUI, TimiFXUI
* @return 显示文本 * @return 显示文本
*/ */
protected abstract String failText(Throwable e); protected abstract String failText(Throwable e);
/**
* 获取更新链接
*
* @return 更新链接
*/
public String getUpdateURL() {
return updateURL;
}
/**
* 设置更新链接
*
* @param updateURL 更新链接
*/
public void setUpdateURL(String updateURL) {
this.updateURL = updateURL;
}
} }

View File

@@ -161,9 +161,9 @@ public class XPagination extends HBox implements TimiFXUI {
// ---------- 事件 ---------- // ---------- 事件 ----------
new ToggleGroup().getToggles().addAll(pageButtons); new ToggleGroup().getToggles().addAll(pageButtons);
for (int i = 0; i < pageButtons.size(); i++) { for (PageButton button : pageButtons) {
// 阻止取消选择 // 阻止取消选择
pageButtons.get(i).addEventFilter(MouseEvent.MOUSE_PRESSED, EVENT_TOGGLE_BUTTON); button.addEventFilter(MouseEvent.MOUSE_PRESSED, EVENT_TOGGLE_BUTTON);
} }
// 数据变动更新 // 数据变动更新
@@ -176,10 +176,10 @@ public class XPagination extends HBox implements TimiFXUI {
ip.set(0); ip.set(0);
} }
// 主动选中 // 主动选中
for (int i = 0; i < pageButtons.size(); i++) { for (PageButton pageButton : pageButtons) {
// 分页存在预设页码,只作触发事件用(如前置页的第五第六页),需要主动计算激活的按钮 // 分页存在预设页码,只作触发事件用(如前置页的第五第六页),需要主动计算激活的按钮
if (ip.get() == pageButtons.get(i).indexProperty.get() && pageButtons.get(i).isVisible()) { if (ip.get() == pageButton.indexProperty.get() && pageButton.isVisible()) {
pageButtons.get(i).setSelected(true); pageButton.setSelected(true);
return; return;
} }
} }

View File

@@ -15,6 +15,7 @@ import javafx.scene.control.TabPane;
import javafx.scene.control.skin.TabPaneSkin; import javafx.scene.control.skin.TabPaneSkin;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.util.Duration; import javafx.util.Duration;
import lombok.Getter;
import java.util.List; import java.util.List;
@@ -24,6 +25,7 @@ import java.util.List;
* @author 夜雨 * @author 夜雨
* @since 2022-07-24 10:54 * @since 2022-07-24 10:54
*/ */
@Getter
public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful { public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
/** 添加按钮 */ /** 添加按钮 */
@@ -36,15 +38,6 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
add.setPrefWidth(20); add.setPrefWidth(20);
} }
/**
* 获取添加按钮
*
* @return 添加按钮
*/
public IconButton getAdd() {
return add;
}
@Override @Override
protected Skin<?> createDefaultSkin() { protected Skin<?> createDefaultSkin() {
Skin<?> skin = super.createDefaultSkin(); Skin<?> skin = super.createDefaultSkin();
@@ -93,8 +86,8 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
} }
}; };
ObservableList<Node> tabList = headersRegion.getChildren(); ObservableList<Node> tabList = headersRegion.getChildren();
for (int i = 0; i < tabList.size(); i++) { for (Node node : tabList) {
resizeCloseButton.handler(tabList.get(i)); resizeCloseButton.handler(node);
} }
headersRegion.getChildren().addListener((ListChangeListener<Node>) c -> { headersRegion.getChildren().addListener((ListChangeListener<Node>) c -> {
if (c.next()) { if (c.next()) {

View File

@@ -20,6 +20,8 @@ import javafx.stage.Screen;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.Window; import javafx.stage.Window;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -38,28 +40,40 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
/** 默认内容边距 */ /** 默认内容边距 */
protected static final Insets PADDING_CONTENT = new Insets(8, 16, 8, 16); protected static final Insets PADDING_CONTENT = new Insets(8, 16, 8, 16);
/** 左侧按钮 */ /** 按钮布局面板的左侧面板(如果按钮布局主面板被修改,此面板无效) */
@Getter
protected final HBox leftButtons; protected final HBox leftButtons;
/** 中部按钮 */ /** 按钮布局面板的中间面板(如果按钮布局主面板被修改,此面板无效) */
@Getter
protected final HBox centerButtons; protected final HBox centerButtons;
/** 右侧按钮 */ /** 按钮布局面板的右侧面板(如果按钮布局主面板被修改,此面板无效) */
@Getter
protected final HBox rightButtons; protected final HBox rightButtons;
/** 根面板 */ /** 根布局BorderPane 下部分为按钮面板 */
@Getter
protected final BorderPane root; protected final BorderPane root;
/** 按钮面板,{@link #leftButtons}、{@link #centerButtons} 、{@link #rightButtons} 在此面板中 */ /** 按钮面板,{@link #leftButtons}、{@link #centerButtons} 、{@link #rightButtons} 在此面板中 */
@Getter
protected final BorderPane btnPane; protected final BorderPane btnPane;
private final ObjectProperty<AlertType> typeProperty; private final ObjectProperty<AlertType> typeProperty;
private final List<CallbackArg<WindowEvent>> shownListeners; private final List<CallbackArg<WindowEvent>> shownListeners;
/** 最近用户动作 */
@Getter
private AlertButton.Action action; private AlertButton.Action action;
/** 弹窗动作事件 */
@Setter
private CallbackArgReturn<AlertButton.Action, Boolean> onActionEvent; private CallbackArgReturn<AlertButton.Action, Boolean> onActionEvent;
/** 窗体尺寸是否适应场景尺寸,显示前设置有效,默认 true */ /** true 为窗体尺寸适应场景尺寸 */
@Setter
@Getter
protected boolean enableSizeToScene = true; protected boolean enableSizeToScene = true;
/** 默认构造 */ /** 默认构造 */
@@ -293,11 +307,11 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
/** /**
* 设置左侧弹窗按钮 * 设置左侧弹窗按钮
* *
* @param btns 按钮 * @param buttons 按钮
*/ */
public void setLeftButtons(AlertButton... btns) { public void setLeftButtons(AlertButton... buttons) {
leftButtons.getChildren().clear(); leftButtons.getChildren().clear();
putButtons(leftButtons, btns); putButtons(leftButtons, buttons);
} }
/** /**
@@ -364,85 +378,4 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
public void addShownListener(CallbackArg<WindowEvent> callback) { public void addShownListener(CallbackArg<WindowEvent> callback) {
shownListeners.add(callback); shownListeners.add(callback);
} }
/**
* 设置弹窗动作事件(用户点击带有动作的弹窗按钮)
*
* @param onActionEvent 弹窗动作事件
*/
public void setOnActionEvent(CallbackArgReturn<AlertButton.Action, Boolean> onActionEvent) {
this.onActionEvent = onActionEvent;
}
/**
* 获取最近用户动作(弹窗按钮事件动作)
*
* @return 最近用户动作
*/
public AlertButton.Action getAction() {
return action;
}
/**
* 获取窗体尺寸是否适应场景尺寸
*
* @return true 为窗体尺寸是否适应场景尺寸
*/
public boolean isEnableSizeToScene() {
return enableSizeToScene;
}
/**
* 设置窗体尺寸是否适应场景尺寸,显示前设置有效,默认 true
*
* @param enableSizeToScene true 为窗体尺寸适应场景尺寸
*/
public void setEnableSizeToScene(boolean enableSizeToScene) {
this.enableSizeToScene = enableSizeToScene;
}
/**
* 获取按钮布局的主面板
*
* @return 按钮布局主面板
*/
public BorderPane getBtnPane() {
return btnPane;
}
/**
* 获取按钮布局面板的左侧面板(如果按钮布局主面板被修改,此面板无效)
*
* @return 按钮布局左侧面板
*/
public HBox getLeftButtons() {
return leftButtons;
}
/**
* 获取按钮布局面板的中间面板(如果按钮布局主面板被修改,此面板无效)
*
* @return 按钮布局中间面板
*/
public HBox getCenterButtons() {
return centerButtons;
}
/**
* 获取按钮布局面板的右侧面板(如果按钮布局主面板被修改,此面板无效)
*
* @return 按钮布局右侧面板
*/
public HBox getRightButtons() {
return rightButtons;
}
/**
* 获取根布局BorderPane 下部分为按钮面板)
*
* @return 根布局面板
*/
public BorderPane getRoot() {
return root;
}
} }

View File

@@ -21,6 +21,8 @@ import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import lombok.Getter;
import lombok.Setter;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@@ -47,8 +49,12 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
protected final AlertButton cancel; protected final AlertButton cancel;
/** 文件目录树 */ /** 文件目录树 */
@Getter
protected final FileTreeView tree; protected final FileTreeView tree;
/** 确认事件,返回 true 自动关闭窗体 */
@Setter
@Getter
private CallbackArgReturn<List<File>, Boolean> onConfirmEvent; private CallbackArgReturn<List<File>, Boolean> onConfirmEvent;
/** /**
@@ -163,8 +169,8 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
if (items.isEmpty()) { if (items.isEmpty()) {
return true; return true;
} }
for (int i = 0; i < items.size(); i++) { for (TreeItem<File> item : items) {
if (roots.contains(items.get(i).getValue())) { if (roots.contains(item.getValue())) {
return true; return true;
} }
} }
@@ -183,7 +189,7 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
if (file.exists()) { if (file.exists()) {
tree.selectItem(file); tree.selectItem(file);
} else { } else {
AlertTips.error(this, TimiFXUI.MULTILINGUAL.textArgs("file.tips.not_found_target", absolutePath.getText())); AlertTips.error(this, TimiFXUI.MULTILINGUAL.text("file.tips.not_found_target"));
} }
} }
}); });
@@ -277,31 +283,4 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
public BooleanProperty showHideProperty() { public BooleanProperty showHideProperty() {
return toggleHide.selectedProperty(); return toggleHide.selectedProperty();
} }
/**
* 获取确认事件
*
* @return 确认事件
*/
public CallbackArgReturn<List<File>, Boolean> getOnConfirmEvent() {
return onConfirmEvent;
}
/**
* 设置确认事件,返回 true 自动关闭窗体
*
* @param onConfirmEvent 确认事件
*/
public void setOnConfirmEvent(CallbackArgReturn<List<File>, Boolean> onConfirmEvent) {
this.onConfirmEvent = onConfirmEvent;
}
/**
* 获取文件目录树
*
* @return 文件目录树
*/
public FileTreeView getTree() {
return tree;
}
} }

View File

@@ -6,6 +6,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.TextInputControl; import javafx.scene.control.TextInputControl;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import lombok.Getter;
/** /**
* 抽象输入弹窗 * 抽象输入弹窗
@@ -16,9 +17,11 @@ import javafx.scene.layout.Region;
public abstract class AbstractAlertInput<T extends TextInputControl> extends AbstractAlert { public abstract class AbstractAlertInput<T extends TextInputControl> extends AbstractAlert {
/** 输入组件 */ /** 输入组件 */
@Getter
protected final T input; protected final T input;
/** 提示文本 */ /** 提示标签组件 */
@Getter
protected final Label tips; protected final Label tips;
/** 内容面板 */ /** 内容面板 */
@@ -42,9 +45,9 @@ public abstract class AbstractAlertInput<T extends TextInputControl> extends Abs
* @param title 标题 * @param title 标题
* @param content 内容 * @param content 内容
* @param text 预设输入框文本 * @param text 预设输入框文本
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AbstractAlertInput(T t, AlertType type, String title, String content, String text, AlertButton... btns) { public AbstractAlertInput(T t, AlertType type, String title, String content, String text, AlertButton... buttons) {
tips = new Label(content); tips = new Label(content);
tips.setTextFill(GRAY); tips.setTextFill(GRAY);
tips.setWrapText(true); tips.setWrapText(true);
@@ -70,7 +73,7 @@ public abstract class AbstractAlertInput<T extends TextInputControl> extends Abs
if (TimiJava.isNotEmpty(title)) { if (TimiJava.isNotEmpty(title)) {
setTitle(title); setTitle(title);
} }
putButtons(btns); putButtons(buttons);
} }
/** /**
@@ -90,22 +93,4 @@ public abstract class AbstractAlertInput<T extends TextInputControl> extends Abs
public void setTips(String tips) { public void setTips(String tips) {
this.tips.setText(tips); this.tips.setText(tips);
} }
/**
* 获取提示标签组件
*
* @return 提示标签组件
*/
public Label getTips() {
return tips;
}
/**
* 获取输入组件
*
* @return 输入组件
*/
public T getInput() {
return input;
}
} }

View File

@@ -3,6 +3,8 @@ package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import lombok.Data;
import lombok.EqualsAndHashCode;
/** /**
* 弹窗按钮 * 弹窗按钮
@@ -10,6 +12,8 @@ import javafx.scene.control.Button;
* @author 夜雨 * @author 夜雨
* @since 2022-01-07 09:37 * @since 2022-01-07 09:37
*/ */
@Data
@EqualsAndHashCode(callSuper = true)
public class AlertButton extends Button { public class AlertButton extends Button {
/** /**
@@ -60,7 +64,10 @@ public class AlertButton extends Button {
OTHER OTHER
} }
/** 按钮所属位置 */
HPos pos; HPos pos;
/** 按钮动作 */
Action action; Action action;
/** /**
@@ -85,60 +92,6 @@ public class AlertButton extends Button {
this.action = action; this.action = action;
} }
/**
* 获取按钮所属位置
*
* @return 按钮所属位置
*/
public HPos getPos() {
return pos;
}
/**
* 设置按钮所属位置
*
* @param pos 按钮所属位置
*/
public void setPos(HPos pos) {
this.pos = pos;
}
/**
* 获取按钮动作
*
* @return 按钮动作
*/
public Action getAction() {
return action;
}
/**
* 设置按钮动作
*
* @param action 按钮动作
*/
public void setAction(Action action) {
this.action = action;
}
/**
* 按钮动作是否一致
*
* @param o 比较对象
* @return true 为按钮动作 AlertButton.Action 相同
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AlertButton that = (AlertButton) o;
return action == that.action;
}
/** /**
* 快速构造应用按钮 * 快速构造应用按钮
* *

View File

@@ -41,10 +41,10 @@ public abstract class AlertConfirm extends AlertTips {
* *
* @param type 类型 * @param type 类型
* @param content 提示内容 * @param content 提示内容
* @param btns 按钮 * @param buttons 按钮
*/ */
public AlertConfirm(AlertType type, String content, AlertButton... btns) { public AlertConfirm(AlertType type, String content, AlertButton... buttons) {
super(type, btns); super(type, buttons);
setTips(content); setTips(content);
setOnActionEvent(action -> { setOnActionEvent(action -> {

View File

@@ -11,6 +11,7 @@ import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.control.SelectionMode; import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import lombok.Getter;
import java.io.File; import java.io.File;
@@ -23,6 +24,7 @@ import java.io.File;
public class AlertFileSelector extends AbstractAlertFile { public class AlertFileSelector extends AbstractAlertFile {
/** 格式过滤列表 */ /** 格式过滤列表 */
@Getter
protected final ObservableList<String> formatFilters; protected final ObservableList<String> formatFilters;
private String[] formatFiltersCache; private String[] formatFiltersCache;
@@ -75,13 +77,4 @@ public class AlertFileSelector extends AbstractAlertFile {
public void removeFormatFilters(String... formats) { public void removeFormatFilters(String... formats) {
formatFilters.removeAll(formats); formatFilters.removeAll(formats);
} }
/**
* 获取格式过滤列表
*
* @return 格式过滤列表
*/
public ObservableList<String> getFormatFilters() {
return formatFilters;
}
} }

View File

@@ -23,10 +23,10 @@ public class AlertPassword extends AbstractAlertInput<PasswordField> {
* 密码输入弹窗 * 密码输入弹窗
* *
* @param content 内容 * @param content 内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertPassword(String content, AlertButton... btns) { public AlertPassword(String content, AlertButton... buttons) {
this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), content, "", btns); this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), content, "", buttons);
} }
/** /**
@@ -36,9 +36,9 @@ public class AlertPassword extends AbstractAlertInput<PasswordField> {
* @param title 标题 * @param title 标题
* @param content 内容 * @param content 内容
* @param text 预设输入框文本 * @param text 预设输入框文本
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertPassword(AlertType type, String title, String content, String text, AlertButton... btns) { public AlertPassword(AlertType type, String title, String content, String text, AlertButton... buttons) {
super(new PasswordField(), type, title, content, text, btns); super(new PasswordField(), type, title, content, text, buttons);
} }
} }

View File

@@ -11,6 +11,7 @@ import javafx.geometry.Insets;
import javafx.scene.control.TextArea; import javafx.scene.control.TextArea;
import javafx.scene.layout.Border; import javafx.scene.layout.Border;
import javafx.stage.Window; import javafx.stage.Window;
import lombok.Getter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@@ -23,7 +24,8 @@ import java.io.StringWriter;
*/ */
public class AlertTextArea extends AbstractAlertInput<TextArea> { public class AlertTextArea extends AbstractAlertInput<TextArea> {
/** 反馈事件 */ /** 反馈错误事件 */
@Getter
private static CallbackArg<String> onFeedback4Error; private static CallbackArg<String> onFeedback4Error;
/** 默认构造 */ /** 默认构造 */
@@ -54,10 +56,10 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
* 文本域输入弹窗 * 文本域输入弹窗
* *
* @param text 输入内容 * @param text 输入内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTextArea(String text, AlertButton... btns) { public AlertTextArea(String text, AlertButton... buttons) {
this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), "", text, btns); this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), "", text, buttons);
} }
/** /**
@@ -65,10 +67,10 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
* *
* @param content 提示 * @param content 提示
* @param text 输入内容 * @param text 输入内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTextArea(String content, String text, AlertButton... btns) { public AlertTextArea(String content, String text, AlertButton... buttons) {
this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), content, text, btns); this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), content, text, buttons);
} }
/** /**
@@ -78,10 +80,10 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
* @param title 标题 * @param title 标题
* @param content 内容 * @param content 内容
* @param text 预设输入框文本 * @param text 预设输入框文本
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTextArea(AlertType type, String title, String content, String text, AlertButton... btns) { public AlertTextArea(AlertType type, String title, String content, String text, AlertButton... buttons) {
super(new TextArea(), type, title, content, text, btns); super(new TextArea(), type, title, content, text, buttons);
SmoothScroll.textarea(getInput()); SmoothScroll.textarea(getInput());
setResizable(true); setResizable(true);
@@ -195,15 +197,6 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
return alert; return alert;
} }
/**
* 获取反馈错误事件
*
* @return 反馈错误事件
*/
public static CallbackArg<String> getOnFeedback4Error() {
return onFeedback4Error;
}
/** /**
* 设置反馈错误事件,全局事件,设置一次即可 * 设置反馈错误事件,全局事件,设置一次即可
* *

View File

@@ -34,10 +34,10 @@ public class AlertTextField extends AbstractAlertInput<TextField> {
* 输入弹窗 * 输入弹窗
* *
* @param content 提示 * @param content 提示
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTextField(String content, AlertButton... btns) { public AlertTextField(String content, AlertButton... buttons) {
this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), content, "", btns); this(AlertType.INFORMATION, AlertType.INFORMATION.getTitle(), content, "", buttons);
} }
/** /**
@@ -45,10 +45,10 @@ public class AlertTextField extends AbstractAlertInput<TextField> {
* *
* @param type 弹窗类型 * @param type 弹窗类型
* @param content 内容 * @param content 内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTextField(AlertType type, String content, AlertButton... btns) { public AlertTextField(AlertType type, String content, AlertButton... buttons) {
super(new TextField(), type, type.getTitle(), content, "", btns); super(new TextField(), type, type.getTitle(), content, "", buttons);
} }
/** /**
@@ -58,10 +58,10 @@ public class AlertTextField extends AbstractAlertInput<TextField> {
* @param title 标题 * @param title 标题
* @param content 内容 * @param content 内容
* @param text 预设输入框文本 * @param text 预设输入框文本
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTextField(AlertType type, String title, String content, String text, AlertButton... btns) { public AlertTextField(AlertType type, String title, String content, String text, AlertButton... buttons) {
super(new TextField(), type, title, content, text, btns); super(new TextField(), type, title, content, text, buttons);
} }
/** /**

View File

@@ -1,7 +1,9 @@
package com.imyeyu.fx.ui.components.alert; package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.java.TimiJava;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.stage.Window; import javafx.stage.Window;
import lombok.Getter;
/** /**
* 弹窗提示 * 弹窗提示
@@ -9,6 +11,7 @@ import javafx.stage.Window;
* @author 夜雨 * @author 夜雨
* @since 2022-01-07 11:29 * @since 2022-01-07 11:29
*/ */
@Getter
public class AlertTips extends AbstractAlert { public class AlertTips extends AbstractAlert {
/** 提示标签 */ /** 提示标签 */
@@ -27,20 +30,20 @@ public class AlertTips extends AbstractAlert {
* 弹窗提示 * 弹窗提示
* *
* @param content 内容 * @param content 内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTips(String content, AlertButton... btns) { public AlertTips(String content, AlertButton... buttons) {
this(AlertType.INFORMATION, null, content, btns); this(AlertType.INFORMATION, null, content, buttons);
} }
/** /**
* 弹窗提示 * 弹窗提示
* *
* @param type 类型 * @param type 类型
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTips(AlertType type, AlertButton... btns) { public AlertTips(AlertType type, AlertButton... buttons) {
this(type, null, "", btns); this(type, null, "", buttons);
} }
/** /**
@@ -58,10 +61,10 @@ public class AlertTips extends AbstractAlert {
* *
* @param type 类型 * @param type 类型
* @param content 内容 * @param content 内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTips(AlertType type, String content, AlertButton... btns) { public AlertTips(AlertType type, String content, AlertButton... buttons) {
this(type, null, content, btns); this(type, null, content, buttons);
} }
/** /**
@@ -70,9 +73,9 @@ public class AlertTips extends AbstractAlert {
* @param type 类型 * @param type 类型
* @param title 标题 * @param title 标题
* @param content 内容 * @param content 内容
* @param btns 可控按钮 * @param buttons 可控按钮
*/ */
public AlertTips(AlertType type, String title, String content, AlertButton... btns) { public AlertTips(AlertType type, String title, String content, AlertButton... buttons) {
tips = new Label(content); tips = new Label(content);
tips.setPadding(PADDING_CONTENT); tips.setPadding(PADDING_CONTENT);
tips.setWrapText(true); tips.setWrapText(true);
@@ -82,10 +85,10 @@ public class AlertTips extends AbstractAlert {
setResizable(false); setResizable(false);
setType(type); setType(type);
if (title != null && !title.trim().equals("")) { if (TimiJava.isNotEmpty(title)) {
setTitle(title); setTitle(title);
} }
putButtons(btns); putButtons(buttons);
} }
/** /**
@@ -97,15 +100,6 @@ public class AlertTips extends AbstractAlert {
this.tips.setText(tips); this.tips.setText(tips);
} }
/**
* 获取提示标签
*
* @return 提示标签
*/
public Label getTips() {
return tips;
}
// ---------- 快速构造 ---------- // ---------- 快速构造 ----------
/** /**

View File

@@ -2,6 +2,8 @@ package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import lombok.AllArgsConstructor;
import lombok.Getter;
/** /**
* 弹窗类型 * 弹窗类型
@@ -9,6 +11,8 @@ import javafx.scene.image.Image;
* @author 夜雨 * @author 夜雨
* @since 2022-01-07 10:51 * @since 2022-01-07 10:51
*/ */
@Getter
@AllArgsConstructor
public enum AlertType { public enum AlertType {
/** 信息 */ /** 信息 */
@@ -26,29 +30,9 @@ public enum AlertType {
/** 错误 */ /** 错误 */
ERROR(new Image("timifx/dialog-error16x.png"), TimiFXUI.MULTILINGUAL.text("error", "错误")); ERROR(new Image("timifx/dialog-error16x.png"), TimiFXUI.MULTILINGUAL.text("error", "错误"));
/** 弹窗类型图标 */
final Image icon; final Image icon;
/** 弹窗类型标题 */
final String title; final String title;
AlertType(Image icon, String title) {
this.icon = icon;
this.title = title;
}
/**
* 获取弹窗类型的图标
*
* @return 弹窗类型图标
*/
public Image getIcon() {
return icon;
}
/**
* 获取弹窗类型的标题
*
* @return 弹窗类型标题
*/
public String getTitle() {
return title;
}
} }

View File

@@ -1,20 +1,17 @@
package com.imyeyu.fx.ui.examples; package com.imyeyu.fx.ui.examples;
import com.imyeyu.inject.InjectApp;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import com.imyeyu.config.ConfigLoader; import com.imyeyu.config.ConfigLoader;
import com.imyeyu.fx.config.BindingsConfig; import com.imyeyu.fx.config.BindingsConfig;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.examples.bean.Config; import com.imyeyu.fx.ui.examples.bean.Config;
import com.imyeyu.fx.ui.examples.ctrl.Main; import com.imyeyu.fx.ui.examples.ctrl.Main;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.TimiInjectApplication; import com.imyeyu.inject.annotation.TimiInjectApplication;
import com.imyeyu.java.bean.Language; import com.imyeyu.java.bean.Language;
import com.imyeyu.lang.multi.ResourcesMultilingual; import com.imyeyu.lang.multi.ResourcesMultilingual;
import javafx.application.Application;
import java.util.Map; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/** /**
* TimiFX 示例程序 * TimiFX 示例程序
@@ -27,7 +24,7 @@ import java.util.Map;
public class TimiFXExamples { public class TimiFXExamples {
/** 版本号 */ /** 版本号 */
public static final String VERSION = "1.1.0"; public static final String VERSION = "1.1.1";
@Getter @Getter
private static Config config; private static Config config;
@@ -36,31 +33,23 @@ public class TimiFXExamples {
private static ConfigLoader<Config> configLoader; private static ConfigLoader<Config> configLoader;
@Getter @Getter
private static InjectApp injectApp; public static TimiInject inject;
public static void main(String[] args) { public static void main(String[] args) {
try {
injectApp = new InjectApp(TimiFXExamples.class);
{ {
configLoader = new ConfigLoader<>("TimiFXExamples.yaml", Config.class); configLoader = new ConfigLoader<>("TimiFXExamples.yaml", Config.class);
for (Map.Entry<Class<?>, BindingsConfig.PropertyConverter<?, ?>> item : BindingsConfig.DEFAULT_CONVERTER_MAP.entrySet()) { BindingsConfig.addAllFXConverter(configLoader);
configLoader.addConverter(item.getKey(), item.getValue());
}
configLoader.addConverter(ObjectProperty.class, BindingsConfig.OBJECT);
config = configLoader.load(); config = configLoader.load();
ResourcesMultilingual multilingual = TimiFXUI.MULTILINGUAL; ResourcesMultilingual multilingual = TimiFXUI.MULTILINGUAL;
multilingual.addAll("lang/timi-fx-ui/%s.lang"); multilingual.addAll("lang/timi-fx-ui/%s.lang");
multilingual.addAll("lang/%s.lang"); multilingual.addAll("lang/%s.lang");
multilingual.setActivated(Language.zh_CN); multilingual.setActivated(Language.Enum.zh_CN);
// 禁止系统 DPI 缩放 // 禁止系统 DPI 缩放
System.setProperty("prism.allowhidpi", "false"); System.setProperty("prism.allowhidpi", "false");
System.setProperty("glass.win.minHiDPI", "1"); System.setProperty("glass.win.minHiDPI", "1");
} }
Application.launch(Main.class); Application.launch(Main.class);
} catch (Exception e) {
log.error("fatal error", e);
}
} }
} }

View File

@@ -1,9 +1,9 @@
package com.imyeyu.fx.ui.examples.bean; package com.imyeyu.fx.ui.examples.bean;
import com.imyeyu.java.bean.Language;
import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import lombok.Data; import lombok.Data;
import com.imyeyu.java.bean.Language;
/** /**
* @author 夜雨 * @author 夜雨
@@ -12,7 +12,7 @@ import com.imyeyu.java.bean.Language;
@Data @Data
public class Config { public class Config {
private ObjectProperty<Language> language; private ObjectProperty<Language.Enum> language;
private DoubleProperty width; private DoubleProperty width;

View File

@@ -1,10 +1,6 @@
package com.imyeyu.fx.ui.examples.component; package com.imyeyu.fx.ui.examples.component;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.fx.ui.examples.service.PageService;
import com.imyeyu.inject.annotation.Inject;
import com.imyeyu.inject.annotation.StaticInject;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
/** /**
@@ -13,12 +9,8 @@ import javafx.scene.layout.BorderPane;
* @author 夜雨 * @author 夜雨
* @since 2022-08-26 14:55 * @since 2022-08-26 14:55
*/ */
@StaticInject
public abstract class AbstractPane extends BorderPane implements TimiFXUI { public abstract class AbstractPane extends BorderPane implements TimiFXUI {
@Inject
private static PageService pageService;
/** 显示时触发UI 线程 */ /** 显示时触发UI 线程 */
protected void onShow() { protected void onShow() {
// 子类实现 // 子类实现
@@ -29,15 +21,6 @@ public abstract class AbstractPane extends BorderPane implements TimiFXUI {
// 子类实现 // 子类实现
} }
/**
* 跳转页面
*
* @param page 页面
*/
protected final void toPage(SidebarItem page) {
pageService.to(page);
}
/** 显示面板事件,由调用者触发,通常是侧边导航 */ /** 显示面板事件,由调用者触发,通常是侧边导航 */
public final void show() { public final void show() {
onShow(); onShow();

View File

@@ -2,9 +2,9 @@ package com.imyeyu.fx.ui.examples.component;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.examples.component.sidebar.Sidebar; import com.imyeyu.fx.ui.examples.component.sidebar.Sidebar;
import com.imyeyu.fx.ui.examples.service.PageService;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.InvokeForInjected;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
/** /**
@@ -16,15 +16,26 @@ import javafx.scene.layout.BorderPane;
@Component @Component
public class RootLayout extends BorderPane implements TimiFXUI { public class RootLayout extends BorderPane implements TimiFXUI {
@Inject private final Sidebar sidebar;
private Sidebar sidebar; private final PageService pageService;
public RootLayout() { public RootLayout(Sidebar sidebar, PageService pageService) {
this.sidebar = sidebar;
this.pageService = pageService;
setBorder(Stroke.TOP); setBorder(Stroke.TOP);
} }
@InvokeForInjected @PostConstruct
public void init() { public void init() {
setLeft(sidebar); setLeft(sidebar);
pageService.activatedPageProperty().addListener((obs, prev, now) -> {
if (now != null && now.getIOCPage() instanceof AbstractPane pane) {
pane.show();
setCenter(pane);
}
if (prev != null && prev.getIOCPage() instanceof AbstractPane pane) {
pane.hide();
}
});
} }
} }

View File

@@ -22,7 +22,7 @@ public class TimiVersionLabel extends VersionLabel<JsonObject> {
private final String appName; private final String appName;
public TimiVersionLabel(String nowVersion, String appName) { public TimiVersionLabel(String nowVersion, String appName) {
super(TimiFXUI.MULTILINGUAL.textArgs("version.checking", nowVersion)); super(TimiFXUI.MULTILINGUAL.text("version.checking"));
this.nowVersion = nowVersion; this.nowVersion = nowVersion;
this.appName = appName; this.appName = appName;
@@ -58,11 +58,11 @@ public class TimiVersionLabel extends VersionLabel<JsonObject> {
@Override @Override
protected String updateText(String newVersion) { protected String updateText(String newVersion) {
return TimiFXUI.MULTILINGUAL.textArgs("version.new", nowVersion, newVersion); return TimiFXUI.MULTILINGUAL.text("version.new");
} }
@Override @Override
protected String failText(Throwable e) { protected String failText(Throwable e) {
return TimiFXUI.MULTILINGUAL.textArgs("version.fail", nowVersion); return TimiFXUI.MULTILINGUAL.text("version.fail");
} }
} }

View File

@@ -31,15 +31,13 @@ public class InterpolatorPane extends BorderPane implements TimiFXUI {
private final Region block; private final Region block;
public InterpolatorPane(Interpolates interpolator) { public InterpolatorPane(Interpolates interpolator) {
SplineInterpolator si = interpolator.getValue();
// 二次曲线 // 二次曲线
Canvas canvas = new Canvas(); Canvas canvas = new Canvas();
canvas.setWidth(64); canvas.setWidth(64);
canvas.setHeight(64); canvas.setHeight(64);
// 插值 // 插值
SelectableLabel label = new SelectableLabel(TimiFXUI.MULTILINGUAL.textArgs("fx.example.interpolator.demo", interpolator, si.getX1(), si.getY1(), si.getX2(), si.getY2())); SelectableLabel label = new SelectableLabel(TimiFXUI.MULTILINGUAL.text("fx.example.interpolator.demo"));
// 方块 // 方块
block = new Region(); block = new Region();
@@ -76,7 +74,7 @@ public class InterpolatorPane extends BorderPane implements TimiFXUI {
// 绘制图示 // 绘制图示
{ {
double[][] list = interpolator.buildBezierPoint(canvas.getWidth(), canvas.getWidth() * .5); double[][] list = interpolator.buildBezierPoint(canvas.getWidth(), (long) (canvas.getWidth() * .5));
GraphicsContext g = canvas.getGraphicsContext2D(); GraphicsContext g = canvas.getGraphicsContext2D();
g.setFill(Colorful.WHITE); g.setFill(Colorful.WHITE);
g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

View File

@@ -4,7 +4,6 @@ import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.components.Navigation; import com.imyeyu.fx.ui.components.Navigation;
import com.imyeyu.fx.ui.examples.service.PageService; import com.imyeyu.fx.ui.examples.service.PageService;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Inject;
import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleButton;
/** /**
@@ -16,10 +15,8 @@ import javafx.scene.control.ToggleButton;
@Component @Component
public class Sidebar extends Navigation { public class Sidebar extends Navigation {
@Inject public Sidebar(PageService pageService) {
private PageService pageService;
public Sidebar() {
Item welcome = new Item(SidebarItem.WELCOME); Item welcome = new Item(SidebarItem.WELCOME);
Item style = new Item(SidebarItem.STYLE); Item style = new Item(SidebarItem.STYLE);
Item extendTools = new Item(SidebarItem.EXTEND_TOOLS); Item extendTools = new Item(SidebarItem.EXTEND_TOOLS);
@@ -37,25 +34,7 @@ public class Sidebar extends Navigation {
addGroup(TimiFXUI.MULTILINGUAL.text("animation"), interpolator, smoothScroll); addGroup(TimiFXUI.MULTILINGUAL.text("animation"), interpolator, smoothScroll);
// 组件 // 组件
SidebarItem[] components = { SidebarItem[] components = {SidebarItem.CHECK_BOX_PICKER, SidebarItem.DATE_TIME_PICKER, SidebarItem.EDITABLE_TABLE_CELL, SidebarItem.FILE_TREE_VIEW, SidebarItem.ICON_BUTTON, SidebarItem.ICON_PICKER, SidebarItem.LABEL_PROGRESS_BAR, SidebarItem.NAVIGATION, SidebarItem.NUMBER_FIELD, SidebarItem.PROGRESS_SLIDER, SidebarItem.SELECTABLE_LABEL, SidebarItem.TEXT_AREA_EDITOR, SidebarItem.TITLE_LABEL, SidebarItem.TOGGLE_ICON, SidebarItem.X_PAGINATION, SidebarItem.X_TAB_PANE, SidebarItem.X_TREE_VIEW};
SidebarItem.CHECK_BOX_PICKER,
SidebarItem.DATE_TIME_PICKER,
SidebarItem.EDITABLE_TABLE_CELL,
SidebarItem.FILE_TREE_VIEW,
SidebarItem.ICON_BUTTON,
SidebarItem.ICON_PICKER,
SidebarItem.LABEL_PROGRESS_BAR,
SidebarItem.NAVIGATION,
SidebarItem.NUMBER_FIELD,
SidebarItem.PROGRESS_SLIDER,
SidebarItem.SELECTABLE_LABEL,
SidebarItem.TEXT_AREA_EDITOR,
SidebarItem.TITLE_LABEL,
SidebarItem.TOGGLE_ICON,
SidebarItem.X_PAGINATION,
SidebarItem.X_TAB_PANE,
SidebarItem.X_TREE_VIEW
};
Item[] componentItems = new Item[components.length]; Item[] componentItems = new Item[components.length];
for (int i = 0; i < componentItems.length; i++) { for (int i = 0; i < componentItems.length; i++) {
componentItems[i] = new Item(components[i]); componentItems[i] = new Item(components[i]);

View File

@@ -155,6 +155,6 @@ public enum SidebarItem {
/** @return 从 TimiInject 控制反转对象获取该页面 */ /** @return 从 TimiInject 控制反转对象获取该页面 */
public Node getIOCPage() { public Node getIOCPage() {
return TimiFXExamples.getInjectApp().injector().di(page); return TimiFXExamples.getInject().getBean(page);
} }
} }

View File

@@ -1,15 +1,13 @@
package com.imyeyu.fx.ui.examples.ctrl; package com.imyeyu.fx.ui.examples.ctrl;
import com.imyeyu.fx.inject.FXTimiInject;
import com.imyeyu.fx.ui.components.TrayFX; import com.imyeyu.fx.ui.components.TrayFX;
import com.imyeyu.fx.ui.examples.TimiFXExamples; import com.imyeyu.fx.ui.examples.TimiFXExamples;
import com.imyeyu.fx.ui.examples.component.sidebar.Sidebar; import com.imyeyu.fx.ui.examples.component.sidebar.Sidebar;
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem; import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.fx.ui.examples.service.PageService; import com.imyeyu.fx.ui.examples.service.PageService;
import com.imyeyu.fx.ui.examples.view.ViewMain; import com.imyeyu.fx.ui.examples.view.ViewMain;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.IOCReturn;
import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.Inject;
import com.imyeyu.inject.annotation.SuperInject;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.awt.SplashScreen; import java.awt.SplashScreen;
@@ -20,7 +18,6 @@ import java.awt.SplashScreen;
* @author 夜雨 * @author 夜雨
* @since 2022-05-03 15:43 * @since 2022-05-03 15:43
*/ */
@SuperInject
public class Main extends ViewMain { public class Main extends ViewMain {
@Inject @Inject
@@ -38,7 +35,7 @@ public class Main extends ViewMain {
public void start(Stage stage) { public void start(Stage stage) {
this.stage = stage; this.stage = stage;
TimiInject.run(TimiFXExamples.getInjectApp()).ioc(this); TimiFXExamples.inject = FXTimiInject.run(TimiFXExamples.class, this, stage);
super.start(stage); super.start(stage);
sidebar.setSelected(SidebarItem.WELCOME); sidebar.setSelected(SidebarItem.WELCOME);
@@ -58,10 +55,4 @@ public class Main extends ViewMain {
trayFX.remove(); trayFX.remove();
stage.close(); stage.close();
} }
/** 主窗体 */
@IOCReturn
public Stage getStage() {
return stage;
}
} }

View File

@@ -1,14 +1,10 @@
package com.imyeyu.fx.ui.examples.service; package com.imyeyu.fx.ui.examples.service;
import com.imyeyu.fx.ui.examples.component.AbstractPane;
import com.imyeyu.fx.ui.examples.component.RootLayout;
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem; import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.inject.annotation.Inject;
import com.imyeyu.inject.annotation.Service; import com.imyeyu.inject.annotation.Service;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import lombok.extern.slf4j.Slf4j;
/** /**
* 页面服务 * 页面服务
@@ -16,13 +12,9 @@ import lombok.extern.slf4j.Slf4j;
* @author 夜雨 * @author 夜雨
* @since 2021-12-26 10:57 * @since 2021-12-26 10:57
*/ */
@Slf4j
@Service @Service
public class PageService { public class PageService {
@Inject
private RootLayout root;
private SidebarItem prev; private SidebarItem prev;
private final ObjectProperty<SidebarItem> activatedPageProperty; private final ObjectProperty<SidebarItem> activatedPageProperty;
@@ -31,13 +23,6 @@ public class PageService {
activatedPageProperty = new SimpleObjectProperty<>(); activatedPageProperty = new SimpleObjectProperty<>();
activatedPageProperty.addListener((obs, prev, now) -> { activatedPageProperty.addListener((obs, prev, now) -> {
this.prev = prev; this.prev = prev;
if (now != null && now.getIOCPage() instanceof AbstractPane pane) {
pane.show();
root.setCenter(pane);
}
if (prev != null && prev.getIOCPage() instanceof AbstractPane pane) {
pane.hide();
}
}); });
} }

View File

@@ -4,7 +4,8 @@ import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.components.TrayFX; import com.imyeyu.fx.ui.components.TrayFX;
import com.imyeyu.fx.ui.examples.TimiFXExamples; import com.imyeyu.fx.ui.examples.TimiFXExamples;
import com.imyeyu.fx.ui.examples.bean.Config; import com.imyeyu.fx.ui.examples.bean.Config;
import com.imyeyu.inject.annotation.IOCReturn; import com.imyeyu.inject.annotation.Bean;
import com.imyeyu.inject.annotation.Configuration;
import javafx.scene.image.Image; import javafx.scene.image.Image;
/** /**
@@ -13,19 +14,19 @@ import javafx.scene.image.Image;
* @author 夜雨 * @author 夜雨
* @since 2022-08-26 15:23 * @since 2022-08-26 15:23
*/ */
@com.imyeyu.inject.annotation.Resources @Configuration
public class Resources implements TimiFXUI { public class Resources implements TimiFXUI {
public static final Image ICON_X64 = new Image(RESOURCE + "icon.png", 64, 64, true, false); public static final Image ICON_X64 = new Image(RESOURCE + "icon.png", 64, 64, true, false);
/** @return 配置 */ /** @return 配置 */
@IOCReturn @Bean
public Config config() { public Config config() {
return TimiFXExamples.getConfig(); return TimiFXExamples.getConfig();
} }
/** @return 托盘 */ /** @return 托盘 */
@IOCReturn @Bean
public TrayFX trayFX() { public TrayFX trayFX() {
return TrayFX.getInstance(); return TrayFX.getInstance();
} }

View File

@@ -13,7 +13,6 @@ import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.fx.ui.examples.ctrl.Main; import com.imyeyu.fx.ui.examples.ctrl.Main;
import com.imyeyu.fx.utils.AnimationRenderer; import com.imyeyu.fx.utils.AnimationRenderer;
import com.imyeyu.fx.utils.Column; import com.imyeyu.fx.utils.Column;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.io.IO; import com.imyeyu.io.IO;
import com.imyeyu.utils.OS; import com.imyeyu.utils.OS;
@@ -65,7 +64,7 @@ public class AnimationRendererDemo extends AbstractDemoPane implements OS.FileSy
SelectableLabel status = new SelectableLabel("-Djavafx.animation.fullspeed=" + isFullSpeed); SelectableLabel status = new SelectableLabel("-Djavafx.animation.fullspeed=" + isFullSpeed);
// 重启 // 重启
Button restart = new Button(TimiFXUI.MULTILINGUAL.textArgs("fx.example.animation_renderer.restart", TimiFXUI.MULTILINGUAL.text(isFullSpeed ? "disable" : "enable"))); Button restart = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.animation_renderer.restart"));
// 示例 // 示例
Label labelDemo = TimiFXUI.title(TimiFXUI.MULTILINGUAL.text("example")); Label labelDemo = TimiFXUI.title(TimiFXUI.MULTILINGUAL.text("example"));
@@ -154,7 +153,7 @@ fps.valueProperty().addListener((obs, o, newFps) -> {
String jar = IO.getJarAbsolutePath(getClass()); String jar = IO.getJarAbsolutePath(getClass());
// 重启 // 重启
try { try {
TimiFX.doRestart(TimiFXExamples.getInjectApp().injector().di(Main.class), jre + param + jar); TimiFX.doRestart(TimiFXExamples.getInject().getBean(Main.class), jre + param + jar);
} catch (Exception ex) { } catch (Exception ex) {
AlertTips.error(getScene().getWindow(), TimiFXUI.MULTILINGUAL.text("tips.restart.error")); AlertTips.error(getScene().getWindow(), TimiFXUI.MULTILINGUAL.text("tips.restart.error"));
} }

View File

@@ -9,8 +9,7 @@ import com.imyeyu.fx.ui.examples.bean.Config;
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane; import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem; import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.InvokeForInjected;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -27,12 +26,11 @@ import javafx.scene.layout.VBox;
@Component @Component
public class BindingsConfigDemo extends AbstractDemoPane { public class BindingsConfigDemo extends AbstractDemoPane {
@Inject private final Config config;
private Config config;
private final Label stageSize, interpolatorDuration; private final Label stageSize, interpolatorDuration;
public BindingsConfigDemo() { public BindingsConfigDemo(Config config) {
this.config = config;
title.setText(SidebarItem.BINDING_CONFIG.getText()); title.setText(SidebarItem.BINDING_CONFIG.getText());
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/config/BindingsConfig.html"); document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/config/BindingsConfig.html");
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/config/BindingsConfig.java"); source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/config/BindingsConfig.java");
@@ -95,8 +93,8 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
}}); }});
} }
@InvokeForInjected @PostConstruct
private void config() { private void init() {
stageSize.textProperty().bind(Bindings.createStringBinding(() -> "[%s, %s]".formatted(config.getWidth().get(), config.getHeight().get()), config.getWidth(), config.getHeight())); stageSize.textProperty().bind(Bindings.createStringBinding(() -> "[%s, %s]".formatted(config.getWidth().get(), config.getHeight().get()), config.getWidth(), config.getHeight()));
interpolatorDuration.textProperty().bind(config.getInterpolator().getDuration().asString()); interpolatorDuration.textProperty().bind(config.getInterpolator().getDuration().asString());
} }

View File

@@ -13,14 +13,11 @@ import com.imyeyu.fx.ui.examples.component.TimiVersionLabel;
import com.imyeyu.fx.ui.examples.ctrl.Main; import com.imyeyu.fx.ui.examples.ctrl.Main;
import com.imyeyu.fx.ui.examples.util.Resources; import com.imyeyu.fx.ui.examples.util.Resources;
import com.imyeyu.fx.utils.Column; import com.imyeyu.fx.utils.Column;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.InvokeForInjected;
import com.imyeyu.io.IO; import com.imyeyu.io.IO;
import com.imyeyu.java.bean.Language; import com.imyeyu.java.bean.Language;
import com.imyeyu.utils.OS; import com.imyeyu.utils.OS;
import com.imyeyu.utils.Time;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
@@ -31,11 +28,8 @@ import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.text.TextAlignment; import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import java.util.Date;
/** /**
* 欢迎页 * 欢迎页
* *
@@ -45,15 +39,11 @@ import java.util.Date;
@Component @Component
public class Welcome extends AbstractPane implements OS.FileSystem { public class Welcome extends AbstractPane implements OS.FileSystem {
@Inject private final Config config;
private Config config; private final ComboBox<Language.Enum> language;
@Inject public Welcome(Config config) {
private Stage stage; this.config = config;
private final ComboBox<Language> language;
public Welcome() {
Label title = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.title"), new ImageView(Resources.ICON_X64)); Label title = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.title"), new ImageView(Resources.ICON_X64));
title.setMaxWidth(Double.MAX_VALUE); title.setMaxWidth(Double.MAX_VALUE);
title.setAlignment(Pos.CENTER); title.setAlignment(Pos.CENTER);
@@ -76,16 +66,16 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
labelLang.setTextFill(Colorful.GRAY); labelLang.setTextFill(Colorful.GRAY);
language = new ComboBox<>(); language = new ComboBox<>();
language.getItems().addAll(Language.values()); language.getItems().addAll(Language.Enum.values());
language.setConverter(new StringConverter<>() { language.setConverter(new StringConverter<>() {
@Override @Override
public String toString(Language language) { public String toString(Language.Enum language) {
return language.getName(); return language.toString();
} }
@Override @Override
public Language fromString(String string) { public Language.Enum fromString(String string) {
return null; return null;
} }
}); });
@@ -95,13 +85,13 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
license.setTextAlignment(TextAlignment.CENTER); license.setTextAlignment(TextAlignment.CENTER);
// 开发者 // 开发者
Label develop = new Label(TimiFXUI.MULTILINGUAL.textArgs("developer.arg", "夜雨")); Label develop = new Label(TimiFXUI.MULTILINGUAL.text("developer.arg"));
develop.setAlignment(Pos.CENTER); develop.setAlignment(Pos.CENTER);
TextFlower blog = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("blog")); TextFlower blog = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("blog"));
blog.setTextAlignment(TextAlignment.CENTER); blog.setTextAlignment(TextAlignment.CENTER);
Label copyright = new Label(TimiFXUI.MULTILINGUAL.textArgs("copyright", "夜雨", Time.yearFull.format(new Date()))); Label copyright = new Label(TimiFXUI.MULTILINGUAL.text("copyright"));
copyright.setAlignment(Pos.CENTER); copyright.setAlignment(Pos.CENTER);
Label versionTimiFX = new Label(TimiFXUI.MULTILINGUAL.textArgs("fx.example.welcome.version.timifx", "0.0.1")); Label versionTimiFX = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.version.timifx"));
TimiVersionLabel version = new TimiVersionLabel(TimiFXExamples.VERSION, TimiFXExamples.class.getSimpleName()) {{ TimiVersionLabel version = new TimiVersionLabel(TimiFXExamples.VERSION, TimiFXExamples.class.getSimpleName()) {{
version.setGraphic(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.version"))); version.setGraphic(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.version")));
}}; }};
@@ -145,8 +135,8 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
}}); }});
} }
@InvokeForInjected @PostConstruct
private void injected() { private void init() {
language.valueProperty().bind(config.getLanguage()); language.valueProperty().bind(config.getLanguage());
// 修改语言 // 修改语言
@@ -163,7 +153,7 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
String jar = IO.getJarAbsolutePath(getClass()); String jar = IO.getJarAbsolutePath(getClass());
// 重启 // 重启
try { try {
TimiFX.doRestart(TimiFXExamples.getInjectApp().injector().di(Main.class), jre + param + jar); TimiFX.doRestart(TimiFXExamples.getInject().getBean(Main.class), jre + param + jar);
} catch (Exception ex) { } catch (Exception ex) {
AlertTips.error(this, TimiFXUI.MULTILINGUAL.text("tips.restart.error")); AlertTips.error(this, TimiFXUI.MULTILINGUAL.text("tips.restart.error"));
} }

View File

@@ -8,8 +8,7 @@ import com.imyeyu.fx.ui.examples.component.animation.InterpolatorPane;
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem; import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.fx.utils.SmoothScroll; import com.imyeyu.fx.utils.SmoothScroll;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.InvokeForInjected;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
@@ -32,12 +31,11 @@ import javafx.util.StringConverter;
@Component @Component
public class InterpolatorDemo extends AbstractDemoPane { public class InterpolatorDemo extends AbstractDemoPane {
@Inject private final Config config;
private Config config;
private final Slider duration; private final Slider duration;
public InterpolatorDemo() { public InterpolatorDemo(Config config) {
this.config = config;
title.setText(SidebarItem.INTERPOLATOR.getText()); title.setText(SidebarItem.INTERPOLATOR.getText());
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/bean/Interpolators.html"); document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/bean/Interpolators.html");
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/bean/Interpolators.java"); source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/bean/Interpolators.java");
@@ -125,8 +123,8 @@ public class InterpolatorDemo extends AbstractDemoPane {
}); });
} }
@InvokeForInjected @PostConstruct
private void config() { private void init() {
duration.valueProperty().bindBidirectional(config.getInterpolator().getDuration()); duration.valueProperty().bindBidirectional(config.getInterpolator().getDuration());
} }
} }

View File

@@ -1,5 +1,6 @@
package com.imyeyu.fx.ui.examples.view.pages.animation; package com.imyeyu.fx.ui.examples.view.pages.animation;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.task.RunAsyncScheduled; import com.imyeyu.fx.task.RunAsyncScheduled;
import com.imyeyu.fx.ui.TimiFXUI; import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane; import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
@@ -21,6 +22,7 @@ import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.control.TextArea; import javafx.scene.control.TextArea;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;

View File

@@ -45,7 +45,7 @@ public class CheckBoxPickerDemo extends AbstractDemoPane {
}}); }});
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
picker.getItems().add(TimiFXUI.MULTILINGUAL.textArgs("fx.example.check_box_picker.item", i)); picker.getItems().add(TimiFXUI.MULTILINGUAL.text("fx.example.check_box_picker.item"));
} }
} }
} }

View File

@@ -10,8 +10,8 @@ import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem; import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
import com.imyeyu.fx.ui.examples.ctrl.Main; import com.imyeyu.fx.ui.examples.ctrl.Main;
import com.imyeyu.inject.annotation.Component; import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Inject; import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.InvokeForInjected; import javafx.stage.Stage;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.VPos; import javafx.geometry.VPos;
import javafx.scene.control.Button; import javafx.scene.control.Button;
@@ -30,18 +30,17 @@ import java.awt.TrayIcon;
* @author 夜雨 * @author 夜雨
* @since 2022-09-01 14:39 * @since 2022-09-01 14:39
*/ */
@Component
public class TrayFXDemo extends AbstractDemoPane { public class TrayFXDemo extends AbstractDemoPane {
@Inject private final Main main;
private Main main; private final Stage stage;
private final TrayFX trayFX;
@Inject
private TrayFX trayFX;
private final Button show, hide; private final Button show, hide;
public TrayFXDemo() { public TrayFXDemo(Main main, Stage stage, TrayFX trayFX) {
this.main = main;
this.stage = stage;
this.trayFX = trayFX;
title.setText(SidebarItem.TRAY.getText()); title.setText(SidebarItem.TRAY.getText());
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/util/TrayFX.html"); document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/util/TrayFX.html");
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/util/TrayFX.java"); source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/util/TrayFX.java");
@@ -103,7 +102,7 @@ public class TrayFXDemo extends AbstractDemoPane {
}); });
} }
@InvokeForInjected @PostConstruct
public void init() { public void init() {
show.disableProperty().bind(trayFX.showingProperty()); show.disableProperty().bind(trayFX.showingProperty());
hide.disableProperty().bind(trayFX.showingProperty().not()); hide.disableProperty().bind(trayFX.showingProperty().not());
@@ -111,7 +110,7 @@ public class TrayFXDemo extends AbstractDemoPane {
MenuItem show = new MenuItem(TimiFXUI.MULTILINGUAL.text("show")); MenuItem show = new MenuItem(TimiFXUI.MULTILINGUAL.text("show"));
MenuItem exit = new MenuItem(TimiFXUI.MULTILINGUAL.text("exit"), TimiFXIcon.fromName("FAIL", Colorful.RED)); MenuItem exit = new MenuItem(TimiFXUI.MULTILINGUAL.text("exit"), TimiFXIcon.fromName("FAIL", Colorful.RED));
show.setOnAction(e -> TimiFX.requestTop(main.getStage())); show.setOnAction(e -> TimiFX.requestTop(stage));
exit.setOnAction(e -> main.stop()); exit.setOnAction(e -> main.stop());
trayFX.addMenu(0, show, TimiFXUI.sep(), exit); trayFX.addMenu(0, show, TimiFXUI.sep(), exit);