自定义的多级下拉框选择列表

在前端经常有多级的下拉框选择,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()));
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
其他源码技术文章

JDK1.7、JavaFx自定义日期选择器

2023-2-28 12:36:24

其他源码

全新热搜热门榜内容系统聚合源码

2023-4-28 11:35:03

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索