最终效果
实现逻辑
整体布局
整个页面最外层的布局使用HBox
进行布局,也就是水平布局,该布局中主要放置两部分,第一部分就是我们左边的菜单,第二部分就是右侧的动态页面部分。
左侧菜单
左侧菜单布局由于使用的是垂直菜单,因此使用了VBox
进行布局,颜色设置为#303133
,里面的菜单项是使用的Button
组件来实现的,重写了按钮的背景色、文字颜色、鼠标移入移出和点击选中的样式和监听事件。目前实现的是移动到菜单项时背景色变为黑色,文字变为黄色,点击后被选中的菜单文字一直显示黄色直到其他选中。
右侧页面
在整体布局中需要注意,在设置右侧页面时需要将HBox
的hgrow
也就是自组件的横向优先级设置为永远,向下面这样:
HBox.setHgrow(currentPageNode, Priority.ALWAYS);
这样可以确保右侧页面的宽度自动为最大宽度,右侧的页面的高度不用指定,因为默认会使用父组件的最大高度,也就是整体布局HBox
的高度。
页面的切换
我这里切换页面时给左侧的Button
增加了点击事件,然后根据点击的按钮通过一个自定义的工厂方法匹配跳转对应的页面,这里的三个示例页面会返回一个Node对象,然后在主页面中动态的将Node设置为右侧的页面。
页面接口工厂
/**
* 页面创建工厂
* @author huhailong
*
*/
public class PageFactory {
public static IPageService createPageService(String itemName) {
IPageService pageService = null;
switch(itemName) {
case "个人中心":
pageService = new UserPage();
break;
case "健康统计":
pageService = new HealthStatistics();
break;
case "增加记录":
pageService = new AddReport();
break;
default:
pageService = new UserPage();
break;
}
return pageService;
}
}
页面接口
/**
* 页面接口
* @author huhailong
*
*/
public interface IPageService {
Node generatePage(Pane root);
}
个人中心页面
/**
* 用户个人中心页面
* @author huhailong
*
*/
public class UserPage implements IPageService {
@Override
public Node generatePage(Pane root) {
VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER);
Label test = new Label("个人中心页面");
StyleUtil.setFont(test, Color.BLACK, 20);
vbox.getChildren().add(test);
return vbox;
}
}
上述只是目前一个简单的演示代码,还有待优化。
页面跳转方法
然后在主页面中添加了一个页面跳转方法
/**
* 右侧页面路由
*/
private Node routePage(Pane root, String itemName) {
return PageFactory.createPageService(itemName).generatePage(root);
}
最终在点击事件中调用该方法即可。
完整代码
仓库地址: https://gitee.com/hlovez/health-manager.git
项目结构:
src
├── app
│ ├── RunApplication.java
│ ├── utils
│ │ ├── DataUtil.java
│ │ ├── ProjectValues.java
│ │ └── StyleUtil.java
│ └── views
│ ├── PageFactory.java
│ └── service
│ ├── IPageService.java
│ └── impl
│ ├── AddReport.java
│ ├── HealthStatistics.java
│ └── UserPage.java
└── module-info.java
module-info.java
module ptu {
requires javafx.controls;
opens app;
}
RunApplication.java (主类)
package app;
import java.util.ArrayList;
import java.util.List;
import app.utils.DataUtil;
import app.utils.ProjectValues;
import app.utils.StyleUtil;
import app.views.PageFactory;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
/**
* PTU启动类
*
* @author huhailong
*
*/
public class RunApplication extends Application {
private HBox root;
private Node currentPageNode = null;
private VBox leftMenu;
private Integer currentMenuIndex;
private Integer tempIndex;
@Override
public void start(Stage primaryStage) throws Exception {
double screenWidth = Screen.getPrimary().getBounds().getWidth();
double screenHeight = Screen.getPrimary().getBounds().getHeight();
root = new HBox();
leftMenu = (VBox) getLeftMenu(root);
root.getChildren().add(leftMenu);
currentPageNode = PageFactory.createPageService("个人中心").generatePage(root);
HBox.setHgrow(currentPageNode, Priority.ALWAYS);
root.getChildren().add(currentPageNode);
StyleUtil.setPaneBackground(root, Color.WHITE);
Scene scene = new Scene(root, screenWidth * 0.8, screenHeight * 0.8);
primaryStage.setTitle("健康管理");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* 获取左侧菜单栏
*/
private Node getLeftMenu(Pane root) {
double leftWidth = ProjectValues.leftMenuWidth;
VBox vbox = new VBox();
vbox.setMinHeight(root.getPrefHeight());
vbox.setMinWidth(leftWidth);
StyleUtil.setPaneBackground(vbox, Color.web(ProjectValues.COLOR_PRIMARY));
// 增加菜单中的项目
vbox.getChildren().addAll(getLeftMenuItemList(leftWidth));
return vbox;
}
/**
* 右侧页面路由
*/
private Node routePage(Pane root, String itemName) {
return PageFactory.createPageService(itemName).generatePage(root);
}
/**
* 生成左侧菜单按钮
*/
private List<Button> getLeftMenuItemList(double width) {
double buttonHeight = 30;
List<Button> buttonList = new ArrayList<>(3);
String[] itemNames = { "个人中心", "健康统计", "增加记录" };
for (String name : itemNames) {
Button button = new Button(name);
button.setMinWidth(width);
button.setMinHeight(buttonHeight);
StyleUtil.setButtonBackground(button, Color.web(ProjectValues.COLOR_PRIMARY), Color.WHITE);
//增加鼠标移动到菜单上到hover效果
button.setOnMouseMoved(event->{StyleUtil.setButtonBackground(button, Color.BLACK, Color.WHITE);StyleUtil.setFont(button, Color.web("#E6A23C"), -1);});
button.setOnMouseExited(event->{
if(currentMenuIndex==null||!button.getText().equals(itemNames[currentMenuIndex])) {
StyleUtil.setButtonBackground(button, Color.web(ProjectValues.COLOR_PRIMARY), Color.WHITE);
}else {
StyleUtil.setButtonBackground(button, Color.web(ProjectValues.COLOR_PRIMARY), Color.web(ProjectValues.COLOR_SELECTED));
}
});
button.setOnMouseClicked(event->{
currentMenuIndex = DataUtil.getIndexForArray(itemNames,button.getText());
currentPageNode = routePage(root,name);
root.getChildren().remove(1); //清楚右侧页面路由组件节点
HBox.setHgrow(currentPageNode, Priority.ALWAYS);
root.getChildren().add(currentPageNode);
StyleUtil.setFont(button, Color.web(ProjectValues.COLOR_SELECTED), -1);
//选中状态逻辑
if(tempIndex!=null) {
Button node = (Button) leftMenu.getChildren().get(tempIndex);
StyleUtil.setFont(node, Color.WHITE, -1); //清空选中状态样式
StyleUtil.setButtonBackground(node, Color.web(ProjectValues.COLOR_PRIMARY), Color.WHITE);
}
StyleUtil.setFont(button, Color.web(ProjectValues.COLOR_SELECTED), -1); //设置选中样式
tempIndex = currentMenuIndex;
});
buttonList.add(button);
}
return buttonList;
}
public static void main(String[] args) {
launch();
}
}
utils.DataUtil.java (后续的数据处理工具类)
/**
* 数据处理工具
* @author huhailong
*
*/
public class DataUtil {
public static int getIndexForArray(String[]array, String item) {
for(int i=0; i<array.length; i++) {
if(array[i].equals(item)) {
return i;
}
}
return -1;
}
}
utils.ProjectValues.java (项目中常用到的一些字符串常量)
package app.utils;
/**
* 常用值
* @author huhailong
*
*/
public class ProjectValues {
public static String COLOR_PRIMARY = "#303133"; //主题色
public static String COLOR_SELECTED = "#E6A23C"; //被选中颜色
public static double leftMenuWidth = 240; //左侧菜单宽度
}
utils.StyleUtil.java (后续的样式工具类)
/**
* 样式工具类
*
* @author huhailong
*
*/
public class StyleUtil {
public static void setPaneBackground(Pane pane, Color color) {
pane.setBackground(new Background(new BackgroundFill(color, null, null)));
}
public static void setButtonBackground(Button button, Color bg, Color text) {
button.setBackground(new Background(new BackgroundFill(bg, null, null)));
button.setTextFill(text);
button.setCursor(Cursor.HAND);
BorderStroke borderStroke = new BorderStroke(null, null, Color.BLACK, null, null, null, BorderStrokeStyle.SOLID,
null, null, null, null);
button.setBorder(new Border(borderStroke));
button.setPadding(new Insets(10));
}
public static void setFont(Labeled node, Color color, double fontSize) {
node.setTextFill(color);
node.setFont(Font.font(null, FontWeight.BOLD, fontSize));
}
}
views.PageFactory.java (页面工厂类)
后续使用枚举等方法进行再次优化
package app.views;
import app.views.service.IPageService;
import app.views.service.impl.AddReport;
import app.views.service.impl.HealthStatistics;
import app.views.service.impl.UserPage;
/**
* 页面创建工厂
* @author huhailong
*
*/
public class PageFactory {
public static IPageService createPageService(String itemName) {
IPageService pageService = null;
switch(itemName) {
case "个人中心":
pageService = new UserPage();
break;
case "健康统计":
pageService = new HealthStatistics();
break;
case "增加记录":
pageService = new AddReport();
break;
default:
pageService = new UserPage();
break;
}
return pageService;
}
}
views.service.IPageService.java (页面接口)
package app.views.service;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
/**
* 页面接口
* @author huhailong
*
*/
public interface IPageService {
Node generatePage(Pane root);
}
views.service.impl.UserPage.java (个人中心页面类)
package app.views.service.impl;
import app.utils.StyleUtil;
import app.views.service.IPageService;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
/**
* 用户个人中心页面
* @author huhailong
*
*/
public class UserPage implements IPageService {
@Override
public Node generatePage(Pane root) {
VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER);
Label test = new Label("个人中心页面");
StyleUtil.setFont(test, Color.BLACK, 20);
vbox.getChildren().add(test);
return vbox;
}
}
其余两个页面类似,此处代码省略。
完整项目代码: https://gitee.com/hlovez/health-manager.git
❤️ ❤️ ❤️ ❤️ ❤️ 如果本文对你有一点点的帮助请点个大大赞👍 ❤️ ❤️ ❤️ ❤️ ❤️