From a143e6a01064e0353f6e64854e557291785ab8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=99=BD=E4=B8=8E=E5=AD=9F=E6=B5=A9=E7=84=B6?= <1063889643@qq.com> Date: Thu, 28 Sep 2023 17:21:12 +0800 Subject: [PATCH 1/2] =?UTF-8?q?#I806RK=20state=20to=20=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=B8=AD=20=E5=9F=BA=E6=9C=AC=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 12 +- ...ialApplication.java => GitManagerApp.java} | 62 ++++++---- src/main/java/com/light/LogApplication.java | 26 ---- src/main/java/com/light/LogService.java | 18 --- .../java/com/light/layout/ContentPane.java | 14 +++ src/main/java/com/light/layout/MenuPane.java | 63 ++++++++++ src/main/java/com/light/layout/NavItem.java | 51 ++++++++ src/main/java/com/light/util/FxUtil.java | 114 ++++++++++++++++++ src/main/java/com/light/util/H2Utils.java | 4 + src/main/java/com/light/util/NodeUtils.java | 29 +++++ src/main/java/module-info.java | 3 + 11 files changed, 323 insertions(+), 73 deletions(-) rename src/main/java/com/light/{TutorialApplication.java => GitManagerApp.java} (30%) delete mode 100644 src/main/java/com/light/LogApplication.java delete mode 100644 src/main/java/com/light/LogService.java create mode 100644 src/main/java/com/light/layout/ContentPane.java create mode 100644 src/main/java/com/light/layout/MenuPane.java create mode 100644 src/main/java/com/light/layout/NavItem.java create mode 100644 src/main/java/com/light/util/FxUtil.java create mode 100644 src/main/java/com/light/util/H2Utils.java create mode 100644 src/main/java/com/light/util/NodeUtils.java diff --git a/pom.xml b/pom.xml index 4ddcd58..882fede 100644 --- a/pom.xml +++ b/pom.xml @@ -9,10 +9,10 @@ 1.0-SNAPSHOT - 20 - 20 + 21 + 21 UTF-8 - 20.0.2 + 21 2.0.1 @@ -106,6 +106,12 @@ atlantafx-base ${atlantafx.version} + + org.jetbrains + annotations + 23.0.0 + compile + diff --git a/src/main/java/com/light/TutorialApplication.java b/src/main/java/com/light/GitManagerApp.java similarity index 30% rename from src/main/java/com/light/TutorialApplication.java rename to src/main/java/com/light/GitManagerApp.java index 97bb58e..6cccd4f 100644 --- a/src/main/java/com/light/TutorialApplication.java +++ b/src/main/java/com/light/GitManagerApp.java @@ -1,45 +1,55 @@ package com.light; +import atlantafx.base.theme.PrimerLight; +import com.light.layout.ContentPane; +import com.light.layout.MenuPane; +import com.light.util.NodeUtils; import javafx.application.Application; +import javafx.geometry.Insets; import javafx.scene.Scene; -import javafx.scene.control.Label; import javafx.scene.image.Image; -import javafx.scene.layout.*; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -/** - * TODO 例子,后续移除 - */ -public class TutorialApplication extends Application { +public class GitManagerApp extends Application { - public static void main(String[] args) { - launch(args); - } + public static final Logger LOGGER = LoggerFactory.getLogger(GitManagerApp.class); @Override public void start(Stage stage) throws Exception { - // label - Label l = new Label("Hello"); - l.setFont(Font.font(20)); - - BorderPane root = new BorderPane(l); - - root.setTop(getPane("blue")); - root.setLeft(getPane("green")); - - Scene scene = new Scene(root, 1096, 768); + // 主题 + Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet()); + + // 根节点 + AnchorPane root = new AnchorPane(); + + // 左右布局 + HBox container = new HBox(); + // 内容 + ContentPane contentPane = new ContentPane(); + // 菜单 + MenuPane menuPane = new MenuPane(contentPane); + container.getChildren().addAll(menuPane, contentPane); + HBox.setHgrow(contentPane, Priority.ALWAYS); + + root.getChildren().add(container); + NodeUtils.setAnchors(root, Insets.EMPTY); + + // 场景 + Scene scene = new Scene(root, 1000, 600); stage.setTitle("Git批量管理工具"); stage.getIcons().add(new Image(this.getClass().getResource("/icons/git.png").toExternalForm())); stage.setScene(scene); stage.show(); + + LOGGER.info("项目启动完成。。。"); } - public Pane getPane(String color) { - Pane pane = new Pane(); - pane.setPrefSize(100.0, 100.0); - pane.setStyle("-fx-background-color: " + color); - return pane; + public static void main(String[] args) { + launch(args); } } diff --git a/src/main/java/com/light/LogApplication.java b/src/main/java/com/light/LogApplication.java deleted file mode 100644 index da176e6..0000000 --- a/src/main/java/com/light/LogApplication.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.light; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -/** - * 日志使用示例,后续删除 - */ -public class LogApplication { - - public static final Logger LOGGER = LoggerFactory.getLogger(LogApplication.class); - private static final Logger COMMON_LOGGER = LoggerFactory.getLogger("COMMON"); - - public static void main(String[] args) { - for (int i = 0; i < 10; i++) { - LogService logService = new LogService(); - LOGGER.info("这是info日志"); - LOGGER.error("这是error日志"); - LOGGER.warn("这是warn日志"); - LOGGER.debug("这是debug日志"); - COMMON_LOGGER.info("这是common的info日志"); - COMMON_LOGGER.warn("这是common的warn日志"); - COMMON_LOGGER.debug("这是common的debug日志"); - } - - } -} diff --git a/src/main/java/com/light/LogService.java b/src/main/java/com/light/LogService.java deleted file mode 100644 index eef7698..0000000 --- a/src/main/java/com/light/LogService.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.light; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 日志使用示例,后续删除 - */ -public class LogService { - - private static final Logger LOGGER = LoggerFactory.getLogger(LogService.class); - - public LogService() { - LOGGER.info("这是com.leo.service中的info日志"); - LOGGER.warn("这是com.leo.service中的warn日志"); - LOGGER.debug("这是com.leo.service中的debug日志"); - } -} diff --git a/src/main/java/com/light/layout/ContentPane.java b/src/main/java/com/light/layout/ContentPane.java new file mode 100644 index 0000000..d08b986 --- /dev/null +++ b/src/main/java/com/light/layout/ContentPane.java @@ -0,0 +1,14 @@ +package com.light.layout; + +import javafx.scene.Node; +import javafx.scene.layout.BorderPane; + +public class ContentPane extends BorderPane { + + public ContentPane() { + } + + public void setContent(Node content) { + setCenter(content); + } +} diff --git a/src/main/java/com/light/layout/MenuPane.java b/src/main/java/com/light/layout/MenuPane.java new file mode 100644 index 0000000..e2e2602 --- /dev/null +++ b/src/main/java/com/light/layout/MenuPane.java @@ -0,0 +1,63 @@ +package com.light.layout; + +import javafx.geometry.Orientation; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.Separator; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled; +import org.kordamp.ikonli.antdesignicons.AntDesignIconsOutlined; +import org.kordamp.ikonli.javafx.FontIcon; + +import java.util.Optional; + +public class MenuPane extends StackPane { + + // 顶部导航栏 + private final NavItem setting = new NavItem(new FontIcon(AntDesignIconsFilled.SETTING), "设置", null); + private final NavItem notification = new NavItem(new FontIcon(AntDesignIconsFilled.NOTIFICATION), "通知", null); + private final VBox topMenu = new VBox(setting, notification); + + // 动态导航栏 + private final ListView dynamicMenu = new ListView<>(); + + // 底部导航栏 + private final Label userLabel = new Label("test"); + private final Label emailLabel = new Label("test@163.com"); + private final VBox bottomMenu = new VBox(userLabel, emailLabel); + + private VBox asideContainer = new VBox(topMenu, new Separator(Orientation.HORIZONTAL), dynamicMenu, new Separator(Orientation.HORIZONTAL), bottomMenu); + + private final ContentPane contentPane; + + public MenuPane(ContentPane contentPane) { + this.contentPane = contentPane; + initialize(); + + // 模拟数据 + dynamicMenu.getItems().addAll( + new NavItem(new FontIcon(AntDesignIconsOutlined.MESSAGE), "提示", null), + new NavItem(new FontIcon(AntDesignIconsFilled.CONTROL), "抽屉", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.MESSAGE), "消息提示", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.LOADING_3_QUARTERS), "加载", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "气泡卡片", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "案例一", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "案例二", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "案例三", null) + ); + } + + private void initialize() { + getChildren().addAll(asideContainer); + VBox.setVgrow(dynamicMenu, Priority.ALWAYS); + + // 加上监听 + dynamicMenu.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + Optional.ofNullable(newValue).ifPresent(menuItem -> { + contentPane.setContent(menuItem.getContent());//设置内容 + }); + }); + } +} diff --git a/src/main/java/com/light/layout/NavItem.java b/src/main/java/com/light/layout/NavItem.java new file mode 100644 index 0000000..76a946d --- /dev/null +++ b/src/main/java/com/light/layout/NavItem.java @@ -0,0 +1,51 @@ +package com.light.layout; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import org.kordamp.ikonli.javafx.FontIcon; + +/** + * 导航组件 + */ +public class NavItem extends HBox { + + /** + * 图标 + */ + private Label iconLabel = new Label(); + + /** + * 标题 + */ + private Label titleLabel = new Label(); + + /** + * 内容界面 + */ + private Node content; + + public NavItem(FontIcon fontIcon, String title, Node content) { + this.iconLabel.setGraphic(fontIcon); + this.titleLabel.setText(title); + this.content = content; + initialize(); + } + + private void initialize() { + getChildren().addAll(iconLabel, titleLabel); + // 标题占满剩余空间 + titleLabel.setMaxSize(Double.MAX_VALUE, USE_PREF_SIZE); + HBox.setHgrow(titleLabel, Priority.ALWAYS); + + getStyleClass().add("nav-item"); + iconLabel.getStyleClass().add("icon-label"); + titleLabel.getStyleClass().add("name-label"); + prefWidthProperty().bind(this.widthProperty().subtract(1)); + } + + public Node getContent() { + return content; + } +} diff --git a/src/main/java/com/light/util/FxUtil.java b/src/main/java/com/light/util/FxUtil.java new file mode 100644 index 0000000..c8bb440 --- /dev/null +++ b/src/main/java/com/light/util/FxUtil.java @@ -0,0 +1,114 @@ +package com.light.util; + +import javafx.beans.binding.Bindings; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.geometry.Bounds; +import javafx.scene.Node; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Region; +import javafx.scene.shape.Rectangle; +import javafx.stage.Stage; +import javafx.stage.Window; + +import java.util.concurrent.Callable; + +/** + * @author ChenFei + * @date 2022/12/9 + */ +public class FxUtil { + + public static String getResource(String resources) { + return FxUtil.class.getResource(resources).toExternalForm(); + } + + public static Image getImage(String resources) { + return new Image(getResource(resources)); + } + + public static ImageView getImageView(String resources, double size) { + return getImageView(resources, size, size); + } + + public static ImageView getImageView(String resources, double height, double width) { + ImageView imageView = new ImageView(getResource(resources)); + imageView.setFitHeight(height); + imageView.setFitWidth(width); + return imageView; + } + + /** + * 获取组件在屏幕中的位置 + * + * @param node + * @return + */ + public static Bounds localToScreen(Node node) { + return node.localToScreen(node.getLayoutBounds()); + } + + /** + * 获取窗口 + * + * @param node + * @return + */ + public static Stage getStage(Node node) { + return (Stage) getWindow(node); + } + + + /** + * 获取当前被聚焦的第一个窗口,没有则返回null。 + * + * @return + */ + public static Window getFocusedWindow() { + return Stage.getWindows().stream().filter(Window::isFocused).findFirst().orElse(null); + } + + /** + * 获取窗口 + * + * @param node + * @return + */ + public static Window getWindow(Node node) { + return node.getParent().getScene().getWindow(); + } + + /** + * 矩形裁剪 + * + * @param region :裁剪区域 + * @return Rectangle + */ + public static Rectangle clipRect(Region region) { + return clipRect(region, new SimpleDoubleProperty(0)); + } + + /** + * 矩形裁剪 + * + * @param node :裁剪区域 + * @param bindArc :裁剪圆角 + * @return Rectangle + */ + public static Rectangle clipRect(Node node, DoubleProperty bindArc) { + Rectangle rectangle = new Rectangle(); + //rectangle.setSmooth(false); + rectangle.widthProperty().bind(Bindings + .createObjectBinding((Callable) () -> + node.getLayoutBounds().getWidth(), node.layoutBoundsProperty())); + rectangle.heightProperty().bind(Bindings + .createObjectBinding((Callable) () -> + node.getLayoutBounds().getHeight(), node.layoutBoundsProperty())); + rectangle.arcWidthProperty().bind(bindArc); + rectangle.arcHeightProperty().bind(bindArc); + node.setClip(rectangle); + return rectangle; + } + +} diff --git a/src/main/java/com/light/util/H2Utils.java b/src/main/java/com/light/util/H2Utils.java new file mode 100644 index 0000000..186e4c2 --- /dev/null +++ b/src/main/java/com/light/util/H2Utils.java @@ -0,0 +1,4 @@ +package com.light.util; + +public class H2Utils { +} diff --git a/src/main/java/com/light/util/NodeUtils.java b/src/main/java/com/light/util/NodeUtils.java new file mode 100644 index 0000000..eeebc21 --- /dev/null +++ b/src/main/java/com/light/util/NodeUtils.java @@ -0,0 +1,29 @@ +package com.light.util; + +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.layout.AnchorPane; + +public final class NodeUtils { + + /** + * 设置子节点距AnchorPane锚点布局四边的距离 + * + * @param node + * @param insets + */ + public static void setAnchors(Node node, Insets insets) { + if (insets.getTop() >= 0) { + AnchorPane.setTopAnchor(node, insets.getTop()); + } + if (insets.getRight() >= 0) { + AnchorPane.setRightAnchor(node, insets.getRight()); + } + if (insets.getBottom() >= 0) { + AnchorPane.setBottomAnchor(node, insets.getBottom()); + } + if (insets.getLeft() >= 0) { + AnchorPane.setLeftAnchor(node, insets.getLeft()); + } + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index a0fa134..fbb190d 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -7,4 +7,7 @@ open module com.leo { requires java.sql; requires com.h2database; requires atlantafx.base; + requires org.kordamp.ikonli.javafx; + requires org.jetbrains.annotations; + requires org.kordamp.ikonli.antdesignicons; } -- Gitee From 2eba09f88088464e9cac32454f3bf43d3371e094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=99=BD=E4=B8=8E=E5=AD=9F=E6=B5=A9=E7=84=B6?= <1063889643@qq.com> Date: Sat, 7 Oct 2023 10:14:54 +0800 Subject: [PATCH 2/2] =?UTF-8?q?#I806RK=20state=20to=20=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=B8=AD=20=E5=9F=BA=E6=9C=AC=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/light/layout/MenuPane.java | 19 ++++--- src/main/resources/css/menu.css | 56 ++++++++++++++++++++ src/main/resources/css/test.css | 1 - 3 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/css/menu.css delete mode 100644 src/main/resources/css/test.css diff --git a/src/main/java/com/light/layout/MenuPane.java b/src/main/java/com/light/layout/MenuPane.java index e2e2602..b56ba7d 100644 --- a/src/main/java/com/light/layout/MenuPane.java +++ b/src/main/java/com/light/layout/MenuPane.java @@ -15,6 +15,8 @@ import java.util.Optional; public class MenuPane extends StackPane { + private static final String STYLE_SHEET = MenuPane.class.getResource("/css/menu.css").toExternalForm(); + // 顶部导航栏 private final NavItem setting = new NavItem(new FontIcon(AntDesignIconsFilled.SETTING), "设置", null); private final NavItem notification = new NavItem(new FontIcon(AntDesignIconsFilled.NOTIFICATION), "通知", null); @@ -38,21 +40,22 @@ public class MenuPane extends StackPane { // 模拟数据 dynamicMenu.getItems().addAll( - new NavItem(new FontIcon(AntDesignIconsOutlined.MESSAGE), "提示", null), - new NavItem(new FontIcon(AntDesignIconsFilled.CONTROL), "抽屉", null), - new NavItem(new FontIcon(AntDesignIconsOutlined.MESSAGE), "消息提示", null), - new NavItem(new FontIcon(AntDesignIconsOutlined.LOADING_3_QUARTERS), "加载", null), - new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "气泡卡片", null), - new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "案例一", null), - new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "案例二", null), - new NavItem(new FontIcon(AntDesignIconsOutlined.CONTROL), "案例三", null) + new NavItem(new FontIcon(AntDesignIconsOutlined.HOME), "首页", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.PARTITION), "管理", null), + new NavItem(new FontIcon(AntDesignIconsOutlined.EDIT), "笔记", null) ); } private void initialize() { + // 加载样式 + getStylesheets().add(STYLE_SHEET); + getChildren().addAll(asideContainer); VBox.setVgrow(dynamicMenu, Priority.ALWAYS); + // 添加样式 + this.dynamicMenu.getStyleClass().addAll("menu"); + // 加上监听 dynamicMenu.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { Optional.ofNullable(newValue).ifPresent(menuItem -> { diff --git a/src/main/resources/css/menu.css b/src/main/resources/css/menu.css new file mode 100644 index 0000000..5f1ad56 --- /dev/null +++ b/src/main/resources/css/menu.css @@ -0,0 +1,56 @@ +/*导航栏Item样式*/ +.nav-item{ + -fx-background-radius: 3px; + -fx-min-height: 40px; + -fx-pref-height: 40px; + -fx-alignment: center-left; + -fx-spacing: 10px; + -fx-padding: 0 10px; + -fx-cursor: hand; +} +.nav-item > .icon-label > .ikonli-font-icon{ + -fx-icon-size: 20px; + -fx-icon-color: derive(#303133,30%); +} +.nav-item > .name-label{ + -fx-font-size: 14px; + -fx-pref-height: 30px; + -fx-font-weight: bolder; + -fx-text-fill: derive(#303133,30%); +} +.nav-item:hover > .name-label{ + -fx-text-fill: #6690FF; +} +.nav-item:hover > .icon-label > .ikonli-font-icon{ + -fx-icon-color: #6690FF; +} +/*动态导航栏*/ +.menu{ + -fx-background-insets: 0px; + -fx-background-color:transparent; + -fx-padding:5px 0 5px 0; +} +.menu .scroll-bar{ + -fx-opacity:0; +} +.menu:hover .scroll-bar{ + -fx-opacity:1; +} +.menu .cell.indexed-cell.list-cell{ + -fx-background-color:transparent; + -fx-padding:0px; +} +.menu .cell.indexed-cell.list-cell:empty:hover{ + -fx-background-color:transparent; +} +.menu .cell.indexed-cell.list-cell:hover{} +.menu .cell.indexed-cell.list-cell:selected{} +.menu .cell.indexed-cell.list-cell:selected .nav-item{ + -fx-background-color: rgba(0,0,0,0.1); +} +.menu .cell.indexed-cell.list-cell:selected .name-label{ + -fx-text-fill: #6690FF; +} +.menu .cell.indexed-cell.list-cell:selected .icon-label > .ikonli-font-icon{ + -fx-icon-color: #6690FF; +} \ No newline at end of file diff --git a/src/main/resources/css/test.css b/src/main/resources/css/test.css deleted file mode 100644 index 4e55547..0000000 --- a/src/main/resources/css/test.css +++ /dev/null @@ -1 +0,0 @@ -/*例子后续移除*/ \ No newline at end of file -- Gitee