在前端经常有多级的下拉框选择,javafx想要实现也就自定义了一个。
节点基础
import javafx.scene.control.ComboBox;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import yu.lian.fx.common.xfx.node.MyNode;
/**
* <p>
* 节点基础
* </p>
*
* @author xj
* @since 2023/3/1 20:51
*/
public class BaseNode extends HBox {
/** 单选按钮组 */
protected static ToggleGroup TG = new ToggleGroup();
/** 保留选择框进行赋值 */
public static ComboBox<MyNode> comboBox;
}
ListView使用的节点
import javafx.scene.control.RadioButton;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import lombok.Getter;
import yu.lian.fx.common.xfx.base.BaseNode;
import yu.lian.fx.common.xfx.components.MyLabel;
import yu.lian.fx.common.xfx.util.XjImageUtil;
import yu.lian.fx.common.xfx.util.XjStageUtil;
import java.util.List;
/**
* <p>
* ListView使用的节点
* </p>
*
* @author xj
* @since 2023/3/1 20:41
*/
@Getter
public class ListNode extends BaseNode {
/** 节点显示的名称 */
String name;
/** 节点实际的值 */
Long valueId;
/** 节点当前级别 */
Integer level;
/** 节点统一的禁用级别 */
Integer disableLevel;
/** 当前节点的单项按钮 */
RadioButton radioButton;
/** 0-disableLevel判断 当前节点小于禁用节点时按钮被禁用,1-childrenList判断 当没有子集的时候才可被选择 */
Integer radioType;
/** 子集数据 */
List<ListNode> childrenList;
/**
* 构造ListNode
* @param name 显示存储值
* @param valueId 实际存储值
* @param level 当前级别
* @param disableLevel 禁用级别
* @param radioType 禁用判断
* @param childrenList 子集数据
*/
public ListNode(String name, Long valueId, Integer level, Integer disableLevel, Integer radioType,
List<ListNode> childrenList) {
this.name = name;
this.valueId = valueId;
this.level = level;
this.disableLevel = disableLevel;
this.radioType = radioType;
// 设置子集数据
setChildrenList(childrenList);
// 初始化数据
init();
}
/**
* 设置子集数据
* @param childrenList 子集数据
*/
public void setChildrenList(List<ListNode> childrenList) {
this.childrenList = childrenList;
if (childrenList != null && childrenList.size() > 0) {
// 判断子集初始化图标或禁用选项
initChildrenList();
}
}
/**
* 初始化
*/
private void init() {
// 创建按钮
radioButton = new RadioButton();
// 添加按钮组
radioButton.setToggleGroup(TG);
// 判断禁用类型和禁用级别
if (radioType == 0 && level < disableLevel) {
radioButton.setDisable(true);
}
// 设置按钮的选择事件
radioButton.selectedProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("被选择:"+name);
// 设置下拉框的节点
MyNode myNode = new MyNode(name, valueId);
// 填充节点至下拉框
comboBox.getItems().add(myNode);
comboBox.getSelectionModel().select(myNode);
// 设置定好的窗体关闭
XjStageUtil.getStage("listViewStage").close();
});
// 设置标签显示值
MyLabel label = new MyLabel(name, 16);
getChildren().addAll(radioButton, label);
}
/**
* 判断子集初始化图标或禁用选项
*/
private void initChildrenList() {
// 判断禁用类型
if (radioType == 1) {
radioButton.setDisable(true);
}
// 有子集数据就显示下一级的图标,设置一个hBox是用来填充中间隔开两边的组件
HBox hBox = new HBox();
HBox.setHgrow(hBox, Priority.ALWAYS);
getChildren().addAll(hBox, XjImageUtil.createImage(20, "/static/image/right.png"));
}
}
我的节点
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 我的节点,可以自定义需要的数据
* </p>
*
* @author xj
* @since 2023/2/23 20:12
*/
@Getter
@Setter
public class MyNode {
/** 树节点显示的名称 */
String name;
/** 树节点的id */
Long id;
public MyNode(String name, Long id) {
this.name = name;
this.id = id;
}
@Override
public String toString() {
// TreeView的节点默认就是对象的toString,所以定义name输出
return name;
}
}
ListView相关工具类
import javafx.beans.binding.Bindings;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.control.ListView;
import javafx.scene.text.Text;
import yu.lian.fx.common.xfx.node.ListNode;
/**
* <p>
* xj-fx-ListView相关工具类
* </p>
*
* @author xj
* @since 2023/3/1 21:32
*/
public class XjListViewUtil {
/**
* 创建listView视图
* @param data 数据
* @param changeListener 更改侦听器
* @return listView视图
*/
public static ListView<ListNode> createListView(ObservableList<ListNode> data,
ChangeListener<ListNode> changeListener) {
// 创建listView
ListView<ListNode> listView = new ListView<>(data);
listView.setStyle("-fx-background-color: transparent;-fx-border-color: black");
// 设置listView的宽度根据文本
DoubleBinding widthBinding = Bindings.createDoubleBinding(() -> {
double maxTextWidth = 0;
for (ListNode item : data) {
Text text = new Text(item.getName());
maxTextWidth = Math.max(maxTextWidth, text.getLayoutBounds().getWidth());
}
return maxTextWidth + 100;
}, data);
listView.prefWidthProperty().bind(widthBinding);
listView.setPrefHeight(300);
listView.getSelectionModel().selectedItemProperty().addListener(changeListener);
return listView;
}
}
Stage相关工具类
import javafx.stage.Stage;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* <p>
* xj-fx-Stage相关工具类
* </p>
*
* @author xj
* @since 2023/2/21 20:24
*/
public class XjStageUtil {
/** 系统内窗体的map */
private final static Map<String, Stage> STAGE_MAP = new ConcurrentHashMap<>();
/**
* 获得窗体
* @param key key
* @return 窗体
*/
public static Stage getStage(String key) {
return STAGE_MAP.get(key);
}
/**
* 移除指定窗体
* @param key key
*/
public static void removeStage(String key) {
STAGE_MAP.remove(key);
}
/**
* 设置指定窗体
* @param key key
* @param stage 窗体
*/
public static void putStage(String key, Stage stage) {
removeStage(key);
STAGE_MAP.put(key, stage);
}
}
自定义的多级下拉框选择列表
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import yu.lian.fx.common.xfx.base.BaseNode;
import yu.lian.fx.common.xfx.node.ListNode;
import yu.lian.fx.common.xfx.node.MyNode;
import yu.lian.fx.common.xfx.util.XjListViewUtil;
import yu.lian.fx.common.xfx.util.XjStageUtil;
/**
* <p>
* MultistageBox 自定义的多级下拉框选择列表
* </p>
*
* @author xj
* @since 2023/3/1 21:17
*/
public class MultistageBox extends HBox {
/** 选择框 */
ComboBox<MyNode> comboBox;
/** 焦点计数 */
int focusedCount;
/** 坐标 */
double x,y;
/**
* 构造MultistageBox
* @param title SelectBox的标题
* @param list 数据
*/
public MultistageBox(String title, ObservableList<ListNode> list) {
// 定义我们自己的下拉框
SelectBox<MyNode> selectBox;
getChildren().add(selectBox = new SelectBox<>(title));
// 获取自己下拉框内部的选择框
comboBox = selectBox.getComboBox();
BaseNode.comboBox = comboBox;
init(list);
}
/**
* 获得下拉框的值
* @return 下拉框的值
*/
public Long getValue() {
return comboBox.getSelectionModel().getSelectedItem().getId();
}
/**
* 初始化
* @param list 数据
*/
public void init(ObservableList<ListNode> list) {
// 设置选择框内部事件隐藏
comboBox.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
// 焦点计数
focusedCount = 0;
// 设置选择框不显示下拉框
comboBox.hide();
// 记录坐标
x = mouseEvent.getScreenX() - mouseEvent.getX();
y = mouseEvent.getScreenY() - mouseEvent.getY();
// 设置内部横窗
HBox hBox = new HBox();
Pane pane = new Pane();
ListView<ListNode> listView = XjListViewUtil.createListView(list, new ChangeListener<ListNode>() {
@Override
public void changed(ObservableValue<? extends ListNode> observable, ListNode oldValue,
ListNode newValue) {
// 移除子集列表
hBox.getChildren().remove(newValue.getLevel(), hBox.getChildren().size());
// 如果存在子集
if (newValue.getChildrenList() != null && newValue.getChildrenList().size() > 0) {
// 创建子集list
ListView<ListNode> listView = XjListViewUtil.createListView(
FXCollections.observableList(newValue.getChildrenList()), this);
hBox.getChildren().add(listView);
}
}
});
hBox.getChildren().addAll(listView);
pane.getChildren().add(hBox);
Stage selectStage = new Stage();
XjStageUtil.putStage("listViewStage", selectStage);
selectStage.focusedProperty().addListener((observableValue, aBoolean, t) -> {
if (selectStage.isShowing() && focusedCount != 0) {
XjStageUtil.removeStage("listViewStage");
selectStage.close();
}
focusedCount++;
});
// 隐藏默认标题栏
selectStage.initStyle(StageStyle.TRANSPARENT);
selectStage.setX(x);
selectStage.setY(y + 30);
selectStage.setScene(new Scene(pane, 0, 300));
selectStage.show();
}
});
}
}
使用方式
MultistageBox multistageBox = new MultistageBox("", FXCollections.observableArrayList(new ListNode()));
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。