Compare commits
10 Commits
40f556d0e1
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57e6b13292 | ||
|
|
b55a66d6df | ||
|
|
867c5f6602 | ||
|
|
0a5bb393cb | ||
|
|
dbb39b3d2f | ||
|
|
6eb36f4c59 | ||
|
|
9d605993c8 | ||
|
|
88f3e135ff | ||
|
|
6837781383 | ||
|
|
68f39aa834 |
111
.gitea/workflows/ci.yml
Normal file
111
.gitea/workflows/ci.yml
Normal 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
5
.gitignore
vendored
@@ -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
2
.idea/misc.xml
generated
@@ -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
147
pom.xml
@@ -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
33
src/assembly/examples.xml
Normal 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>
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.java.bean.CallbackArgReturn;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.geometry.Bounds;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Pos;
|
|
||||||
import javafx.scene.control.CheckBox;
|
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.layout.TilePane;
|
|
||||||
import javafx.stage.Popup;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 多选选择器,文本框弹出复选框组件进行多项选择
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2021-12-29 17:05
|
|
||||||
*/
|
|
||||||
public class CheckBoxPicker<T> extends TextField implements TimiFXUI {
|
|
||||||
|
|
||||||
private final ObservableList<T> items;
|
|
||||||
private final CheckBoxListPopup<T> checkBoxListPopup;
|
|
||||||
|
|
||||||
/** 默认构造器 */
|
|
||||||
public CheckBoxPicker() {
|
|
||||||
items = FXCollections.observableList(new ArrayList<>());
|
|
||||||
|
|
||||||
checkBoxListPopup = new CheckBoxListPopup<>(items);
|
|
||||||
|
|
||||||
setEditable(false);
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
setOnMouseClicked(e -> {
|
|
||||||
Bounds b = localToScreen(getLayoutBounds());
|
|
||||||
checkBoxListPopup.show(this, b.getMinX() - 5, b.getMaxY() - 6);
|
|
||||||
});
|
|
||||||
|
|
||||||
checkBoxListPopup.root.prefWidthProperty().bind(widthProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置复选框工厂,工厂入参数据对象,返回复选框组件
|
|
||||||
*
|
|
||||||
* @param factory 复选框工厂
|
|
||||||
*/
|
|
||||||
public void setCheckBoxFactory(CallbackArgReturn<T, CheckBox> factory) {
|
|
||||||
checkBoxListPopup.checkBoxFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取已选项
|
|
||||||
*
|
|
||||||
* @return 已选项
|
|
||||||
*/
|
|
||||||
public ObservableList<T> getSelectedItems() {
|
|
||||||
return checkBoxListPopup.selectedItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取数据列表
|
|
||||||
*
|
|
||||||
* @return 数据列表
|
|
||||||
*/
|
|
||||||
public ObservableList<T> getItems() {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 复选框列表弹窗
|
|
||||||
*
|
|
||||||
* @param <T> 数据类型
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2021-12-29 19:40
|
|
||||||
*/
|
|
||||||
private static class CheckBoxListPopup<T> extends Popup implements TimiFXUI {
|
|
||||||
|
|
||||||
private static final Insets PADDING = new Insets(6, 8, 6, 8);
|
|
||||||
|
|
||||||
private final TilePane root;
|
|
||||||
private final Map<T, CheckBox> cache; // 数据映射缓存
|
|
||||||
|
|
||||||
final ObservableList<T> selectedItems;
|
|
||||||
CallbackArgReturn<T, CheckBox> checkBoxFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认构造
|
|
||||||
*
|
|
||||||
* @param items 数据列表
|
|
||||||
*/
|
|
||||||
public CheckBoxListPopup(ObservableList<T> items) {
|
|
||||||
cache = new HashMap<>();
|
|
||||||
selectedItems = FXCollections.observableList(new ArrayList<>());
|
|
||||||
|
|
||||||
root = new TilePane();
|
|
||||||
root.setHgap(8);
|
|
||||||
root.setEffect(Shadow.POPUP);
|
|
||||||
root.setBorder(Stroke.DEFAULT);
|
|
||||||
root.setPadding(PADDING);
|
|
||||||
root.setMinWidth(300);
|
|
||||||
root.setBackground(BG.DEFAULT);
|
|
||||||
root.setTileAlignment(Pos.CENTER_LEFT);
|
|
||||||
|
|
||||||
setAutoHide(true);
|
|
||||||
getContent().add(root);
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
// 列表更新
|
|
||||||
items.addListener((ListChangeListener<T>) c -> {
|
|
||||||
if (c.next()) {
|
|
||||||
if (c.wasAdded()) {
|
|
||||||
// 添加
|
|
||||||
List<? extends T> list = c.getAddedSubList();
|
|
||||||
for (T t : list) {
|
|
||||||
CheckBox box;
|
|
||||||
if (checkBoxFactory != null) {
|
|
||||||
box = checkBoxFactory.handler(t);
|
|
||||||
} else {
|
|
||||||
box = new CheckBox(t.toString());
|
|
||||||
}
|
|
||||||
box.selectedProperty().addListener((obs, o, isSelected) -> {
|
|
||||||
if (isSelected) {
|
|
||||||
selectedItems.add(t);
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cache.put(t, box);
|
|
||||||
root.getChildren().add(box);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.wasRemoved()) {
|
|
||||||
// 移除
|
|
||||||
List<? extends T> list = c.getRemoved();
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
root.getChildren().remove(cache.get(list.get(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-05-26 14:32
|
* @since 2022-05-26 14:32
|
||||||
*/
|
*/
|
||||||
public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
|
public class FileTreeView extends TreeView<File> implements TimiFXUI.Colorful {
|
||||||
|
|
||||||
/** 正在查找节点监听 */
|
/** 正在查找节点监听 */
|
||||||
protected final BooleanBinding findingItem;
|
protected final BooleanBinding findingItem;
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ import java.util.regex.Pattern;
|
|||||||
* 超链标签
|
* 超链标签
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* new XHyperlink("个人博客", "<a href="https://www.imyeyu.net">https://www.imyeyu.net</a>");
|
* new Hyperlink("个人博客", "<a href="https://www.imyeyu.net">https://www.imyeyu.net</a>");
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-08-30 10:51
|
* @since 2022-08-30 10:51
|
||||||
*/
|
*/
|
||||||
public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
public class Hyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
||||||
|
|
||||||
private static final Pattern URL_PATTERN = Pattern.compile("https?://(www\\.)?[-a-zA-Z\\d@:%._+~#=]{1,256}\\.[a-zA-Z\\d()]{1,6}\\b([-a-zA-Z\\d()@:%_+.~#?&/=]*)");
|
private static final Pattern URL_PATTERN = Pattern.compile("https?://(www\\.)?[-a-zA-Z\\d@:%._+~#=]{1,256}\\.[a-zA-Z\\d()]{1,6}\\b([-a-zA-Z\\d()@:%_+.~#?&/=]*)");
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
protected final StringProperty url;
|
protected final StringProperty url;
|
||||||
|
|
||||||
/** 默认构造器 */
|
/** 默认构造器 */
|
||||||
public XHyperlink() {
|
public Hyperlink() {
|
||||||
this("", "");
|
this("", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
*
|
*
|
||||||
* @param url 链接
|
* @param url 链接
|
||||||
*/
|
*/
|
||||||
public XHyperlink(String url) {
|
public Hyperlink(String url) {
|
||||||
this(url, url);
|
this(url, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
* @param text 显示文本
|
* @param text 显示文本
|
||||||
* @param url 链接
|
* @param url 链接
|
||||||
*/
|
*/
|
||||||
public XHyperlink(String text, String url) {
|
public Hyperlink(String text, String url) {
|
||||||
this(null, text, url);
|
this(null, text, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
* @param text 显示文本
|
* @param text 显示文本
|
||||||
* @param url 链接
|
* @param url 链接
|
||||||
*/
|
*/
|
||||||
public XHyperlink(Node icon, String text, String url) {
|
public Hyperlink(Node icon, String text, String url) {
|
||||||
super(text);
|
super(text);
|
||||||
|
|
||||||
this.url = new SimpleStringProperty(url);
|
this.url = new SimpleStringProperty(url);
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
313
src/main/java/com/imyeyu/fx/ui/components/LabelTips.java
Normal file
313
src/main/java/com/imyeyu/fx/ui/components/LabelTips.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.control.TitledPane;
|
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
import javafx.scene.control.ToggleGroup;
|
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 纵向导航组件,可实现二级导航,折叠导航
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-02-17 00:11
|
|
||||||
*/
|
|
||||||
public class Navigation extends ScrollPane implements TimiFXUI {
|
|
||||||
|
|
||||||
/** 导航列表项 */
|
|
||||||
protected final ObservableList<ToggleButton> items;
|
|
||||||
|
|
||||||
/** 已选中监听 */
|
|
||||||
protected final ObjectProperty<ToggleButton> selectedItem;
|
|
||||||
|
|
||||||
/** 默认构造器 */
|
|
||||||
public Navigation() {
|
|
||||||
items = FXCollections.observableArrayList();
|
|
||||||
selectedItem = new SimpleObjectProperty<>();
|
|
||||||
|
|
||||||
VBox root = new VBox();
|
|
||||||
root.setBorder(Stroke.BOTTOM);
|
|
||||||
|
|
||||||
getStyleClass().addAll("navigation", "sp-border");
|
|
||||||
setMaxWidth(Double.MAX_VALUE);
|
|
||||||
setVbarPolicy(ScrollBarPolicy.NEVER);
|
|
||||||
setFitToWidth(true);
|
|
||||||
setContent(root);
|
|
||||||
|
|
||||||
SmoothScroll.scrollPaneV(this);
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
ToggleGroup group = new ToggleGroup();
|
|
||||||
|
|
||||||
// 主动选择(代码触发)
|
|
||||||
selectedItem.addListener((obs, o, newSelectedItem) -> group.selectToggle(newSelectedItem));
|
|
||||||
|
|
||||||
// 被动选择(操作触发)
|
|
||||||
group.selectedToggleProperty().addListener((obs, o, toggle) -> {
|
|
||||||
if (toggle instanceof ToggleButton btn) {
|
|
||||||
selectedItem.set(btn);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ObservableList<Node> childrens = root.getChildren();
|
|
||||||
|
|
||||||
// 响应 TimiFXUI
|
|
||||||
items.addListener((ListChangeListener<ToggleButton>) c -> {
|
|
||||||
while (c.next()) {
|
|
||||||
if (c.wasAdded()) {
|
|
||||||
// 添加
|
|
||||||
List<? extends ToggleButton> list = c.getAddedSubList();
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
list.get(i).setMaxWidth(Double.MAX_VALUE);
|
|
||||||
list.get(i).getStyleClass().setAll(CSS.MINECRAFT, "navigation-button");
|
|
||||||
list.get(i).addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN);
|
|
||||||
|
|
||||||
if (list.get(i).getProperties().get("OWNER") instanceof TitledPane pane) {
|
|
||||||
// 存在所属组
|
|
||||||
if (!childrens.contains(pane)) {
|
|
||||||
// 未添加组
|
|
||||||
childrens.add(pane);
|
|
||||||
}
|
|
||||||
if (pane.getContent() instanceof VBox box) {
|
|
||||||
box.getChildren().add(list.get(i));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 单独项
|
|
||||||
if (!childrens.isEmpty()) {
|
|
||||||
if (childrens.get(childrens.size() - 1) instanceof TitledPane) {
|
|
||||||
// 上一项是组导航,添加上边框
|
|
||||||
list.get(i).getStyleClass().add("after-group");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
childrens.add(list.get(i));
|
|
||||||
}
|
|
||||||
// 归组
|
|
||||||
group.getToggles().add(list.get(i));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.wasRemoved()) {
|
|
||||||
// 移除
|
|
||||||
List<? extends ToggleButton> list = c.getRemoved();
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
if (list.get(i).getProperties().get("OWNER") instanceof TitledPane pane) {
|
|
||||||
// 存在所属组
|
|
||||||
if (pane.getContent() instanceof VBox box) {
|
|
||||||
box.getChildren().remove(list.get(i));
|
|
||||||
if (box.getChildren().isEmpty()) {
|
|
||||||
// 该组已没有列表项
|
|
||||||
childrens.remove(box);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 单独项
|
|
||||||
childrens.remove(list.get(i));
|
|
||||||
}
|
|
||||||
// 从组移除
|
|
||||||
group.getToggles().remove(list.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加导航按钮
|
|
||||||
*
|
|
||||||
* @param buttons 导航按钮
|
|
||||||
*/
|
|
||||||
public void add(ToggleButton... buttons) {
|
|
||||||
getItems().addAll(buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加默认没有展开的导航组
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 构造的折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addGroup(String title, ToggleButton... buttons) {
|
|
||||||
return addGroup(title, false, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加默认展开的导航组
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 构造的折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addExpandedGroup(String title, ToggleButton... buttons) {
|
|
||||||
return addGroup(title, true, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加导航组
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @param isExpanded true 为默认展开
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 构造的折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addGroup(String title, boolean isExpanded, ToggleButton... buttons) {
|
|
||||||
TitledPane pane = new TitledPane();
|
|
||||||
pane.setText(title);
|
|
||||||
return addGroup(pane, isExpanded, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加导航组
|
|
||||||
*
|
|
||||||
* @param pane 所属组
|
|
||||||
* @param isExpanded true 为默认展开
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 原折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addGroup(TitledPane pane, boolean isExpanded, ToggleButton... buttons) {
|
|
||||||
VBox content = new VBox();
|
|
||||||
content.setPadding(Insets.EMPTY);
|
|
||||||
|
|
||||||
pane.setContent(content);
|
|
||||||
pane.setExpanded(isExpanded);
|
|
||||||
pane.getStyleClass().add("group-pane");
|
|
||||||
|
|
||||||
for (int i = 0; i < buttons.length; i++) {
|
|
||||||
buttons[i].getProperties().put("OWNER", pane);
|
|
||||||
items.add(buttons[i]);
|
|
||||||
}
|
|
||||||
return pane;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取该按钮所属组
|
|
||||||
*
|
|
||||||
* @param btn 按钮
|
|
||||||
* @return 所属组,null 时为不属于任何组
|
|
||||||
*/
|
|
||||||
public TitledPane getGroup(ToggleButton btn) {
|
|
||||||
if (btn.getProperties().get("OWNER") instanceof TitledPane pane) {
|
|
||||||
return pane;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置当前激活导航项
|
|
||||||
*
|
|
||||||
* @param button 导航项
|
|
||||||
*/
|
|
||||||
public void setSelectedItem(ToggleButton button) {
|
|
||||||
selectedItem.set(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前激活的导航项
|
|
||||||
*
|
|
||||||
* @return 当前激活的导航项
|
|
||||||
*/
|
|
||||||
public ToggleButton getSelectedItem() {
|
|
||||||
return selectedItem.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取激活导航项监听
|
|
||||||
*
|
|
||||||
* @return 激活导航项监听
|
|
||||||
*/
|
|
||||||
public ObjectProperty<ToggleButton> selectedItem() {
|
|
||||||
return selectedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取导航数据列表
|
|
||||||
*
|
|
||||||
* @return 导航数据列表
|
|
||||||
*/
|
|
||||||
public ObservableList<ToggleButton> getItems() {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* 分页组件,支持省略页,滚动页,如 [<][1]..[5][6][7][8][9]..[20][>]
|
* 分页组件,支持省略页,滚动页,如 [<][1]..[5][6][7][8][9]..[20][>]
|
||||||
* <pre>
|
* <pre>
|
||||||
* XPagination pagination = new XPagination();
|
* Pagination pagination = new Pagination();
|
||||||
* pagination.setSize(10); // 单页数据量
|
* pagination.setSize(10); // 单页数据量
|
||||||
* pagination.setLength(200); // 总数据量
|
* pagination.setLength(200); // 总数据量
|
||||||
* pagination.indexProperty((obs, o, newIndex) -> {
|
* pagination.indexProperty((obs, o, newIndex) -> {
|
||||||
@@ -36,7 +36,7 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2021-12-22 15:25
|
* @since 2021-12-22 15:25
|
||||||
*/
|
*/
|
||||||
public class XPagination extends HBox implements TimiFXUI {
|
public class Pagination extends HBox implements TimiFXUI {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "x-pagination";
|
private static final String STYLE_CLASS = "x-pagination";
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
private final IntegerProperty cp; // chunkProperty 页面数量 [1, N]
|
private final IntegerProperty cp; // chunkProperty 页面数量 [1, N]
|
||||||
|
|
||||||
/** 默认构造 */
|
/** 默认构造 */
|
||||||
public XPagination() {
|
public Pagination() {
|
||||||
// 基本参数
|
// 基本参数
|
||||||
lp = new SimpleLongProperty();
|
lp = new SimpleLongProperty();
|
||||||
ip = new SimpleIntegerProperty();
|
ip = new SimpleIntegerProperty();
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
// 选中更新激活下标
|
// 选中更新激活下标
|
||||||
selectedProperty().addListener((obs, o, isSelected) -> {
|
selectedProperty().addListener((obs, o, isSelected) -> {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
XPagination.this.ip.set(indexProperty.get());
|
Pagination.this.ip.set(indexProperty.get());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,16 @@ import com.imyeyu.fx.icon.TimiFXIcon;
|
|||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.java.bean.CallbackArg;
|
import com.imyeyu.java.bean.CallbackArg;
|
||||||
import com.imyeyu.java.ref.Ref;
|
import com.imyeyu.java.ref.Ref;
|
||||||
import javafx.animation.TranslateTransition;
|
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
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.scene.shape.Rectangle;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -24,26 +23,8 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-07-24 10:54
|
* @since 2022-07-24 10:54
|
||||||
*/
|
*/
|
||||||
public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
@Getter
|
||||||
|
public class TabPane extends javafx.scene.control.TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
||||||
/** 添加按钮 */
|
|
||||||
protected final IconButton add;
|
|
||||||
|
|
||||||
/** 默认构造 */
|
|
||||||
public XTabPane() {
|
|
||||||
add = new IconButton(TimiFXIcon.fromName("PLUS")).withBackground();
|
|
||||||
add.getStyleClass().add(CSS.BORDER_RB);
|
|
||||||
add.setPrefWidth(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取添加按钮
|
|
||||||
*
|
|
||||||
* @return 添加按钮
|
|
||||||
*/
|
|
||||||
public IconButton getAdd() {
|
|
||||||
return add;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Skin<?> createDefaultSkin() {
|
protected Skin<?> createDefaultSkin() {
|
||||||
@@ -52,24 +33,7 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
try {
|
try {
|
||||||
StackPane tabHeaderArea = Ref.getFieldValue(tabPaneSkin, "tabHeaderArea", StackPane.class);
|
StackPane tabHeaderArea = Ref.getFieldValue(tabPaneSkin, "tabHeaderArea", StackPane.class);
|
||||||
StackPane headersRegion = Ref.getFieldValue(tabHeaderArea, "headersRegion", StackPane.class);
|
StackPane headersRegion = Ref.getFieldValue(tabHeaderArea, "headersRegion", StackPane.class);
|
||||||
StackPane headersBackground = Ref.getFieldValue(tabHeaderArea, "headerBackground", StackPane.class);
|
Rectangle headerClip = Ref.getFieldValue(tabHeaderArea, "headerClip", Rectangle.class);
|
||||||
|
|
||||||
// 添加按钮
|
|
||||||
TranslateTransition transition = new TranslateTransition();
|
|
||||||
transition.setNode(add);
|
|
||||||
transition.setDuration(Duration.millis(150));
|
|
||||||
headersRegion.widthProperty().addListener((obs, oldWidth, newWidth) -> {
|
|
||||||
if (oldWidth.doubleValue() < newWidth.doubleValue()) {
|
|
||||||
transition.setFromX(add.getTranslateX());
|
|
||||||
transition.setToX(newWidth.intValue());
|
|
||||||
transition.play();
|
|
||||||
} else {
|
|
||||||
add.setTranslateX(newWidth.intValue());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add.prefHeightProperty().bind(headersBackground.heightProperty());
|
|
||||||
StackPane.setAlignment(add, Pos.CENTER_LEFT);
|
|
||||||
headersBackground.getChildren().add(add);
|
|
||||||
|
|
||||||
// 关闭按钮调整
|
// 关闭按钮调整
|
||||||
CallbackArg<Node> resizeCloseButton = tabHeaderSkin -> {
|
CallbackArg<Node> resizeCloseButton = tabHeaderSkin -> {
|
||||||
@@ -89,18 +53,18 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
closeBtn.getChildren().add(icon);
|
closeBtn.getChildren().add(icon);
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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()) {
|
||||||
List<? extends Node> list = c.getAddedSubList();
|
List<? extends Node> list = c.getAddedSubList();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (Node node : list) {
|
||||||
resizeCloseButton.handler(list.get(i));
|
resizeCloseButton.handler(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取编辑器标题
|
* 获取编辑器标题
|
||||||
*
|
*
|
||||||
@@ -151,7 +129,7 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
|
|||||||
* 编辑器弹窗
|
* 编辑器弹窗
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-07-26 16:54
|
* @since 2022-07-26 16:54
|
||||||
*/
|
*/
|
||||||
public static class EditorStage extends Stage {
|
public static class EditorStage extends Stage {
|
||||||
|
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
import javafx.scene.text.TextFlow;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本流组件,支持插入超链文本,解析富文本:{@link #matcher(String)}
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-09-05 10:41
|
|
||||||
*/
|
|
||||||
public class TextFlower extends TextFlow implements TimiFXUI {
|
|
||||||
|
|
||||||
/** 默认构造器 */
|
|
||||||
public TextFlower() {
|
|
||||||
getStyleClass().add(CSS.MINECRAFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本开始,添加一个制表符
|
|
||||||
*
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textStart() {
|
|
||||||
getChildren().add(new Text("\t"));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本,左侧补充一个制表符,通常是段落开始
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textStart(String text) {
|
|
||||||
getChildren().add(new Text("\t" + text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower text(String text) {
|
|
||||||
getChildren().add(new Text(text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本,左侧补充空格
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textLSP(String text) {
|
|
||||||
getChildren().add(new Text(" " + text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本,右侧补充空格
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textRSP(String text) {
|
|
||||||
getChildren().add(new Text(text + " "));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加链接文本
|
|
||||||
*
|
|
||||||
* @param text 显示文本
|
|
||||||
* @param link 访问链接
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower link(String text, String link) {
|
|
||||||
getChildren().add(new XHyperlink(text, link));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加链接文本
|
|
||||||
*
|
|
||||||
* @param icon 图标
|
|
||||||
* @param text 显示文本
|
|
||||||
* @param link 访问链接
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower link(Node icon, String text, String link) {
|
|
||||||
getChildren().add(new XHyperlink(icon, text, link));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加链接,显示文本为链接
|
|
||||||
*
|
|
||||||
* @param value 内容
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower syncLink(String value) {
|
|
||||||
getChildren().add(new XHyperlink(value, value));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置最后一个文本节点为链接
|
|
||||||
*
|
|
||||||
* @param link 链接
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower asLink(String link) {
|
|
||||||
Node text = getChildren().remove(getChildren().size() - 1);
|
|
||||||
if (text instanceof Text t) {
|
|
||||||
getChildren().add(new XHyperlink(t.getText(), link));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 富文本匹配解析字符串,转义使用 '\'
|
|
||||||
* <br>
|
|
||||||
* <p>格式标准:
|
|
||||||
* <ul>
|
|
||||||
* <li>超链:[可选文本,连接]</li>
|
|
||||||
* <li>图标:<可选颜色, timi-fx-icon 图标名称></li>
|
|
||||||
* <li>重点:`[可选样式,内容]`</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param value 字符串
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower matcher(String value) {
|
|
||||||
if (TimiJava.isNotEmpty(value)) {
|
|
||||||
getChildren().addAll(RichMatcher.parse(value));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 富文本匹配
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-10-10 11:23
|
|
||||||
*/
|
|
||||||
private static class RichMatcher {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 匹配正则
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-10-10 11:58
|
|
||||||
*/
|
|
||||||
private enum Regex {
|
|
||||||
|
|
||||||
LINK("\\[(.*?)]"),
|
|
||||||
|
|
||||||
ICON("<(.*?)>"),
|
|
||||||
|
|
||||||
SPAN("`(.*?)`");
|
|
||||||
|
|
||||||
final Pattern pattern;
|
|
||||||
|
|
||||||
Regex(String regex) {
|
|
||||||
this.pattern = Pattern.compile(regex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重点内容样式
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-10-10 11:58
|
|
||||||
*/
|
|
||||||
private enum Style {
|
|
||||||
|
|
||||||
UNDERLINE("u", "underline");
|
|
||||||
|
|
||||||
private final String[] matches;
|
|
||||||
|
|
||||||
Style(String... matches) {
|
|
||||||
this.matches = matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Style fromMatcher(String matcher) {
|
|
||||||
Style[] values = values();
|
|
||||||
for (int i = 0; i < values.length; i++) {
|
|
||||||
String[] matches = values[i].matches;
|
|
||||||
for (int j = 0; j < matches.length; j++) {
|
|
||||||
if (matches[j].equalsIgnoreCase(matcher)) {
|
|
||||||
return values[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析富文本匹配
|
|
||||||
*
|
|
||||||
* @param data 文本内容
|
|
||||||
* @return 匹配节点列表
|
|
||||||
*/
|
|
||||||
static List<Node> parse(String data) {
|
|
||||||
List<Node> result = new ArrayList<>();
|
|
||||||
|
|
||||||
Regex[] regexes = Regex.values();
|
|
||||||
|
|
||||||
Map<String, Node> nodeMap = new HashMap<>();
|
|
||||||
|
|
||||||
int[] insertI = {0};
|
|
||||||
String value = data;
|
|
||||||
Matcher matcher;
|
|
||||||
for (int i = 0; i < regexes.length; i++) {
|
|
||||||
final int j = i;
|
|
||||||
matcher = regexes[i].pattern.matcher(value);
|
|
||||||
|
|
||||||
value = matcher.replaceAll(matchResult -> {
|
|
||||||
if (matchResult.start() - 1 != -1) {
|
|
||||||
if (data.charAt(matchResult.start() - 1) == '\\') {
|
|
||||||
return matchResult.group();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodeMap.put(String.valueOf(insertI[0]), node(regexes[j], value(regexes[j], matchResult.group())));
|
|
||||||
return "[" + insertI[0]++ + "]";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 二次解析
|
|
||||||
matcher = Pattern.compile("\\[(.*?)]").matcher(value);
|
|
||||||
int end = 0;
|
|
||||||
while (matcher.find()) {
|
|
||||||
if (matcher.start() - 1 != -1) {
|
|
||||||
if (data.charAt(matcher.start() - 1) == '\\') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (end != matcher.start()) {
|
|
||||||
result.add(new Text(value.substring(end, matcher.start())));
|
|
||||||
}
|
|
||||||
result.add(nodeMap.get(value(Regex.LINK, matcher.group())));
|
|
||||||
end = matcher.end();
|
|
||||||
}
|
|
||||||
result.add(new Text(value.substring(end)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析正则匹配值
|
|
||||||
*
|
|
||||||
* @param regex 匹配正则
|
|
||||||
* @param matcherResult 匹配结果
|
|
||||||
* @return 匹配值
|
|
||||||
*/
|
|
||||||
private static String value(Regex regex, String matcherResult) {
|
|
||||||
return switch (regex) {
|
|
||||||
case LINK, ICON, SPAN -> matcherResult.substring(1, matcherResult.length() - 1);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析节点
|
|
||||||
*
|
|
||||||
* @param regex 匹配正则
|
|
||||||
* @param value 匹配值
|
|
||||||
* @return 节点
|
|
||||||
*/
|
|
||||||
private static Node node(Regex regex, String value) {
|
|
||||||
return switch (regex) {
|
|
||||||
// 超链
|
|
||||||
case LINK -> {
|
|
||||||
int sp = value.indexOf(",");
|
|
||||||
if (sp == -1) {
|
|
||||||
yield new XHyperlink(value.trim());
|
|
||||||
} else {
|
|
||||||
while (value.charAt(sp - 1) == '\\') {
|
|
||||||
sp = value.indexOf(",", sp + 1);
|
|
||||||
}
|
|
||||||
yield new XHyperlink(value.substring(0, sp).trim(), value.substring(sp + 1).trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 图标
|
|
||||||
case ICON -> {
|
|
||||||
Text icon;
|
|
||||||
int sp = value.lastIndexOf(",");
|
|
||||||
if (sp == -1) {
|
|
||||||
icon = TimiFXIcon.fromName(value);
|
|
||||||
} else {
|
|
||||||
icon = TimiFXIcon.fromName(value.substring(sp + 1).trim());
|
|
||||||
icon.setFill(Paint.valueOf(value.substring(0, sp).trim()));
|
|
||||||
}
|
|
||||||
yield icon;
|
|
||||||
}
|
|
||||||
// 重点内容
|
|
||||||
case SPAN -> {
|
|
||||||
int sp = value.indexOf(",");
|
|
||||||
if (sp == -1) {
|
|
||||||
yield new Text(value);
|
|
||||||
} else {
|
|
||||||
Text text = new Text(value.substring(sp + 1).trim());
|
|
||||||
String[] styles = value.substring(0, sp).trim().split(" ");
|
|
||||||
for (int i = 0; i < styles.length; i++) {
|
|
||||||
Style style = Style.fromMatcher(styles[i]);
|
|
||||||
if (style == null) {
|
|
||||||
text.setFill(Paint.valueOf(styles[i]));
|
|
||||||
} else {
|
|
||||||
if (style == Style.UNDERLINE) {
|
|
||||||
text.setUnderline(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yield text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.components;
|
|||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.SmoothScroll;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import javafx.scene.control.TreeView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不显示根节点的树形结构,实现多个根节点
|
* 不显示根节点的树形结构,实现多个根节点
|
||||||
@@ -11,12 +10,12 @@ import javafx.scene.control.TreeView;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2021-04-26 01:34
|
* @since 2021-04-26 01:34
|
||||||
*/
|
*/
|
||||||
public class XTreeView<T> extends TreeView<T> {
|
public class TreeView<T> extends javafx.scene.control.TreeView<T> {
|
||||||
|
|
||||||
private final TreeItem<T> dummyRoot = new TreeItem<>();
|
private final TreeItem<T> dummyRoot = new TreeItem<>();
|
||||||
|
|
||||||
/** 默认构造 */
|
/** 默认构造 */
|
||||||
public XTreeView() {
|
public TreeView() {
|
||||||
dummyRoot.setExpanded(true);
|
dummyRoot.setExpanded(true);
|
||||||
setRoot(dummyRoot);
|
setRoot(dummyRoot);
|
||||||
setShowRoot(false);
|
setShowRoot(false);
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,13 +12,15 @@ 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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按钮通用动作,用于标记,具体事件由调用决定
|
* 按钮通用动作,用于标记,具体事件由调用决定
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-01-20 00:55
|
* @since 2022-01-20 00:55
|
||||||
*/
|
*/
|
||||||
public enum Action {
|
public enum Action {
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 快速构造应用按钮
|
* 快速构造应用按钮
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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 -> {
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置反馈错误事件,全局事件,设置一次即可
|
* 设置反馈错误事件,全局事件,设置一次即可
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- 快速构造 ----------
|
// ---------- 快速构造 ----------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,570 @@
|
|||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.TimiFX;
|
||||||
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.utils.SmoothScroll;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.control.TitledPane;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纵向导航组件,可实现多级折叠导航
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-16
|
||||||
|
*/
|
||||||
|
public class Navigation extends ScrollPane implements TimiFXUI {
|
||||||
|
|
||||||
|
/** 默认缩进像素 */
|
||||||
|
static final double DEFAULT_INDENT_SIZE = 16;
|
||||||
|
|
||||||
|
/** 导航项原始标题属性 */
|
||||||
|
private static final String RAW_ITEM_TEXT = "RAW_ITEM_TEXT";
|
||||||
|
|
||||||
|
/** 导航项原始图标属性 */
|
||||||
|
private static final String RAW_ITEM_GRAPHIC = "RAW_ITEM_GRAPHIC";
|
||||||
|
|
||||||
|
/** 导航项图标同步锁属性 */
|
||||||
|
private static final String GRAPHIC_SYNCING = "GRAPHIC_SYNCING";
|
||||||
|
|
||||||
|
/** 导航项是否已初始化 */
|
||||||
|
private static final String INITIALIZED = "INITIALIZED";
|
||||||
|
|
||||||
|
/** 导航数据列表 */
|
||||||
|
@Getter
|
||||||
|
protected final ObservableList<Node> items;
|
||||||
|
|
||||||
|
/** 已选中监听 */
|
||||||
|
protected final ObjectProperty<ToggleButton> selectedItem;
|
||||||
|
|
||||||
|
/** 缩进像素 */
|
||||||
|
private final DoubleProperty indentSize;
|
||||||
|
|
||||||
|
/** 根容器 */
|
||||||
|
private final VBox contentBox;
|
||||||
|
|
||||||
|
/** 选择组 */
|
||||||
|
private final ToggleGroup toggleGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public Navigation() {
|
||||||
|
items = FXCollections.observableArrayList();
|
||||||
|
selectedItem = new SimpleObjectProperty<>();
|
||||||
|
indentSize = new SimpleDoubleProperty(DEFAULT_INDENT_SIZE);
|
||||||
|
contentBox = new VBox();
|
||||||
|
toggleGroup = new ToggleGroup();
|
||||||
|
|
||||||
|
initView();
|
||||||
|
initSelection();
|
||||||
|
initPropertyListener();
|
||||||
|
initItemsListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化视图
|
||||||
|
*/
|
||||||
|
private void initView() {
|
||||||
|
contentBox.setBorder(Stroke.BOTTOM);
|
||||||
|
|
||||||
|
getStyleClass().addAll("navigation", "sp-border");
|
||||||
|
setMaxWidth(Double.MAX_VALUE);
|
||||||
|
setVbarPolicy(ScrollBarPolicy.NEVER);
|
||||||
|
setFitToWidth(true);
|
||||||
|
setContent(contentBox);
|
||||||
|
|
||||||
|
SmoothScroll.scrollPaneV(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化选中同步
|
||||||
|
*/
|
||||||
|
private void initSelection() {
|
||||||
|
selectedItem.addListener((obs, o, newSelectedItem) -> {
|
||||||
|
if (newSelectedItem == null) {
|
||||||
|
toggleGroup.selectToggle(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (toggleGroup.getToggles().contains(newSelectedItem)) {
|
||||||
|
toggleGroup.selectToggle(newSelectedItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggleGroup.selectedToggleProperty().addListener((obs, o, toggle) -> {
|
||||||
|
if (toggle instanceof ToggleButton button) {
|
||||||
|
selectedItem.set(button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedItem.set(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化属性监听
|
||||||
|
*/
|
||||||
|
private void initPropertyListener() {
|
||||||
|
indentSize.addListener((obs, o, n) -> rebuild());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化导航数据监听
|
||||||
|
*/
|
||||||
|
private void initItemsListener() {
|
||||||
|
items.addListener(this::handleItemsChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理导航数据变更
|
||||||
|
*
|
||||||
|
* @param change 变更内容
|
||||||
|
*/
|
||||||
|
private void handleItemsChanged(ListChangeListener.Change<? extends Node> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasAdded()) {
|
||||||
|
for (Node node : change.getAddedSubList()) {
|
||||||
|
bindGroup(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (change.wasRemoved()) {
|
||||||
|
for (Node node : change.getRemoved()) {
|
||||||
|
unbindGroup(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定导航组刷新回调
|
||||||
|
*
|
||||||
|
* @param node 子节点
|
||||||
|
*/
|
||||||
|
private void bindGroup(Node node) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(this::rebuild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑导航组刷新回调
|
||||||
|
*
|
||||||
|
* @param node 子节点
|
||||||
|
*/
|
||||||
|
private void unbindGroup(Node node) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建导航结构
|
||||||
|
*/
|
||||||
|
private void rebuild() {
|
||||||
|
contentBox.getChildren().clear();
|
||||||
|
toggleGroup.getToggles().clear();
|
||||||
|
|
||||||
|
for (Node node : items) {
|
||||||
|
Node attachedNode = buildNode(node, 0);
|
||||||
|
if (attachedNode != null) {
|
||||||
|
contentBox.getChildren().add(attachedNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshStandaloneItemStyle();
|
||||||
|
if (selectedItem.get() != null && !toggleGroup.getToggles().contains(selectedItem.get())) {
|
||||||
|
selectedItem.set(null);
|
||||||
|
}
|
||||||
|
if (selectedItem.get() != null) {
|
||||||
|
toggleGroup.selectToggle(selectedItem.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建节点
|
||||||
|
*
|
||||||
|
* @param node 节点
|
||||||
|
* @param level 层级
|
||||||
|
* @return 可挂载节点
|
||||||
|
*/
|
||||||
|
private Node buildNode(Node node, int level) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
return buildGroup(group, level);
|
||||||
|
}
|
||||||
|
if (node instanceof ToggleButton button) {
|
||||||
|
return buildItem(button, level);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @param level 层级
|
||||||
|
* @return 导航组节点
|
||||||
|
*/
|
||||||
|
private NavigationGroup buildGroup(NavigationGroup group, int level) {
|
||||||
|
int currentLevel = level + group.getLevelOffset();
|
||||||
|
group.applyLevel(currentLevel, getIndentSize());
|
||||||
|
if (!group.getStyleClass().contains("group-pane")) {
|
||||||
|
group.getStyleClass().add("group-pane");
|
||||||
|
}
|
||||||
|
|
||||||
|
VBox groupContent = group.getContentBox();
|
||||||
|
groupContent.getChildren().clear();
|
||||||
|
for (Node child : group.getItems()) {
|
||||||
|
Node childNode = buildNode(child, currentLevel + 1);
|
||||||
|
if (childNode != null) {
|
||||||
|
groupContent.getChildren().add(childNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建导航项
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @param level 层级
|
||||||
|
* @return 导航项节点
|
||||||
|
*/
|
||||||
|
private ToggleButton buildItem(ToggleButton button, int level) {
|
||||||
|
configureButton(button, level);
|
||||||
|
toggleGroup.getToggles().add(button);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新独立导航项样式
|
||||||
|
*/
|
||||||
|
private void refreshStandaloneItemStyle() {
|
||||||
|
List<Node> children = contentBox.getChildren();
|
||||||
|
for (int i = 0; i < children.size(); i++) {
|
||||||
|
Node node = children.get(i);
|
||||||
|
if (node instanceof ToggleButton button) {
|
||||||
|
button.getStyleClass().remove("after-group");
|
||||||
|
if (0 < i && children.get(i - 1) instanceof TitledPane) {
|
||||||
|
button.getStyleClass().add("after-group");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置导航项
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @param level 层级
|
||||||
|
*/
|
||||||
|
private void configureButton(ToggleButton button, int level) {
|
||||||
|
cacheItemState(button);
|
||||||
|
button.setText(resolveItemText(button));
|
||||||
|
button.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
button.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
applyButtonIndent(button, Math.max(0, level) * getIndentSize());
|
||||||
|
button.getStyleClass().setAll(CSS.MINECRAFT, "navigation-button");
|
||||||
|
|
||||||
|
if (!Boolean.TRUE.equals(button.getProperties().get(INITIALIZED))) {
|
||||||
|
button.addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN);
|
||||||
|
button.graphicProperty().addListener((obs, o, n) -> {
|
||||||
|
if (!Boolean.TRUE.equals(button.getProperties().get(GRAPHIC_SYNCING))) {
|
||||||
|
button.getProperties().put(RAW_ITEM_GRAPHIC, n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
button.getProperties().put(INITIALIZED, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存导航项原始状态
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
*/
|
||||||
|
private void cacheItemState(ToggleButton button) {
|
||||||
|
if (!(button.getProperties().get(RAW_ITEM_TEXT) instanceof String)) {
|
||||||
|
button.getProperties().put(RAW_ITEM_TEXT, button.getText());
|
||||||
|
}
|
||||||
|
if (!button.getProperties().containsKey(RAW_ITEM_GRAPHIC)) {
|
||||||
|
button.getProperties().put(RAW_ITEM_GRAPHIC, button.getGraphic());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导航项原始标题
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @return 原始标题
|
||||||
|
*/
|
||||||
|
private String resolveItemText(ToggleButton button) {
|
||||||
|
cacheItemState(button);
|
||||||
|
return (String) button.getProperties().get(RAW_ITEM_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用导航项缩进
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @param indentWidth 缩进宽度
|
||||||
|
*/
|
||||||
|
private void applyButtonIndent(ToggleButton button, double indentWidth) {
|
||||||
|
Node rawGraphic = (Node) button.getProperties().get(RAW_ITEM_GRAPHIC);
|
||||||
|
if (0 == indentWidth) {
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, true);
|
||||||
|
button.setGraphic(rawGraphic);
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region spacer = new Region();
|
||||||
|
spacer.setMinWidth(indentWidth);
|
||||||
|
spacer.setPrefWidth(indentWidth);
|
||||||
|
spacer.setMaxWidth(indentWidth);
|
||||||
|
|
||||||
|
HBox graphicBox = new HBox();
|
||||||
|
graphicBox.getChildren().add(spacer);
|
||||||
|
if (rawGraphic != null) {
|
||||||
|
graphicBox.getChildren().add(rawGraphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, true);
|
||||||
|
button.setGraphic(graphicBox);
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航按钮
|
||||||
|
*
|
||||||
|
* @param buttons 导航按钮
|
||||||
|
*/
|
||||||
|
public void add(ToggleButton... buttons) {
|
||||||
|
getItems().addAll(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param groups 导航组
|
||||||
|
*/
|
||||||
|
public void add(NavigationGroup... groups) {
|
||||||
|
getItems().addAll(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航节点
|
||||||
|
*
|
||||||
|
* @param nodes 导航节点
|
||||||
|
*/
|
||||||
|
public void add(Node... nodes) {
|
||||||
|
getItems().addAll(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认没有展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(String title, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, 0, false, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addExpandedGroup(String title, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, 0, true, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认没有展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(String title, int level, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, level, false, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addExpandedGroup(String title, int level, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, level, true, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param isExpanded true 为默认展开
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(String title, int level, boolean isExpanded, ToggleButton... buttons) {
|
||||||
|
NavigationGroup group = new NavigationGroup(title).levelOffset(level).expanded(isExpanded);
|
||||||
|
group.add(buttons);
|
||||||
|
add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @return 原导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(NavigationGroup group) {
|
||||||
|
add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @param isExpanded true 为默认展开
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 原导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(NavigationGroup group, boolean isExpanded, ToggleButton... buttons) {
|
||||||
|
return addGroup(group, group.getLevelOffset(), isExpanded, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param isExpanded true 为默认展开
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 原导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(NavigationGroup group, int level, boolean isExpanded, ToggleButton... buttons) {
|
||||||
|
group.levelOffset(level).expanded(isExpanded).add(buttons);
|
||||||
|
add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该按钮所属组
|
||||||
|
*
|
||||||
|
* @param button 按钮
|
||||||
|
* @return 所属组,null 时为不属于任何组
|
||||||
|
*/
|
||||||
|
public NavigationGroup getGroup(ToggleButton button) {
|
||||||
|
for (Node node : items) {
|
||||||
|
NavigationGroup group = findGroup(node, button);
|
||||||
|
if (group != null) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前激活导航项
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
*/
|
||||||
|
public void setSelectedItem(ToggleButton button) {
|
||||||
|
selectedItem.set(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前激活的导航项
|
||||||
|
*
|
||||||
|
* @return 当前激活的导航项
|
||||||
|
*/
|
||||||
|
public ToggleButton getSelectedItem() {
|
||||||
|
return selectedItem.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取激活导航项监听
|
||||||
|
*
|
||||||
|
* @return 激活导航项监听
|
||||||
|
*/
|
||||||
|
public ObjectProperty<ToggleButton> selectedItem() {
|
||||||
|
return selectedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缩进像素
|
||||||
|
*
|
||||||
|
* @param indentSize 缩进像素
|
||||||
|
*/
|
||||||
|
public void setIndentSize(double indentSize) {
|
||||||
|
this.indentSize.set(Math.max(0, indentSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缩进像素
|
||||||
|
*
|
||||||
|
* @return 缩进像素
|
||||||
|
*/
|
||||||
|
public double getIndentSize() {
|
||||||
|
return indentSize.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缩进像素属性
|
||||||
|
*
|
||||||
|
* @return 缩进像素属性
|
||||||
|
*/
|
||||||
|
public DoubleProperty indentSize() {
|
||||||
|
return indentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找按钮所属导航组
|
||||||
|
*
|
||||||
|
* @param node 当前节点
|
||||||
|
* @param button 目标按钮
|
||||||
|
* @return 所属导航组
|
||||||
|
*/
|
||||||
|
private NavigationGroup findGroup(Node node, ToggleButton button) {
|
||||||
|
if (!(node instanceof NavigationGroup group)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Node child : group.getItems()) {
|
||||||
|
if (child == button) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
NavigationGroup nestedGroup = findGroup(child, button);
|
||||||
|
if (nestedGroup != null) {
|
||||||
|
return nestedGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.TitledPane;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航组
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-16
|
||||||
|
*/
|
||||||
|
public class NavigationGroup extends TitledPane {
|
||||||
|
|
||||||
|
/** 子节点列表 */
|
||||||
|
@Getter
|
||||||
|
private final ObservableList<Node> items;
|
||||||
|
|
||||||
|
/** 内容容器 */
|
||||||
|
private final VBox contentBox;
|
||||||
|
|
||||||
|
/** 结构变更回调 */
|
||||||
|
private Runnable structureChangedAction;
|
||||||
|
|
||||||
|
/** 原始标题 */
|
||||||
|
private String rawTitle;
|
||||||
|
|
||||||
|
/** 原始图标 */
|
||||||
|
private Node rawGraphic;
|
||||||
|
|
||||||
|
/** 标题同步锁 */
|
||||||
|
private boolean textSyncing;
|
||||||
|
|
||||||
|
/** 图标同步锁 */
|
||||||
|
private boolean graphicSyncing;
|
||||||
|
|
||||||
|
/** 标题缩进偏移量 */
|
||||||
|
private int levelOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public NavigationGroup() {
|
||||||
|
items = FXCollections.observableArrayList();
|
||||||
|
contentBox = new VBox();
|
||||||
|
structureChangedAction = () -> {};
|
||||||
|
rawTitle = "";
|
||||||
|
|
||||||
|
contentBox.setPadding(Insets.EMPTY);
|
||||||
|
setContent(contentBox);
|
||||||
|
getStyleClass().add("group-pane");
|
||||||
|
items.addListener(this::handleItemsChanged);
|
||||||
|
initRawStateListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过标题创建导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
*/
|
||||||
|
public NavigationGroup(String title) {
|
||||||
|
this();
|
||||||
|
setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航项
|
||||||
|
*
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup add(ToggleButton... buttons) {
|
||||||
|
items.addAll(buttons);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param groups 导航组
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup add(NavigationGroup... groups) {
|
||||||
|
items.addAll(groups);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加子节点
|
||||||
|
*
|
||||||
|
* @param nodes 子节点
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup add(Node... nodes) {
|
||||||
|
items.addAll(nodes);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否默认展开
|
||||||
|
*
|
||||||
|
* @param expanded true 为默认展开
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup expanded(boolean expanded) {
|
||||||
|
setExpanded(expanded);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置标题缩进偏移量
|
||||||
|
*
|
||||||
|
* @param levelOffset 偏移量
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup levelOffset(int levelOffset) {
|
||||||
|
this.levelOffset = Math.max(0, levelOffset);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取内容容器
|
||||||
|
*
|
||||||
|
* @return 内容容器
|
||||||
|
*/
|
||||||
|
VBox getContentBox() {
|
||||||
|
return contentBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取标题缩进偏移量
|
||||||
|
*
|
||||||
|
* @return 标题缩进偏移量
|
||||||
|
*/
|
||||||
|
int getLevelOffset() {
|
||||||
|
return levelOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置结构变更回调
|
||||||
|
*
|
||||||
|
* @param structureChangedAction 回调
|
||||||
|
*/
|
||||||
|
void setStructureChangedAction(Runnable structureChangedAction) {
|
||||||
|
this.structureChangedAction = structureChangedAction == null ? () -> {} : structureChangedAction;
|
||||||
|
for (Node node : items) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(this::notifyStructureChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用显示层级
|
||||||
|
*
|
||||||
|
* @param level 层级
|
||||||
|
* @param indentSize 缩进像素
|
||||||
|
*/
|
||||||
|
void applyLevel(int level, double indentSize) {
|
||||||
|
textSyncing = true;
|
||||||
|
super.setText(rawTitle);
|
||||||
|
textSyncing = false;
|
||||||
|
applyGraphicIndent(Math.max(0, level) * indentSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理子节点变更
|
||||||
|
*
|
||||||
|
* @param change 变更内容
|
||||||
|
*/
|
||||||
|
private void handleItemsChanged(ListChangeListener.Change<? extends Node> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasAdded()) {
|
||||||
|
for (Node node : change.getAddedSubList()) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(this::notifyStructureChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (change.wasRemoved()) {
|
||||||
|
for (Node node : change.getRemoved()) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyStructureChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发结构变更通知
|
||||||
|
*/
|
||||||
|
private void notifyStructureChanged() {
|
||||||
|
structureChangedAction.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化原始状态监听
|
||||||
|
*/
|
||||||
|
private void initRawStateListener() {
|
||||||
|
rawTitle = getText() == null ? "" : getText();
|
||||||
|
rawGraphic = getGraphic();
|
||||||
|
|
||||||
|
textProperty().addListener((obs, o, n) -> {
|
||||||
|
if (!textSyncing) {
|
||||||
|
rawTitle = n == null ? "" : n;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
graphicProperty().addListener((obs, o, n) -> {
|
||||||
|
if (!graphicSyncing) {
|
||||||
|
rawGraphic = n;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用标题缩进
|
||||||
|
*
|
||||||
|
* @param indentWidth 缩进宽度
|
||||||
|
*/
|
||||||
|
private void applyGraphicIndent(double indentWidth) {
|
||||||
|
if (0 == indentWidth) {
|
||||||
|
graphicSyncing = true;
|
||||||
|
super.setGraphic(rawGraphic);
|
||||||
|
graphicSyncing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region spacer = new Region();
|
||||||
|
spacer.setMinWidth(indentWidth);
|
||||||
|
spacer.setPrefWidth(indentWidth);
|
||||||
|
spacer.setMaxWidth(indentWidth);
|
||||||
|
|
||||||
|
HBox graphicBox = new HBox();
|
||||||
|
graphicBox.getChildren().add(spacer);
|
||||||
|
if (rawGraphic != null) {
|
||||||
|
graphicBox.getChildren().add(rawGraphic);
|
||||||
|
}
|
||||||
|
graphicSyncing = true;
|
||||||
|
super.setGraphic(graphicBox);
|
||||||
|
graphicSyncing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
|
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航项
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-16
|
||||||
|
*/
|
||||||
|
public class NavigationItem extends ToggleButton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public NavigationItem() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过标题创建导航项
|
||||||
|
*
|
||||||
|
* @param text 标题
|
||||||
|
*/
|
||||||
|
public NavigationItem(String text) {
|
||||||
|
super(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/** 导航组件 */
|
||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
@@ -630,6 +630,24 @@
|
|||||||
.tab-pane > .tab-header-area > .headers-region > .tab > .tab-container > .tab-label {
|
.tab-pane > .tab-header-area > .headers-region > .tab > .tab-container > .tab-label {
|
||||||
-fx-padding: 0 .5em 0 0;
|
-fx-padding: 0 .5em 0 0;
|
||||||
}
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab > .container {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab > .container > .tab-down-button {
|
||||||
|
-fx-padding: 0 .5em;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab > .container > .tab-down-button > .arrow {
|
||||||
|
-fx-shape: "M301.5,393.5v1h1v1h1v1h1v1h1v1h1v-1h1v-1h1v-1h1v-1h1v-1Z";
|
||||||
|
-fx-min-width: 9;
|
||||||
|
-fx-min-height: 5;
|
||||||
|
-fx-pref-width: 9;
|
||||||
|
-fx-pref-height: 5;
|
||||||
|
}
|
||||||
.tab-pane:top > .tab-header-area {
|
.tab-pane:top > .tab-header-area {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
@@ -813,4 +831,4 @@
|
|||||||
}
|
}
|
||||||
.border-lr {
|
.border-lr {
|
||||||
-fx-border-width: 0 1 0 1;
|
-fx-border-width: 0 1 0 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
{
|
BindingsConfig.addAllFXConverter(configLoader);
|
||||||
configLoader = new ConfigLoader<>("TimiFXExamples.yaml", Config.class);
|
config = configLoader.load();
|
||||||
for (Map.Entry<Class<?>, BindingsConfig.PropertyConverter<?, ?>> item : BindingsConfig.DEFAULT_CONVERTER_MAP.entrySet()) {
|
|
||||||
configLoader.addConverter(item.getKey(), item.getValue());
|
|
||||||
}
|
|
||||||
configLoader.addConverter(ObjectProperty.class, BindingsConfig.OBJECT);
|
|
||||||
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);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("fatal error", e);
|
|
||||||
}
|
}
|
||||||
|
Application.launch(Main.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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.components.XHyperlink;
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
@@ -22,10 +22,10 @@ public abstract class AbstractDemoPane extends AbstractPane {
|
|||||||
protected Label tips;
|
protected Label tips;
|
||||||
|
|
||||||
/** 文档 */
|
/** 文档 */
|
||||||
protected XHyperlink document;
|
protected Hyperlink document;
|
||||||
|
|
||||||
/** 源码 */
|
/** 源码 */
|
||||||
protected XHyperlink source;
|
protected Hyperlink source;
|
||||||
|
|
||||||
public AbstractDemoPane() {
|
public AbstractDemoPane() {
|
||||||
// 标题
|
// 标题
|
||||||
@@ -37,11 +37,11 @@ public abstract class AbstractDemoPane extends AbstractPane {
|
|||||||
|
|
||||||
// 文档
|
// 文档
|
||||||
Label labelDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
Label labelDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
||||||
document = new XHyperlink();
|
document = new Hyperlink();
|
||||||
|
|
||||||
// 源码
|
// 源码
|
||||||
Label labelSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
Label labelSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
||||||
source = new XHyperlink();
|
source = new Hyperlink();
|
||||||
|
|
||||||
// 提示
|
// 提示
|
||||||
tips = TimiFXUI.label();
|
tips = TimiFXUI.label();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package com.imyeyu.fx.ui.examples.component.sidebar;
|
package com.imyeyu.fx.ui.examples.component.sidebar;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.Navigation;
|
import com.imyeyu.fx.ui.components.navigation.Navigation;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationGroup;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationItem;
|
||||||
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 java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导航
|
* 导航
|
||||||
@@ -16,10 +19,11 @@ import javafx.scene.control.ToggleButton;
|
|||||||
@Component
|
@Component
|
||||||
public class Sidebar extends Navigation {
|
public class Sidebar extends Navigation {
|
||||||
|
|
||||||
@Inject
|
/** 侧边栏项目映射 */
|
||||||
private PageService pageService;
|
private final Map<SidebarItem, Item> itemMap = new EnumMap<>(SidebarItem.class);
|
||||||
|
|
||||||
|
public Sidebar(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);
|
||||||
@@ -34,41 +38,22 @@ public class Sidebar extends Navigation {
|
|||||||
// 动画
|
// 动画
|
||||||
Item interpolator = new Item(SidebarItem.INTERPOLATOR);
|
Item interpolator = new Item(SidebarItem.INTERPOLATOR);
|
||||||
Item smoothScroll = new Item(SidebarItem.SMOOTH_SCROLL);
|
Item smoothScroll = new Item(SidebarItem.SMOOTH_SCROLL);
|
||||||
addGroup(TimiFXUI.MULTILINGUAL.text("animation"), interpolator, smoothScroll);
|
add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("animation")).add(interpolator, smoothScroll));
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
SidebarItem[] components = {
|
SidebarItem[] components = {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]);
|
||||||
}
|
}
|
||||||
addGroup(TimiFXUI.MULTILINGUAL.text("component"), componentItems);
|
add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("component")).add(componentItems));
|
||||||
|
|
||||||
// 其他
|
// 其他
|
||||||
Item draggableNode = new Item(SidebarItem.DRAGGABLE_NODE);
|
Item draggableNode = new Item(SidebarItem.DRAGGABLE_NODE);
|
||||||
Item draggableWindow = new Item(SidebarItem.DRAGGABLE_WINDOW);
|
Item draggableWindow = new Item(SidebarItem.DRAGGABLE_WINDOW);
|
||||||
Item screen = new Item(SidebarItem.SCREEN);
|
Item screen = new Item(SidebarItem.SCREEN);
|
||||||
Item tray = new Item(SidebarItem.TRAY);
|
Item tray = new Item(SidebarItem.TRAY);
|
||||||
addGroup(TimiFXUI.MULTILINGUAL.text("other"), draggableNode, draggableWindow, screen, tray);
|
add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("other")).add(draggableNode, draggableWindow, screen, tray));
|
||||||
|
|
||||||
getStyleClass().add(CSS.BORDER_R);
|
getStyleClass().add(CSS.BORDER_R);
|
||||||
setMinWidth(140);
|
setMinWidth(140);
|
||||||
|
|
||||||
@@ -88,29 +73,34 @@ public class Sidebar extends Navigation {
|
|||||||
* @param item 选中项
|
* @param item 选中项
|
||||||
*/
|
*/
|
||||||
public void setSelected(SidebarItem item) {
|
public void setSelected(SidebarItem item) {
|
||||||
for (int i = 0; i < items.size(); i++) {
|
Item selected = itemMap.get(item);
|
||||||
if (items.get(i) instanceof Item it && it.item == item) {
|
if (selected != null) {
|
||||||
setSelectedItem(items.get(i));
|
setSelectedItem(selected);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new NullPointerException("not found item page for " + item);
|
throw new NullPointerException("not found item page for %s".formatted(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列表项
|
* 列表项
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-02-22 19:45
|
* @since 2022-02-22 19:45
|
||||||
*/
|
*/
|
||||||
private static class Item extends ToggleButton {
|
private class Item extends NavigationItem {
|
||||||
|
|
||||||
/** 列表项对象 */
|
/** 列表项对象 */
|
||||||
final SidebarItem item;
|
final SidebarItem item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建侧边栏项目
|
||||||
|
*
|
||||||
|
* @param item 侧边栏项目
|
||||||
|
*/
|
||||||
public Item(SidebarItem item) {
|
public Item(SidebarItem item) {
|
||||||
this.item = item;
|
this.item = item;
|
||||||
setText(item.text);
|
setText(item.text);
|
||||||
|
itemMap.put(item, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import com.imyeyu.fx.ui.examples.view.pages.Style;
|
|||||||
import com.imyeyu.fx.ui.examples.view.pages.Welcome;
|
import com.imyeyu.fx.ui.examples.view.pages.Welcome;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.animation.InterpolatorDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.animation.InterpolatorDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.animation.SmoothScrollDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.animation.SmoothScrollDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.CheckBoxPickerDemo;
|
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.DateTimePickerDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.DateTimePickerDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.EditableTableCellDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.EditableTableCellDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.FileTreeViewDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.FileTreeViewDemo;
|
||||||
@@ -82,9 +81,6 @@ public enum SidebarItem {
|
|||||||
|
|
||||||
// ---------- 组件 ----------
|
// ---------- 组件 ----------
|
||||||
|
|
||||||
/** 复选框选择器 */
|
|
||||||
CHECK_BOX_PICKER(CheckBoxPickerDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.check_box_picker")),
|
|
||||||
|
|
||||||
/** 详细时间选择器 */
|
/** 详细时间选择器 */
|
||||||
DATE_TIME_PICKER(DateTimePickerDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.date_time_picker")),
|
DATE_TIME_PICKER(DateTimePickerDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.date_time_picker")),
|
||||||
|
|
||||||
@@ -155,6 +151,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ package com.imyeyu.fx.ui.examples.view.pages;
|
|||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.components.TextFlower;
|
|
||||||
import com.imyeyu.fx.ui.components.TitleLabel;
|
import com.imyeyu.fx.ui.components.TitleLabel;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.examples.bean.Config;
|
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,21 +25,19 @@ 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");
|
||||||
|
|
||||||
// timi-java 说明
|
// timi-java 说明
|
||||||
TextFlower timijavaTips = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.binding_config.tips"));
|
Hyperlink timijavaDescription = new Hyperlink("https://www.imyeyu.net/article/public/aid117.html#配置系统");
|
||||||
XHyperlink timijavaDescription = new XHyperlink("https://www.imyeyu.net/article/public/aid117.html#配置系统");
|
Hyperlink timijavaDocument = new Hyperlink("https://doc.imyeyu.net/timi-java/net/imyeyu/timijava/config/package-summary.html");
|
||||||
XHyperlink timijavaDocument = new XHyperlink("https://doc.imyeyu.net/timi-java/net/imyeyu/timijava/config/package-summary.html");
|
Hyperlink timijavaSource = new Hyperlink("https://git.imyeyu.net/Timi/timi-java/src/master/src/main/java/net/imyeyu/timijava/config");
|
||||||
XHyperlink timijavaSource = new XHyperlink("https://git.imyeyu.net/Timi/timi-java/src/master/src/main/java/net/imyeyu/timijava/config");
|
|
||||||
|
|
||||||
// 窗体尺寸
|
// 窗体尺寸
|
||||||
stageSize = new Label();
|
stageSize = new Label();
|
||||||
@@ -71,7 +67,6 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
|
|||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
add(timijavaTips, 0, row++, 2, 1);
|
|
||||||
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description")), timijavaDescription);
|
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description")), timijavaDescription);
|
||||||
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document")), timijavaDocument);
|
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document")), timijavaDocument);
|
||||||
addRow(row, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source")), timijavaSource);
|
addRow(row, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source")), timijavaSource);
|
||||||
@@ -88,15 +83,14 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
|
|||||||
}});
|
}});
|
||||||
setBottom(new BorderPane() {{
|
setBottom(new BorderPane() {{
|
||||||
setMargin(code, new Insets(12, 0, 0, 0));
|
setMargin(code, new Insets(12, 0, 0, 0));
|
||||||
setTop(new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.binding_config.description")));
|
|
||||||
setCenter(code);
|
setCenter(code);
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
@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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages;
|
package com.imyeyu.fx.ui.examples.view.pages;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.components.TitleLabel;
|
import com.imyeyu.fx.ui.components.TitleLabel;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
|
||||||
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.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.SmoothScroll;
|
||||||
@@ -97,10 +97,10 @@ public class ExtendDemo extends AbstractDemoPane {
|
|||||||
final TitleLabel title = new TitleLabel();
|
final TitleLabel title = new TitleLabel();
|
||||||
|
|
||||||
/** 文档 */
|
/** 文档 */
|
||||||
final XHyperlink document = new XHyperlink();
|
final Hyperlink document = new Hyperlink();
|
||||||
|
|
||||||
/** 源码 */
|
/** 源码 */
|
||||||
final XHyperlink source = new XHyperlink();
|
final Hyperlink source = new Hyperlink();
|
||||||
|
|
||||||
public Item() {
|
public Item() {
|
||||||
setPadding(new Insets(0, 0, 32, 0));
|
setPadding(new Insets(0, 0, 32, 0));
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.examples.view.pages;
|
|||||||
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.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.components.TextFlower;
|
|
||||||
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;
|
||||||
@@ -31,22 +30,11 @@ public class RunAsyncDemo extends AbstractDemoPane {
|
|||||||
Label title = new Label(TimiFXUI.MULTILINGUAL.text("important"));
|
Label title = new Label(TimiFXUI.MULTILINGUAL.text("important"));
|
||||||
title.setTextFill(Colorful.RED);
|
title.setTextFill(Colorful.RED);
|
||||||
|
|
||||||
// 提示 0
|
|
||||||
TextFlower tips0 = new TextFlower().textStart();
|
|
||||||
tips0.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.run_async.tips0"));
|
|
||||||
|
|
||||||
// 提示 1
|
|
||||||
TextFlower tips1 = new TextFlower().textStart();
|
|
||||||
tips1.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.run_async.tips1"));
|
|
||||||
|
|
||||||
// 时间示例
|
// 时间示例
|
||||||
Label time = new Label();
|
Label time = new Label();
|
||||||
RunAsyncScheduled.call(Duration.seconds(1), Time::now, t -> time.setText(Time.toDateTime(t)));
|
RunAsyncScheduled.call(Duration.seconds(1), Time::now, t -> time.setText(Time.toDateTime(t)));
|
||||||
|
|
||||||
// 扩展说明
|
|
||||||
TextFlower description = new TextFlower();
|
|
||||||
description.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.run_async.description"));
|
|
||||||
|
|
||||||
// 代码示例
|
// 代码示例
|
||||||
TextAreaEditor code = new TextAreaEditor();
|
TextAreaEditor code = new TextAreaEditor();
|
||||||
code.setEditable(false);
|
code.setEditable(false);
|
||||||
@@ -69,7 +57,7 @@ RunAsyncScheduled.call(Duration.seconds(1), () -> {
|
|||||||
setTop(new VBox() {{
|
setTop(new VBox() {{
|
||||||
setMargin(time, new Insets(20, 0, 0, 0));
|
setMargin(time, new Insets(20, 0, 0, 0));
|
||||||
setSpacing(4);
|
setSpacing(4);
|
||||||
getChildren().addAll(title, tips0, tips1, time, description);
|
getChildren().addAll(title, time);
|
||||||
}});
|
}});
|
||||||
setCenter(code);
|
setCenter(code);
|
||||||
}});
|
}});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages;
|
package com.imyeyu.fx.ui.examples.view.pages;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.components.TitleLabel;
|
import com.imyeyu.fx.ui.components.TitleLabel;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
||||||
import com.imyeyu.fx.utils.BgFill;
|
import com.imyeyu.fx.utils.BgFill;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.Column;
|
||||||
@@ -29,9 +29,9 @@ public class Style extends AbstractPane {
|
|||||||
public Style() {
|
public Style() {
|
||||||
TitleLabel titleTimiFX = new TitleLabel("TimiFX");
|
TitleLabel titleTimiFX = new TitleLabel("TimiFX");
|
||||||
Label labelTimiFXDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
Label labelTimiFXDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
||||||
XHyperlink timiFXDocument = new XHyperlink("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/TimiFX.html");
|
Hyperlink timiFXDocument = new Hyperlink("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/TimiFX.html");
|
||||||
Label labelTimiFXSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
Label labelTimiFXSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
||||||
XHyperlink timiFXSource = new XHyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/TimiFX.java");
|
Hyperlink timiFXSource = new Hyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/TimiFX.java");
|
||||||
Label labelTimiFXDescription = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description"));
|
Label labelTimiFXDescription = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description"));
|
||||||
Label timiFXDescription = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.style.timifx"));
|
Label timiFXDescription = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.style.timifx"));
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public class Style extends AbstractPane {
|
|||||||
// 样式文件
|
// 样式文件
|
||||||
TitleLabel styleFile = new TitleLabel(TimiFXUI.MULTILINGUAL.text("fx.example.style.file"));
|
TitleLabel styleFile = new TitleLabel(TimiFXUI.MULTILINGUAL.text("fx.example.style.file"));
|
||||||
Label labelFile = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
Label labelFile = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
||||||
XHyperlink file = new XHyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/resources/timifx/style.css");
|
Hyperlink file = new Hyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/resources/timifx/style.css");
|
||||||
|
|
||||||
setCenter(new VBox() {{
|
setCenter(new VBox() {{
|
||||||
setSpacing(16);
|
setSpacing(16);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.examples.view.pages;
|
|||||||
import com.imyeyu.fx.TimiFX;
|
import com.imyeyu.fx.TimiFX;
|
||||||
import com.imyeyu.fx.ui.MinecraftFont;
|
import com.imyeyu.fx.ui.MinecraftFont;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.TextFlower;
|
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
|
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
||||||
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
||||||
@@ -13,14 +12,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 +27,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 +38,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);
|
||||||
@@ -62,10 +51,6 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
title.setPadding(new Insets(8, 0, 8, 0));
|
title.setPadding(new Insets(8, 0, 8, 0));
|
||||||
MinecraftFont.css(title, MinecraftFont.X32);
|
MinecraftFont.css(title, MinecraftFont.X32);
|
||||||
|
|
||||||
// 文档和源码
|
|
||||||
TextFlower docSource = new TextFlower();
|
|
||||||
docSource.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.top"));
|
|
||||||
docSource.setTextAlignment(TextAlignment.CENTER);
|
|
||||||
|
|
||||||
// 提示
|
// 提示
|
||||||
Label tips = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips"));
|
Label tips = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips"));
|
||||||
@@ -76,32 +61,26 @@ 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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 版权
|
|
||||||
TextFlower license = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.license"));
|
|
||||||
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"));
|
Label copyright = new Label(TimiFXUI.MULTILINGUAL.text("copyright"));
|
||||||
blog.setTextAlignment(TextAlignment.CENTER);
|
|
||||||
Label copyright = new Label(TimiFXUI.MULTILINGUAL.textArgs("copyright", "夜雨", Time.yearFull.format(new Date())));
|
|
||||||
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")));
|
||||||
}};
|
}};
|
||||||
@@ -111,15 +90,11 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
setSpacing(20);
|
setSpacing(20);
|
||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
setAlignment(Pos.TOP_CENTER);
|
setAlignment(Pos.TOP_CENTER);
|
||||||
getChildren().addAll(docSource, tips, new VBox() {{
|
getChildren().addAll(tips, new VBox() {{
|
||||||
setPadding(new Insets(40));
|
setPadding(new Insets(40));
|
||||||
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips0")));
|
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips0")));
|
||||||
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips1")));
|
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips1")));
|
||||||
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips2")));
|
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips2")));
|
||||||
getChildren().add(new TextFlower() {{
|
|
||||||
setPadding(new Insets(40, 0, 0, 0));
|
|
||||||
matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips3"));
|
|
||||||
}});
|
|
||||||
getChildren().add(new GridPane() {{
|
getChildren().add(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.build(HPos.RIGHT), Column.VALUE);
|
getColumnConstraints().addAll(Column.build(HPos.RIGHT), Column.VALUE);
|
||||||
setHgap(8);
|
setHgap(8);
|
||||||
@@ -141,12 +116,12 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
setAlignment(Pos.CENTER);
|
setAlignment(Pos.CENTER);
|
||||||
getChildren().addAll(TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("lang")), language);
|
getChildren().addAll(TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("lang")), language);
|
||||||
}});
|
}});
|
||||||
getChildren().addAll(versionTimiFX, version, develop, license, blog, copyright);
|
getChildren().addAll(versionTimiFX, version, develop, copyright);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
@InvokeForInjected
|
@PostConstruct
|
||||||
private void injected() {
|
private void init() {
|
||||||
language.valueProperty().bind(config.getLanguage());
|
language.valueProperty().bind(config.getLanguage());
|
||||||
|
|
||||||
// 修改语言
|
// 修改语言
|
||||||
@@ -163,7 +138,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"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.fx.ui.components.CheckBoxPicker;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
|
||||||
import com.imyeyu.inject.annotation.Component;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.layout.FlowPane;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 多选框选择器
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-08-29 15:27
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class CheckBoxPickerDemo extends AbstractDemoPane {
|
|
||||||
|
|
||||||
public CheckBoxPickerDemo() {
|
|
||||||
title.setText(SidebarItem.CHECK_BOX_PICKER.getText());
|
|
||||||
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/CheckBoxPicker.html");
|
|
||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/CheckBoxPicker.java");
|
|
||||||
|
|
||||||
// 选择器
|
|
||||||
CheckBoxPicker<String> picker = new CheckBoxPicker<>();
|
|
||||||
picker.setPrefWidth(390);
|
|
||||||
picker.getSelectedItems().addListener((ListChangeListener<String>) c -> {
|
|
||||||
List<String> items = picker.getSelectedItems();
|
|
||||||
picker.clear();
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
|
||||||
picker.appendText(items.get(i));
|
|
||||||
if (i < items.size() - 1) {
|
|
||||||
picker.appendText(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setCenter(new FlowPane() {{
|
|
||||||
setPadding(new Insets(20));
|
|
||||||
getChildren().add(picker);
|
|
||||||
}});
|
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
picker.getItems().add(TimiFXUI.MULTILINGUAL.textArgs("fx.example.check_box_picker.item", i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -82,7 +82,7 @@ public class EditableTableCellDemo extends AbstractDemoPane {
|
|||||||
* 数据对象
|
* 数据对象
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-08-29 21:10
|
* @since 2022-08-29 21:10
|
||||||
*/
|
*/
|
||||||
public static class Item {
|
public static class Item {
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.components.IconPicker;
|
import com.imyeyu.fx.ui.components.IconPicker;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
|
||||||
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;
|
||||||
@@ -26,7 +26,7 @@ public class IconPickerDemo extends AbstractDemoPane {
|
|||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/IconPicker.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/IconPicker.java");
|
||||||
|
|
||||||
// 图标主页
|
// 图标主页
|
||||||
XHyperlink index = new XHyperlink("https://www.imyeyu.net/article/public/aid119.html");
|
Hyperlink index = new Hyperlink("https://www.imyeyu.net/article/public/aid119.html");
|
||||||
|
|
||||||
if (getTop() instanceof VBox top) {
|
if (getTop() instanceof VBox top) {
|
||||||
top.getChildren().add(new TextFlow() {{
|
top.getChildren().add(new TextFlow() {{
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.Navigation;
|
import com.imyeyu.fx.ui.components.navigation.Navigation;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationGroup;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationItem;
|
||||||
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.fx.utils.Column;
|
import com.imyeyu.fx.utils.Column;
|
||||||
@@ -10,7 +12,6 @@ import com.imyeyu.inject.annotation.Component;
|
|||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,40 +33,55 @@ public class NavigationDemo extends AbstractDemoPane {
|
|||||||
Label labelCommonly = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("commonly"));
|
Label labelCommonly = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("commonly"));
|
||||||
labelCommonly.setAlignment(Pos.CENTER);
|
labelCommonly.setAlignment(Pos.CENTER);
|
||||||
Navigation commonly = new Navigation();
|
Navigation commonly = new Navigation();
|
||||||
commonly.add(new ToggleButton("item 0"));
|
commonly.setPrefWidth(240);
|
||||||
commonly.add(new ToggleButton("item 1"));
|
commonly.add(new NavigationItem("item 0"));
|
||||||
commonly.add(new ToggleButton("item 2"));
|
commonly.add(new NavigationItem("item 1"));
|
||||||
|
commonly.add(new NavigationItem("item 2"));
|
||||||
|
|
||||||
// 二级
|
// 二级
|
||||||
Label labelSecond = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"));
|
Label labelSecond = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"));
|
||||||
labelSecond.setAlignment(Pos.CENTER);
|
labelSecond.setAlignment(Pos.CENTER);
|
||||||
Navigation second = new Navigation();
|
Navigation second = new Navigation();
|
||||||
second.add(new ToggleButton("item 0"));
|
second.add(new NavigationItem("item 0"));
|
||||||
second.add(new ToggleButton("item 1"));
|
second.add(new NavigationItem("item 1"));
|
||||||
second.add(new ToggleButton("item 2"));
|
second.add(new NavigationItem("item 2"));
|
||||||
second.addGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
second.add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1")));
|
||||||
|
|
||||||
// 默认展开
|
// 默认展开
|
||||||
Label labelExpanded = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.expanded"));
|
Label labelExpanded = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.expanded"));
|
||||||
labelExpanded.setAlignment(Pos.CENTER);
|
labelExpanded.setAlignment(Pos.CENTER);
|
||||||
Navigation expanded = new Navigation();
|
Navigation expanded = new Navigation();
|
||||||
expanded.add(new ToggleButton("item 0"));
|
expanded.add(new NavigationItem("item 0"));
|
||||||
expanded.add(new ToggleButton("item 1"));
|
expanded.add(new NavigationItem("item 1"));
|
||||||
expanded.add(new ToggleButton("item 2"));
|
expanded.add(new NavigationItem("item 2"));
|
||||||
expanded.addExpandedGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
expanded.add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1")));
|
||||||
|
|
||||||
// 多个二级
|
// 三级
|
||||||
Label labelMulti = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.multi"));
|
Label labelMulti = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.multi"));
|
||||||
labelMulti.setAlignment(Pos.CENTER);
|
labelMulti.setAlignment(Pos.CENTER);
|
||||||
Navigation multi = new Navigation();
|
Navigation multi = new Navigation();
|
||||||
multi.add(new ToggleButton("item 0"));
|
multi.add(new NavigationItem("item 0"));
|
||||||
multi.add(new ToggleButton("item 1"));
|
multi.add(new NavigationItem("item 1"));
|
||||||
multi.add(new ToggleButton("item 2"));
|
multi.add(new NavigationItem("item 2"));
|
||||||
multi.addExpandedGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
multi.add(
|
||||||
multi.addExpandedGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(
|
||||||
|
new NavigationItem("item 0"),
|
||||||
|
new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.multi"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1"))
|
||||||
|
),
|
||||||
|
new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1"))
|
||||||
|
);
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
Column col = Column.build().width(120);
|
Column col = Column.build().width(220);
|
||||||
getColumnConstraints().addAll(col, col, col, col);
|
getColumnConstraints().addAll(col, col, col, col);
|
||||||
getRowConstraints().addAll(Row.build(), Row.build().alwaysPriority());
|
getRowConstraints().addAll(Row.build(), Row.build().alwaysPriority());
|
||||||
setVgap(5);
|
setVgap(5);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.XPagination;
|
import com.imyeyu.fx.ui.components.Pagination;
|
||||||
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.fx.utils.Column;
|
import com.imyeyu.fx.utils.Column;
|
||||||
@@ -26,7 +26,7 @@ public class XPaginationDemo extends AbstractDemoPane {
|
|||||||
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/XPagination.html");
|
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/XPagination.html");
|
||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/XPagination.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/XPagination.java");
|
||||||
|
|
||||||
XPagination pagination = new XPagination();
|
Pagination pagination = new Pagination();
|
||||||
|
|
||||||
// 总数
|
// 总数
|
||||||
Label total = new Label();
|
Label total = new Label();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.XTabPane;
|
import com.imyeyu.fx.ui.components.TabPane;
|
||||||
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;
|
||||||
@@ -10,8 +10,6 @@ import javafx.scene.control.Button;
|
|||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签面板
|
* 标签面板
|
||||||
*
|
*
|
||||||
@@ -29,17 +27,15 @@ public class XTabPaneDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
Button add = new Button(TimiFXUI.MULTILINGUAL.text("add"));
|
Button add = new Button(TimiFXUI.MULTILINGUAL.text("add"));
|
||||||
|
|
||||||
XTabPane tabPane = new XTabPane();
|
TabPane tabPane = new TabPane();
|
||||||
|
tabPane.setTabClosingPolicy(javafx.scene.control.TabPane.TabClosingPolicy.ALL_TABS);
|
||||||
|
|
||||||
setCenter(new BorderPane() {{
|
setCenter(new BorderPane() {{
|
||||||
setMargin(add, new Insets(0, 0, 20, 0));
|
setMargin(add, new Insets(0, 0, 20, 0));
|
||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
setTop(add);
|
setTop(add);
|
||||||
setCenter(tabPane);
|
setBottom(tabPane);
|
||||||
}});
|
}});
|
||||||
|
add.setOnAction(e -> tabPane.getTabs().add(new Tab("test顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶")));
|
||||||
add.setOnAction(e -> tabPane.getAdd().fire());
|
|
||||||
tabPane.getAdd().setOnAction(e -> tabPane.getTabs().add(new Tab(UUID.randomUUID().toString().substring(0, 8))));
|
|
||||||
tabPane.getAdd().fire();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user