package com.fine.theme.utils; import com.fine.swing.ui.layout.Column; import com.fine.swing.ui.layout.Layouts; import com.fine.swing.ui.layout.Row; import com.fine.swing.ui.layout.Spacer; import com.fr.design.constants.LayoutConstants; import com.fr.design.foldablepane.UIExpandablePane; import com.fr.log.FineLoggerFactory; import com.fr.stable.collections.combination.Pair; import javax.swing.JPanel; import java.awt.BorderLayout; import java.awt.Component; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; import static com.fine.swing.ui.layout.Layouts.cell; /** * 设计器典型布局构建器 * * @author Levy.Xie * @since 11.0 * Created on 2024/05/08 */ public class FineLayoutBuilder { /** * 创建标准行列表格布局,行内元素均匀分布 * * @param elePerRow 每行元素数 * @param rowSpacing 行内间距 * @param colSpacing 列内间距 * @param componentList 组件 * @return 表格面板 */ public static Column createCommonTableLayout(int elePerRow, int rowSpacing, int colSpacing, List componentList) { int rowNum = componentList.size() / elePerRow + 1; Iterator iterator = componentList.iterator(); Column column = new Column(); column.setSpacing(colSpacing); Row currentRow; for (int i = 0; i < rowNum; i++) { currentRow = new Row(); currentRow.setSpacing(rowSpacing); for (int j = 0; j < elePerRow; j++) { Layouts.populate(currentRow, cell( iterator.hasNext() ? iterator.next() : new Spacer(1) ).weight(1)); } column.add(currentRow); } return column; } /** * 兼容TableLayout配置项,生成网格布局面板 * * @param colSpacing 间距 * @param components 组件二维数组,内部每个一维数组均为行内组件,一维数组元素需与weight严格对应 * @param weight 行内权重列表,形如[0.4,0.6] 即首个元素占比0.4,第二个元素占比0.6 * @return 面板 */ public static JPanel compatibleTableLayout(int colSpacing, Component[][] components, double[] weight) { Column column = new Column(); column.setSpacing(colSpacing); try { for (Component[] componentArray : components) { Row row = new Row(); List visibleComponents = Arrays.stream(componentArray) .filter(com -> com != null && com.isVisible()).collect(Collectors.toList()); if (!visibleComponents.isEmpty()) { // 仅当存在可见组件时处理布局 dealWithVisibleComponents(weight, column, componentArray, row, visibleComponents); } } return asBorderLayoutWrapped(column); } catch (Exception e) { FineLoggerFactory.getLogger().error(e, "[Designer] create layout failed."); } return new JPanel(); } /** * 典型的左右网格布局,竖向间距为典型间距,标签及组件比例采用典型比例 * * @param components 组件,两列多行 * @return 面板 */ public static JPanel commonLeftRightLayout(Component[][] components) { return compatibleTableLayout(LayoutConstants.VERTICAL_GAP, components, new double[]{LayoutConstants.LEFT_WEIGHT, LayoutConstants.RIGHT_WEIGHT}); } private static void dealWithVisibleComponents(double[] weight, Column column, Component[] value, Row row, List components) { if (components.size() == 1 && value[0] != null) { // 仅存在首个元素,则该元素自适应占满整行 Layouts.populate(row, cell(components.get(0)).weight(1)); } else { // 其他场景,按权重分配布局,以适配原TableLayout形式 for (int j = 0; j < value.length; j++) { Component component = value[j]; if (component == null) { component = new Spacer(1); } Layouts.populate(row, cell(component).weight(weight[j])); } } column.add(row); } /** * 创建竖向排列的扩展面板列表 * * @param spacing 间距 * @param elements 面板元素,含标题、面板 * @return 竖向排列面板 */ @SafeVarargs public static Column createVerticalExpandPaneLayout(int spacing, Pair... elements) { UIExpandablePane[] panes = IntStream.range(0, elements.length) .mapToObj(i -> { Pair pair = elements[i]; if (i != elements.length - 1) { return new UIExpandablePane(pair.getFirst(), pair.getSecond(), true); } return new UIExpandablePane(pair.getFirst(), pair.getSecond()); }) .toArray(UIExpandablePane[]::new); return createVerticalLayout(spacing, panes); } /** * 创建垂直布局面板 * * @param spacing 间距 * @param elements 面板元素 * @return 面板 */ public static Column createVerticalLayout(int spacing, Component... elements) { Column column = new Column(); column.setSpacing(spacing); for (Component element : elements) { column.add(element); } return column; } /** * 创建水平布局面板 * * @param spacing 间距 * @param elements 面板元素 * @return 面板 */ public static Row createHorizontalLayout(int spacing, double[] weight, Component... elements) { Row row = new Row(); row.setSpacing(spacing); for (int i = 0; i < elements.length; i++) { Layouts.populate(row, cell(elements[i]).weight(weight[i])); } return row; } /** * 创建水平布局面板 * * @param spacing 间距 * @param elements 面板元素 * @return 面板 */ public static Row createHorizontalLayout(int spacing, Component... elements) { Row row = new Row(); row.setSpacing(spacing); for (Component element : elements) { Layouts.populate(row, cell(element)); } return row; } /** * 组件包装于BorderLayout中 * * @param component 组件 * @return 包装后的面板 */ public static JPanel asBorderLayoutWrapped(Component component) { JPanel panel = new JPanel(new BorderLayout()); panel.add(component); return panel; } }