From 57e6b1329271ec72d2ba1f9eb1b3f789241f2ca5 Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 17 Jun 2026 01:14:11 +0800 Subject: [PATCH] rename remove X prefix --- .../imyeyu/fx/ui/components/FileTreeView.java | 2 +- .../{XHyperlink.java => Hyperlink.java} | 12 +++--- .../{XPagination.java => Pagination.java} | 8 ++-- .../{XTabPane.java => TabPane.java} | 41 +++---------------- .../{XTreeView.java => TreeView.java} | 5 +-- src/main/resources/timifx/style.css | 20 ++++++++- .../examples/component/AbstractDemoPane.java | 10 ++--- .../examples/component/sidebar/Sidebar.java | 39 +++++++++++------- .../component/sidebar/SidebarItem.java | 4 -- .../view/pages/BindingsConfigDemo.java | 12 ++---- .../fx/ui/examples/view/pages/ExtendDemo.java | 6 +-- .../ui/examples/view/pages/RunAsyncDemo.java | 14 +------ .../fx/ui/examples/view/pages/Style.java | 8 ++-- .../fx/ui/examples/view/pages/Welcome.java | 19 +-------- .../view/pages/component/IconPickerDemo.java | 4 +- .../view/pages/component/XPaginationDemo.java | 4 +- .../view/pages/component/XTabPaneDemo.java | 14 +++---- 17 files changed, 91 insertions(+), 131 deletions(-) rename src/main/java/com/imyeyu/fx/ui/components/{XHyperlink.java => Hyperlink.java} (87%) rename src/main/java/com/imyeyu/fx/ui/components/{XPagination.java => Pagination.java} (98%) rename src/main/java/com/imyeyu/fx/ui/components/{XTabPane.java => TabPane.java} (63%) rename src/main/java/com/imyeyu/fx/ui/components/{XTreeView.java => TreeView.java} (88%) diff --git a/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java b/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java index d747bf0..7831412 100644 --- a/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java +++ b/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java @@ -40,7 +40,7 @@ import java.util.List; * @author 夜雨 * @since 2022-05-26 14:32 */ -public class FileTreeView extends XTreeView implements TimiFXUI.Colorful { +public class FileTreeView extends TreeView implements TimiFXUI.Colorful { /** 正在查找节点监听 */ protected final BooleanBinding findingItem; diff --git a/src/main/java/com/imyeyu/fx/ui/components/XHyperlink.java b/src/main/java/com/imyeyu/fx/ui/components/Hyperlink.java similarity index 87% rename from src/main/java/com/imyeyu/fx/ui/components/XHyperlink.java rename to src/main/java/com/imyeyu/fx/ui/components/Hyperlink.java index 52ece2c..d8a35fc 100644 --- a/src/main/java/com/imyeyu/fx/ui/components/XHyperlink.java +++ b/src/main/java/com/imyeyu/fx/ui/components/Hyperlink.java @@ -21,13 +21,13 @@ import java.util.regex.Pattern; * 超链标签 * *
- *     new XHyperlink("个人博客", "https://www.imyeyu.net");
+ *     new Hyperlink("个人博客", "https://www.imyeyu.net");
  * 
* * @author 夜雨 * @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()@:%_+.~#?&/=]*)"); @@ -35,7 +35,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful { protected final StringProperty url; /** 默认构造器 */ - public XHyperlink() { + public Hyperlink() { this("", ""); } @@ -44,7 +44,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful { * * @param url 链接 */ - public XHyperlink(String url) { + public Hyperlink(String url) { this(url, url); } @@ -54,7 +54,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful { * @param text 显示文本 * @param url 链接 */ - public XHyperlink(String text, String url) { + public Hyperlink(String text, String url) { this(null, text, url); } @@ -65,7 +65,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful { * @param text 显示文本 * @param url 链接 */ - public XHyperlink(Node icon, String text, String url) { + public Hyperlink(Node icon, String text, String url) { super(text); this.url = new SimpleStringProperty(url); diff --git a/src/main/java/com/imyeyu/fx/ui/components/XPagination.java b/src/main/java/com/imyeyu/fx/ui/components/Pagination.java similarity index 98% rename from src/main/java/com/imyeyu/fx/ui/components/XPagination.java rename to src/main/java/com/imyeyu/fx/ui/components/Pagination.java index 85d9311..7eb8f93 100644 --- a/src/main/java/com/imyeyu/fx/ui/components/XPagination.java +++ b/src/main/java/com/imyeyu/fx/ui/components/Pagination.java @@ -24,7 +24,7 @@ import java.util.List; /** * 分页组件,支持省略页,滚动页,如 [<][1]..[5][6][7][8][9]..[20][>] *
- *     XPagination pagination = new XPagination();
+ *     Pagination pagination = new Pagination();
  *     pagination.setSize(10);    // 单页数据量
  *     pagination.setLength(200); // 总数据量
  *     pagination.indexProperty((obs, o, newIndex) -> {
@@ -36,7 +36,7 @@ import java.util.List;
  * @author 夜雨
  * @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";
 
@@ -58,7 +58,7 @@ public class XPagination extends HBox implements TimiFXUI {
 	private final IntegerProperty cp; // chunkProperty  页面数量 [1, N]
 
 	/** 默认构造 */
-	public XPagination() {
+	public Pagination() {
 		// 基本参数
 		lp = new SimpleLongProperty();
 		ip = new SimpleIntegerProperty();
@@ -329,7 +329,7 @@ public class XPagination extends HBox implements TimiFXUI {
 			// 选中更新激活下标
 			selectedProperty().addListener((obs, o, isSelected) -> {
 				if (isSelected) {
-					XPagination.this.ip.set(indexProperty.get());
+					Pagination.this.ip.set(indexProperty.get());
 				}
 			});
 		}
diff --git a/src/main/java/com/imyeyu/fx/ui/components/XTabPane.java b/src/main/java/com/imyeyu/fx/ui/components/TabPane.java
similarity index 63%
rename from src/main/java/com/imyeyu/fx/ui/components/XTabPane.java
rename to src/main/java/com/imyeyu/fx/ui/components/TabPane.java
index 7c9e37e..64931e4 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/XTabPane.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TabPane.java
@@ -4,17 +4,15 @@ import com.imyeyu.fx.icon.TimiFXIcon;
 import com.imyeyu.fx.ui.TimiFXUI;
 import com.imyeyu.java.bean.CallbackArg;
 import com.imyeyu.java.ref.Ref;
-import javafx.animation.TranslateTransition;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
 import javafx.scene.control.Skin;
-import javafx.scene.control.TabPane;
 import javafx.scene.control.skin.TabPaneSkin;
 import javafx.scene.layout.StackPane;
-import javafx.util.Duration;
+import javafx.scene.shape.Rectangle;
 import lombok.Getter;
 
 import java.util.List;
@@ -26,17 +24,7 @@ import java.util.List;
  * @since 2022-07-24 10:54
  */
 @Getter
-public class XTabPane extends 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);
-	}
+public class TabPane extends javafx.scene.control.TabPane implements TimiFXUI, TimiFXUI.Colorful {
 
 	@Override
 	protected Skin createDefaultSkin() {
@@ -45,24 +33,7 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
 			try {
 				StackPane tabHeaderArea = Ref.getFieldValue(tabPaneSkin, "tabHeaderArea", StackPane.class);
 				StackPane headersRegion = Ref.getFieldValue(tabHeaderArea, "headersRegion", StackPane.class);
-				StackPane headersBackground = Ref.getFieldValue(tabHeaderArea, "headerBackground", StackPane.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);
+				Rectangle headerClip = Ref.getFieldValue(tabHeaderArea, "headerClip", Rectangle.class);
 
 				// 关闭按钮调整
 				CallbackArg resizeCloseButton = tabHeaderSkin -> {
@@ -82,7 +53,7 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
 							closeBtn.getChildren().add(icon);
 						}
 					} catch (IllegalAccessException e) {
-						e.printStackTrace();
+						throw new RuntimeException(e);
 					}
 				};
 				ObservableList tabList = headersRegion.getChildren();
@@ -92,8 +63,8 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
 				headersRegion.getChildren().addListener((ListChangeListener) c -> {
 					if (c.next()) {
 						List list = c.getAddedSubList();
-						for (int i = 0; i < list.size(); i++) {
-							resizeCloseButton.handler(list.get(i));
+						for (Node node : list) {
+							resizeCloseButton.handler(node);
 						}
 					}
 				});
diff --git a/src/main/java/com/imyeyu/fx/ui/components/XTreeView.java b/src/main/java/com/imyeyu/fx/ui/components/TreeView.java
similarity index 88%
rename from src/main/java/com/imyeyu/fx/ui/components/XTreeView.java
rename to src/main/java/com/imyeyu/fx/ui/components/TreeView.java
index 5235fef..dbb04c8 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/XTreeView.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TreeView.java
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.components;
 import com.imyeyu.fx.utils.SmoothScroll;
 import javafx.collections.ObservableList;
 import javafx.scene.control.TreeItem;
-import javafx.scene.control.TreeView;
 
 /**
  * 不显示根节点的树形结构,实现多个根节点
@@ -11,12 +10,12 @@ import javafx.scene.control.TreeView;
  * @author 夜雨
  * @since 2021-04-26 01:34
  */
-public class XTreeView extends TreeView {
+public class TreeView extends javafx.scene.control.TreeView {
 
 	private final TreeItem dummyRoot = new TreeItem<>();
 
 	/** 默认构造 */
-	public XTreeView() {
+	public TreeView() {
 		dummyRoot.setExpanded(true);
 		setRoot(dummyRoot);
 		setShowRoot(false);
diff --git a/src/main/resources/timifx/style.css b/src/main/resources/timifx/style.css
index f39fc72..efbcc73 100644
--- a/src/main/resources/timifx/style.css
+++ b/src/main/resources/timifx/style.css
@@ -630,6 +630,24 @@
 .tab-pane > .tab-header-area > .headers-region > .tab > .tab-container > .tab-label {
     -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 {
     -fx-padding: 0;
 }
@@ -813,4 +831,4 @@
 }
 .border-lr {
 	-fx-border-width: 0 1 0 1;
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/component/AbstractDemoPane.java b/src/test/java/com/imyeyu/fx/ui/examples/component/AbstractDemoPane.java
index fbed343..31bf37e 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/component/AbstractDemoPane.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/component/AbstractDemoPane.java
@@ -1,7 +1,7 @@
 package com.imyeyu.fx.ui.examples.component;
 
 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.scene.control.Label;
 import javafx.scene.layout.GridPane;
@@ -22,10 +22,10 @@ public abstract class AbstractDemoPane extends AbstractPane {
 	protected Label tips;
 
 	/** 文档 */
-	protected XHyperlink document;
+	protected Hyperlink document;
 
 	/** 源码 */
-	protected XHyperlink source;
+	protected Hyperlink source;
 
 	public AbstractDemoPane() {
 		// 标题
@@ -37,11 +37,11 @@ public abstract class AbstractDemoPane extends AbstractPane {
 
 		// 文档
 		Label labelDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
-		document = new XHyperlink();
+		document = new Hyperlink();
 
 		// 源码
 		Label labelSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
-		source = new XHyperlink();
+		source = new Hyperlink();
 
 		// 提示
 		tips = TimiFXUI.label();
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/Sidebar.java b/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/Sidebar.java
index 87f3a51..51be609 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/Sidebar.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/Sidebar.java
@@ -1,10 +1,14 @@
 package com.imyeyu.fx.ui.examples.component.sidebar;
 
 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.inject.annotation.Component;
-import javafx.scene.control.ToggleButton;
+
+import java.util.EnumMap;
+import java.util.Map;
 
 /**
  * 导航
@@ -15,6 +19,9 @@ import javafx.scene.control.ToggleButton;
 @Component
 public class Sidebar extends Navigation {
 
+	/** 侧边栏项目映射 */
+	private final Map itemMap = new EnumMap<>(SidebarItem.class);
+
 	public Sidebar(PageService pageService) {
 
 		Item welcome = new Item(SidebarItem.WELCOME);
@@ -31,23 +38,22 @@ public class Sidebar extends Navigation {
 		// 动画
 		Item interpolator = new Item(SidebarItem.INTERPOLATOR);
 		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.CHECK_BOX_PICKER, SidebarItem.DATE_TIME_PICKER, SidebarItem.EDITABLE_TABLE_CELL, SidebarItem.FILE_TREE_VIEW, SidebarItem.ICON_BUTTON, SidebarItem.ICON_PICKER, SidebarItem.LABEL_PROGRESS_BAR, SidebarItem.NAVIGATION, SidebarItem.NUMBER_FIELD, SidebarItem.PROGRESS_SLIDER, SidebarItem.SELECTABLE_LABEL, SidebarItem.TEXT_AREA_EDITOR, SidebarItem.TITLE_LABEL, SidebarItem.TOGGLE_ICON, SidebarItem.X_PAGINATION, SidebarItem.X_TAB_PANE, SidebarItem.X_TREE_VIEW};
+		SidebarItem[] 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};
 		Item[] componentItems = new Item[components.length];
 		for (int i = 0; i < componentItems.length; 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 draggableWindow = new Item(SidebarItem.DRAGGABLE_WINDOW);
 		Item screen = new Item(SidebarItem.SCREEN);
 		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);
 		setMinWidth(140);
 
@@ -67,13 +73,12 @@ public class Sidebar extends Navigation {
 	 * @param item 选中项
 	 */
 	public void setSelected(SidebarItem item) {
-		for (int i = 0; i < items.size(); i++) {
-			if (items.get(i) instanceof Item it && it.item == item) {
-				setSelectedItem(items.get(i));
-				return;
-			}
+		Item selected = itemMap.get(item);
+		if (selected != null) {
+			setSelectedItem(selected);
+			return;
 		}
-		throw new NullPointerException("not found item page for " + item);
+		throw new NullPointerException("not found item page for %s".formatted(item));
 	}
 
 	/**
@@ -82,14 +87,20 @@ public class Sidebar extends Navigation {
 	 * @author 夜雨
 	 * @since 2022-02-22 19:45
 	 */
-	private static class Item extends ToggleButton {
+	private class Item extends NavigationItem {
 
 		/** 列表项对象 */
 		final SidebarItem item;
 
+		/**
+		 * 创建侧边栏项目
+		 *
+		 * @param item 侧边栏项目
+		 */
 		public Item(SidebarItem item) {
 			this.item = item;
 			setText(item.text);
+			itemMap.put(item, this);
 		}
 	}
 }
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/SidebarItem.java b/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/SidebarItem.java
index 31cf6b3..810a658 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/SidebarItem.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/component/sidebar/SidebarItem.java
@@ -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.animation.InterpolatorDemo;
 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.EditableTableCellDemo;
 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")),
 
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/BindingsConfigDemo.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/BindingsConfigDemo.java
index 8f22a30..7075cd4 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/BindingsConfigDemo.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/BindingsConfigDemo.java
@@ -2,9 +2,8 @@ package com.imyeyu.fx.ui.examples.view.pages;
 
 import com.imyeyu.fx.ui.TimiFXUI;
 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.XHyperlink;
+import com.imyeyu.fx.ui.components.Hyperlink;
 import com.imyeyu.fx.ui.examples.bean.Config;
 import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
 import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
@@ -36,10 +35,9 @@ public class BindingsConfigDemo extends AbstractDemoPane {
 		source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/config/BindingsConfig.java");
 
 		// timi-java 说明
-		TextFlower timijavaTips = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.binding_config.tips"));
-		XHyperlink timijavaDescription = new XHyperlink("https://www.imyeyu.net/article/public/aid117.html#配置系统");
-		XHyperlink timijavaDocument = new XHyperlink("https://doc.imyeyu.net/timi-java/net/imyeyu/timijava/config/package-summary.html");
-		XHyperlink timijavaSource = new XHyperlink("https://git.imyeyu.net/Timi/timi-java/src/master/src/main/java/net/imyeyu/timijava/config");
+		Hyperlink timijavaDescription = new Hyperlink("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");
+		Hyperlink timijavaSource = new Hyperlink("https://git.imyeyu.net/Timi/timi-java/src/master/src/main/java/net/imyeyu/timijava/config");
 
 		// 窗体尺寸
 		stageSize = new Label();
@@ -69,7 +67,6 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
 				setPadding(new Insets(20));
 
 				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("document")), timijavaDocument);
 				addRow(row, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source")), timijavaSource);
@@ -86,7 +83,6 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
 				}});
 				setBottom(new BorderPane() {{
 					setMargin(code, new Insets(12, 0, 0, 0));
-					setTop(new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.binding_config.description")));
 					setCenter(code);
 				}});
 			}});
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/ExtendDemo.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/ExtendDemo.java
index a4b2f31..8e6e5da 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/ExtendDemo.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/ExtendDemo.java
@@ -1,8 +1,8 @@
 package com.imyeyu.fx.ui.examples.view.pages;
 
 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.XHyperlink;
 import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
 import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
 import com.imyeyu.fx.utils.SmoothScroll;
@@ -97,10 +97,10 @@ public class ExtendDemo extends AbstractDemoPane {
 		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() {
 			setPadding(new Insets(0, 0, 32, 0));
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/RunAsyncDemo.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/RunAsyncDemo.java
index 0758b9e..77c8f41 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/RunAsyncDemo.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/RunAsyncDemo.java
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.examples.view.pages;
 import com.imyeyu.fx.task.RunAsyncScheduled;
 import com.imyeyu.fx.ui.TimiFXUI;
 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.sidebar.SidebarItem;
 import com.imyeyu.inject.annotation.Component;
@@ -31,22 +30,11 @@ public class RunAsyncDemo extends AbstractDemoPane {
 		Label title = new Label(TimiFXUI.MULTILINGUAL.text("important"));
 		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();
 		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();
 		code.setEditable(false);
@@ -69,7 +57,7 @@ RunAsyncScheduled.call(Duration.seconds(1), () -> {
 			setTop(new VBox() {{
 				setMargin(time, new Insets(20, 0, 0, 0));
 				setSpacing(4);
-				getChildren().addAll(title, tips0, tips1, time, description);
+				getChildren().addAll(title, time);
 			}});
 			setCenter(code);
 		}});
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Style.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Style.java
index 1f3ccec..8188609 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Style.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Style.java
@@ -1,8 +1,8 @@
 package com.imyeyu.fx.ui.examples.view.pages;
 
 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.XHyperlink;
 import com.imyeyu.fx.ui.examples.component.AbstractPane;
 import com.imyeyu.fx.utils.BgFill;
 import com.imyeyu.fx.utils.Column;
@@ -29,9 +29,9 @@ public class Style extends AbstractPane {
 	public Style() {
 		TitleLabel titleTimiFX = new TitleLabel("TimiFX");
 		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"));
-		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 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"));
 		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() {{
 			setSpacing(16);
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Welcome.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Welcome.java
index 70e87d9..72dc281 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Welcome.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/Welcome.java
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.examples.view.pages;
 import com.imyeyu.fx.TimiFX;
 import com.imyeyu.fx.ui.MinecraftFont;
 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.AlertTips;
 import com.imyeyu.fx.ui.examples.TimiFXExamples;
@@ -52,10 +51,6 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
 		title.setPadding(new Insets(8, 0, 8, 0));
 		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"));
@@ -80,15 +75,9 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
 			}
 		});
 
-		// 版权
-		TextFlower license = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.license"));
-		license.setTextAlignment(TextAlignment.CENTER);
-
 		// 开发者
 		Label develop = new Label(TimiFXUI.MULTILINGUAL.text("developer.arg"));
 		develop.setAlignment(Pos.CENTER);
-		TextFlower blog = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("blog"));
-		blog.setTextAlignment(TextAlignment.CENTER);
 		Label copyright = new Label(TimiFXUI.MULTILINGUAL.text("copyright"));
 		copyright.setAlignment(Pos.CENTER);
 		Label versionTimiFX = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.version.timifx"));
@@ -101,15 +90,11 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
 			setSpacing(20);
 			setPadding(new Insets(20));
 			setAlignment(Pos.TOP_CENTER);
-			getChildren().addAll(docSource, tips, new VBox() {{
+			getChildren().addAll(tips, new VBox() {{
 				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.tips1")));
 				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() {{
 					getColumnConstraints().addAll(Column.build(HPos.RIGHT), Column.VALUE);
 					setHgap(8);
@@ -131,7 +116,7 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
 				setAlignment(Pos.CENTER);
 				getChildren().addAll(TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("lang")), language);
 			}});
-			getChildren().addAll(versionTimiFX, version, develop, license, blog, copyright);
+			getChildren().addAll(versionTimiFX, version, develop, copyright);
 		}});
 	}
 
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/IconPickerDemo.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/IconPickerDemo.java
index bda94d3..21c4856 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/IconPickerDemo.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/IconPickerDemo.java
@@ -1,8 +1,8 @@
 package com.imyeyu.fx.ui.examples.view.pages.component;
 
 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.XHyperlink;
 import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
 import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
 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");
 
 		// 图标主页
-		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) {
 			top.getChildren().add(new TextFlow() {{
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XPaginationDemo.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XPaginationDemo.java
index dffdf9c..aeeff18 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XPaginationDemo.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XPaginationDemo.java
@@ -1,7 +1,7 @@
 package com.imyeyu.fx.ui.examples.view.pages.component;
 
 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.sidebar.SidebarItem;
 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");
 		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();
diff --git a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XTabPaneDemo.java b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XTabPaneDemo.java
index f7d2ae7..6a07849 100644
--- a/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XTabPaneDemo.java
+++ b/src/test/java/com/imyeyu/fx/ui/examples/view/pages/component/XTabPaneDemo.java
@@ -1,7 +1,7 @@
 package com.imyeyu.fx.ui.examples.view.pages.component;
 
 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.sidebar.SidebarItem;
 import com.imyeyu.inject.annotation.Component;
@@ -10,8 +10,6 @@ import javafx.scene.control.Button;
 import javafx.scene.control.Tab;
 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"));
 
-		XTabPane tabPane = new XTabPane();
+		TabPane tabPane = new TabPane();
+		tabPane.setTabClosingPolicy(javafx.scene.control.TabPane.TabClosingPolicy.ALL_TABS);
 
 		setCenter(new BorderPane() {{
 			setMargin(add, new Insets(0, 0, 20, 0));
 			setPadding(new Insets(20));
 			setTop(add);
-			setCenter(tabPane);
+			setBottom(tabPane);
 		}});
-
-		add.setOnAction(e -> tabPane.getAdd().fire());
-		tabPane.getAdd().setOnAction(e -> tabPane.getTabs().add(new Tab(UUID.randomUUID().toString().substring(0, 8))));
-		tabPane.getAdd().fire();
+		add.setOnAction(e -> tabPane.getTabs().add(new Tab("test顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶")));
 	}
 }