最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?Swing自定義實(shí)現(xiàn)組件與表單工具

 更新時(shí)間:2026年05月18日 08:53:24   作者:RainCity  
Swing 原生組件缺少一些常用的便捷方法,使用本文介紹了兩個(gè)Java?Swing實(shí)用工具類ComponentUtils和FormPanelUtils,ComponentUtils提供了通用組件操作封裝,FormPanelUtils則專注于表單布局,感興趣的可以了解下

一、這兩個(gè)類解決什么問題

Swing 原生組件缺少一些常用的便捷方法,比如:

  • 統(tǒng)一文本框的邊框和聚焦樣式
  • 快速創(chuàng)建帶邊框的面板
  • 表單中常用的“標(biāo)簽 + 組件”一行添加
  • 安全執(zhí)行后臺任務(wù)(SwingWorker)

ComponentUtilsFormPanelUtils 就是對這類操作的封裝。

兩個(gè)類的職責(zé)劃分:

職責(zé)
ComponentUtils通用組件操作:文本框創(chuàng)建、邊框設(shè)置、Tab標(biāo)簽、SwingWorker封裝
FormPanelUtils表單布局專用:標(biāo)簽+組件一行添加、表單元素快速創(chuàng)建

二、ComponentUtils 源碼

import cn.hutool.core.util.ArrayUtil;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 組件工具類
 * 封裝 Swing 組件的常用操作
 *
 * 使用示例:
 * 1. 創(chuàng)建統(tǒng)一樣式的文本框:
 *    JTextField textField = ComponentUtils.createTextField();
 * 2. 創(chuàng)建 Tab 標(biāo)簽:
 *    JLabel tab = ComponentUtils.createTabLabel("用戶管理", 16, "#409EFF", true);
 * 3. 執(zhí)行后臺任務(wù):
 *    ComponentUtils.handleSwingWorker(() -> service.getData(), result -> table.setData(result));
 */
public class ComponentUtils {

    // ==================== 鼠標(biāo)光標(biāo) ====================

    /**
     * 給組件添加鼠標(biāo)移入時(shí)變成手型光標(biāo)的功能
     * @param component 目標(biāo)組件
     */
    public static void addComponentCursor(Component component) {
        if (null == component) return;
        component.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                component.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            }

            @Override
            public void mouseExited(MouseEvent e) {
                component.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        });
    }

    // ==================== 尺寸設(shè)置 ====================

    /**
     * 設(shè)置組件首選大小
     * @param component 目標(biāo)組件
     * @param width 寬度
     * @param height 高度
     */
    public static void setSize(JComponent component, int width, int height) {
        Dimension size = new Dimension(width, height);
        component.setPreferredSize(size);
        component.setMinimumSize(size);
        component.setMaximumSize(size);
    }

    // ==================== 邊框設(shè)置 ====================

    /**
     * 為組件設(shè)置帶標(biāo)題的邊框和內(nèi)邊距
     * @param component 目標(biāo)組件
     * @param title 邊框標(biāo)題
     * @param top 上內(nèi)邊距
     * @param left 左內(nèi)邊距
     * @param bottom 下內(nèi)邊距
     * @param right 右內(nèi)邊距
     */
    public static void setBorder(JComponent component, String title, int top, int left, int bottom, int right) {
        EmptyBorder emptyBorder = new EmptyBorder(top, left, bottom, right);
        TitledBorder titledBorder = new TitledBorder(title);
        Border compoundBorder = BorderFactory.createCompoundBorder(emptyBorder, titledBorder);
        component.setBorder(compoundBorder);
    }

    /**
     * 創(chuàng)建帶標(biāo)題的邊框(僅邊框,不設(shè)置到組件)
     * @param title 邊框標(biāo)題
     * @return 邊框?qū)ο?
     */
    public static Border createTitleEmptyBorder(String title) {
        TitledBorder titledBorder = BorderFactory.createTitledBorder(title);
        titledBorder.setBorder(BorderFactory.createEmptyBorder());
        // 這里的字體根據(jù)項(xiàng)目修改
        titledBorder.setTitleFont(new Font("Serif", Font.BOLD + Font.ITALIC, 16));
        Border paddingBorder = new EmptyBorder(5, 10, 5, 10);
        return BorderFactory.createCompoundBorder(titledBorder, paddingBorder);
    }

    // ==================== Tab 標(biāo)簽 ====================

    /**
     * 創(chuàng)建 Tab 標(biāo)簽
     * @param text 標(biāo)簽文字
     * @param fontSize 字體大小
     * @param hexColor 激活時(shí)的字體顏色(十六進(jìn)制,如 "#409EFF")
     * @param active 是否激活
     * @return 標(biāo)簽組件
     */
    public static JLabel createTabLabel(String text, int fontSize, String hexColor, boolean active) {
        JLabel label = new JLabel(text);
        label.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
        label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        label.setFont(new Font("Microsoft YaHei", Font.PLAIN, fontSize));
        label.setHorizontalAlignment(SwingConstants.CENTER);
        label.setOpaque(true);
        if (active) {
            label.setForeground(Color.decode(hexColor));
            label.setBackground(Color.WHITE);
        } else {
            label.setForeground(Color.decode("#333333"));
            label.setBackground(Color.decode("#F2F3F5"));
        }
        return label;
    }

    /**
     * 創(chuàng)建可點(diǎn)擊的 Tab 標(biāo)簽
     * @param text 標(biāo)簽文字
     * @param fontSize 字體大小
     * @param hexColor 激活時(shí)的字體顏色
     * @param active 是否激活
     * @param runnable 點(diǎn)擊事件
     * @return 標(biāo)簽組件
     */
    public static JLabel createTabLabel(String text, int fontSize, String hexColor, boolean active, Runnable runnable) {
        JLabel label = createTabLabel(text, fontSize, hexColor, active);
        label.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                CallbackProcessor.run(runnable);
            }
        });
        return label;
    }

    // ==================== 文本框 ====================

    private static void setTextFieldBorder(JTextField textField) {
        Border border = BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1, true),
                BorderFactory.createEmptyBorder(0, 10, 0, 10)
        );
        textField.setBorder(border);
        textField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                textField.setBorder(BorderFactory.createCompoundBorder(
                        BorderFactory.createLineBorder(Color.decode("#98C3EB"), 2, true),
                        BorderFactory.createEmptyBorder(0, 10, 0, 10)
                ));
            }

            @Override
            public void focusLost(FocusEvent e) {
                textField.setBorder(border);
            }
        });
    }

    /**
     * 創(chuàng)建統(tǒng)一樣式的文本框
     * @return 文本框
     */
    public static JTextField createTextField() {
        JTextField textField = new JTextField();
        setTextFieldBorder(textField);
        return textField;
    }

    /**
     * 創(chuàng)建帶默認(rèn)文本的文本框
     * @param text 默認(rèn)文本
     * @return 文本框
     */
    public static JTextField createTextField(String text) {
        JTextField textField = createTextField();
        textField.setText(text);
        return textField;
    }

    /**
     * 創(chuàng)建密碼框
     * @return 密碼框
     */
    public static JPasswordField createPasswordField() {
        JPasswordField passwordField = new JPasswordField();
        setTextFieldBorder(passwordField);
        return passwordField;
    }

    /**
     * 創(chuàng)建帶默認(rèn)文本的密碼框
     * @param text 默認(rèn)文本
     * @return 密碼框
     */
    public static JPasswordField createPasswordField(String text) {
        JPasswordField passwordField = new JPasswordField(text);
        setTextFieldBorder(passwordField);
        return passwordField;
    }

    // ==================== 中文字符處理 ====================

    /**
     * 計(jì)算文本實(shí)際渲染寬度(中英文混合)
     * @param text 文本
     * @param fm 字體度量
     * @return 寬度(像素)
     */
    public static int calculateTextWidth(String text, FontMetrics fm) {
        int width = 0;
        for (char c : text.toCharArray()) {
            if (isChineseChar(c)) {
                width += fm.charWidth('中');
            } else if (Character.isLetterOrDigit(c)) {
                width += fm.charWidth(c);
            } else {
                width += fm.charWidth(c);
            }
        }
        return width;
    }

    /**
     * 判斷字符是否為中文字符
     * @param c 字符
     * @return 是中文返回 true
     */
    public static boolean isChineseChar(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
    }

    // ==================== 窗口切換 ====================

    /**
     * 平滑切換窗口(先顯示新窗口,延遲隱藏舊窗口)
     * @param show 顯示窗口的回調(diào)
     * @param hide 隱藏窗口的回調(diào)
     */
    public static void smoothSwitch(Runnable show, Runnable hide) {
        SwingUtilities.invokeLater(() -> {
            CallbackProcessor.run(show);
            Timer timer = new Timer(100, e -> CallbackProcessor.run(hide));
            timer.setRepeats(false);
            timer.start();
        });
    }

    // ==================== 標(biāo)題標(biāo)簽 ====================

    /**
     * 創(chuàng)建標(biāo)題標(biāo)簽
     * @param title 標(biāo)題文字
     * @return 標(biāo)題標(biāo)簽
     */
    public static JLabel createTitleLabel(String title) {
        return createTitleLabel(title, new Font("Microsoft YaHei", Font.BOLD, 20));
    }

    /**
     * 創(chuàng)建標(biāo)題標(biāo)簽(可指定字體)
     * @param title 標(biāo)題文字
     * @param font 字體
     * @return 標(biāo)題標(biāo)簽
     */
    public static JLabel createTitleLabel(String title, Font font) {
        JLabel titleLabel = new JLabel(title);
        titleLabel.setFont(font);
        // 這里的圖片就是獲取一個(gè)ImageIcon
        // titleLabel.setIcon();
        return titleLabel;
    }

    // ==================== 包裹層面板 ====================

    /**
     * 創(chuàng)建帶圓角背景的包裹面板
     * @param layout 布局管理器
     * @return 面板
     */
    public static JPanel createWrapPanel(LayoutManager layout) {
        JPanel wrapPanel = new JPanel(layout);
        // FlatLaf 圓角樣式,不使用 FlatLaf 可注釋
        wrapPanel.putClientProperty("FlatLaf.style", "arc: 30;");
        wrapPanel.setBackground(Color.WHITE);
        return wrapPanel;
    }

    /**
     * 創(chuàng)建帶圓角背景的包裹面板(BorderLayout)
     * @return 面板
     */
    public static JPanel createWrapPanel() {
        return createWrapPanel(new BorderLayout());
    }

    /**
     * 創(chuàng)建固定高度的包裹面板
     * @param height 高度
     * @return 面板
     */
    public static JPanel createWrapPanel(int height) {
        JPanel wrapPanel = createWrapPanel(new BorderLayout());
        wrapPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, height));
        wrapPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, height));
        return wrapPanel;
    }

    /**
     * 創(chuàng)建固定高度的包裹面板(指定布局)
     * @param layout 布局管理器
     * @param height 高度
     * @return 面板
     */
    public static JPanel createWrapPanel(LayoutManager layout, int height) {
        JPanel wrapPanel = createWrapPanel(layout);
        wrapPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, height));
        wrapPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, height));
        return wrapPanel;
    }

    // ==================== SwingWorker 封裝 ====================

    /**
     * 執(zhí)行后臺任務(wù)(有返回值),完成后在 EDT 執(zhí)行回調(diào)
     * @param doInBackground 后臺任務(wù)
     * @param doneAction 完成后的回調(diào)(在 EDT 執(zhí)行)
     * @param <T> 返回值類型
     */
    public static <T> void handleSwingWorker(Supplier<T> doInBackground, Consumer<T> doneAction) {
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            T result;

            @Override
            protected Void doInBackground() {
                Optional<T> optional = CallbackProcessor.get(doInBackground);
                result = optional.orElse(null);
                return null;
            }

            @Override
            protected void done() {
                CallbackProcessor.accept(doneAction, result);
            }
        };
        worker.execute();
    }

    /**
     * 執(zhí)行后臺任務(wù)(無返回值),完成后在 EDT 執(zhí)行回調(diào)
     * @param doInBackground 后臺任務(wù)
     * @param doneAction 完成后的回調(diào)(在 EDT 執(zhí)行)
     */
    public static void handleSwingWorker(Runnable doInBackground, Runnable doneAction) {
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() {
                CallbackProcessor.run(doInBackground);
                return null;
            }

            @Override
            protected void done() {
                CallbackProcessor.run(doneAction);
            }
        };
        worker.execute();
    }

    // ==================== 透明設(shè)置 ====================

    /**
     * 遞歸設(shè)置組件及其所有子面板的透明屬性
     * @param parent 父組件
     * @param opaque false 為透明,true 為不透明
     */
    public static void setOpaque(JComponent parent, boolean opaque) {
        Component[] components = parent.getComponents();
        if (ArrayUtil.isEmpty(components)) {
            parent.setOpaque(opaque);
            return;
        }
        for (Component component : components) {
            if (component instanceof JPanel) {
                ((JPanel) component).setOpaque(opaque);
                setOpaque((JPanel) component, opaque);
            }
        }
    }
}

三、FormPanelUtils 源碼

import cn.hutool.core.util.StrUtil;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
 * 表單面板工具類
 * 封裝表單布局的常用操作(標(biāo)簽+組件一行添加、數(shù)字輸入框等)
 *
 * 使用示例:
 * 1. 添加一行標(biāo)簽+組件:
 *    FormPanelUtils.addLabelAndTextField(panel, "用戶名:", textField, null);
 * 2. 創(chuàng)建數(shù)字輸入框:
 *    JTextField numberField = FormPanelUtils.getNumberField();
 */
public class FormPanelUtils {

    // ==================== 標(biāo)簽 ====================

    /**
     * 創(chuàng)建標(biāo)簽
     * @param text 標(biāo)簽文字
     * @return 標(biāo)簽
     */
    public static JLabel getLabel(String text) {
        return getLabel(text, null);
    }

    /**
     * 創(chuàng)建帶圖標(biāo)的標(biāo)簽
     * @param text 標(biāo)簽文字
     * @param iconPath 圖標(biāo)路徑
     * @return 標(biāo)簽
     */
    public static JLabel getLabel(String text, String iconPath) {
        JLabel label = new JLabel(text);
        if (null != iconPath) {
            // 需自己獲取圖片
            // label.setIcon();
        }
        return label;
    }

    /**
     * 創(chuàng)建指定尺寸的標(biāo)簽
     * @param text 標(biāo)簽文字
     * @param size 尺寸 [寬, 高]
     * @return 標(biāo)簽
     */
    public static JLabel getJLabel(String text, Integer... size) {
        JLabel label = new JLabel(text);
        int width = 85;
        int height = 36;
        if (null != size) {
            if (size.length > 0) width = size[0];
            if (size.length > 1) height = size[1];
        }
        ComponentUtils.setSize(label, width, height);
        return label;
    }

    // ==================== 文本框 ====================

    /**
     * 創(chuàng)建普通文本框(默認(rèn)尺寸 180x36)
     * @return 文本框
     */
    public static JTextField getTextField() {
        JTextField text = new JTextField();
        ComponentUtils.setSize(text, 180, 36);
        return text;
    }

    /**
     * 創(chuàng)建指定尺寸的文本框
     * @param size 尺寸 [寬, 高]
     * @return 文本框
     */
    public static JTextField getTextField(Integer... size) {
        JTextField text = new JTextField();
        int width = 180;
        int height = 36;
        if (null != size) {
            if (size.length > 0) width = size[0];
            if (size.length > 1) height = size[1];
        }
        ComponentUtils.setSize(text, width, height);
        return text;
    }

    /**
     * 創(chuàng)建帶默認(rèn)文本的文本框
     * @param text 默認(rèn)文本
     * @param size 尺寸 [寬, 高]
     * @return 文本框
     */
    public static JTextField getTextField(String text, Integer... size) {
        JTextField textField = getTextField(size);
        textField.setText(text);
        return textField;
    }

    /**
     * 創(chuàng)建可編輯/不可編輯的文本框
     * @param editable 是否可編輯
     * @param size 尺寸 [寬, 高]
     * @return 文本框
     */
    public static JTextField getTextField(Boolean editable, Integer... size) {
        JTextField text = getTextField(size);
        text.setEditable(editable);
        return text;
    }

		// ==================== 數(shù)字輸入框 ====================

    /**
     * 創(chuàng)建數(shù)字輸入框(支持小數(shù))
     * @param size 尺寸 [寬, 高]
     * @return 文本框
     */
    public static JTextField getNumberField(Integer... size) {
        JTextField textField = getTextField(size);
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                String key = "0123456789.";
                if (key.indexOf(e.getKeyChar()) < 0) {
                    e.consume();
                }
                if (e.getKeyChar() == '.' && textField.getText().indexOf(".") > 0) {
                    e.consume();
                }
            }
        });
        return textField;
    }

    /**
     * 創(chuàng)建帶默認(rèn)值的數(shù)字輸入框
     * @param text 默認(rèn)值
     * @param size 尺寸 [寬, 高]
     * @return 文本框
     */
    public static JTextField getNumberField(String text, Integer... size) {
        JTextField textField = getNumberField(size);
        if (StrUtil.isNotBlank(text)) {
            textField.setText(text);
        }
        return textField;
    }

    /**
     * 創(chuàng)建整數(shù)輸入框(不支持小數(shù)點(diǎn))
     * @param size 尺寸 [寬, 高]
     * @return 文本框
     */
    public static JTextField getIntegerField(Integer... size) {
        JTextField textField = getTextField(size);
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                String key = "0123456789";
                if (key.indexOf(e.getKeyChar()) < 0) {
                    e.consume();
                }
            }
        });
        return textField;
    }

    // ==================== 表單布局 ====================

    /**
     * 向父面板添加組件(自動(dòng)換行包裝)
     * @param parentPanel 父面板
     * @param components 組件數(shù)組
     */
    public static void addComponent(JPanel parentPanel, JComponent... components) {
        JPanel subPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        subPanel.setBorder(new EmptyBorder(0, 0, 0, 0));
        for (JComponent component : components) {
            subPanel.add(component);
        }
        parentPanel.add(subPanel);
    }

    /**
     * 向父面板添加透明背景的組件
     * @param parentPanel 父面板
     * @param components 組件數(shù)組
     */
    public static void addTransparentComponent(JPanel parentPanel, JComponent... components) {
        JPanel subPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        subPanel.setOpaque(false);
        subPanel.setBorder(new EmptyBorder(0, 0, 0, 0));
        for (JComponent component : components) {
            subPanel.add(component);
        }
        parentPanel.add(subPanel);
    }

    /**
     * 向面板添加“標(biāo)簽 + 組件”一行(默認(rèn)標(biāo)簽寬100,組件寬400)
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param component 組件
     * @param gbc 布局約束(可為null)
     */
    public static void addLabelAndTextField(JPanel parentPanel, String text, JComponent component, GridBagConstraints gbc) {
        addLabelAndTextField(parentPanel, text, component, gbc, false);
    }

    /**
     * 向面板添加“標(biāo)簽 + 組件”一行(可選必填標(biāo)記)
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param component 組件
     * @param gbc 布局約束(可為null)
     * @param required 是否必填(顯示紅色星標(biāo))
     */
    public static void addLabelAndTextField(JPanel parentPanel, String text, JComponent component, GridBagConstraints gbc, boolean required) {
        addLabelAndTextField(parentPanel, text, 100, component, 400, gbc, required);
    }

    /**
     * 向面板添加“標(biāo)簽 + 組件”一行(指定寬度)
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param labelWidth 標(biāo)簽寬度
     * @param component 組件
     * @param componentWidth 組件寬度
     * @param gbc 布局約束(可為null)
     */
    public static void addLabelAndTextField(JPanel parentPanel, String text, int labelWidth, JComponent component, int componentWidth, GridBagConstraints gbc) {
        addLabelAndTextField(parentPanel, text, labelWidth, component, componentWidth, gbc, false);
    }

    /**
     * 向面板添加“標(biāo)簽 + 組件”一行(完整參數(shù))
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param labelWidth 標(biāo)簽寬度
     * @param component 組件
     * @param componentWidth 組件寬度
     * @param gbc 布局約束(可為null)
     * @param required 是否必填
     */
    public static void addLabelAndTextField(JPanel parentPanel, String text, int labelWidth, JComponent component, int componentWidth, GridBagConstraints gbc, boolean required) {
        JPanel subPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        if (StrUtil.isNotBlank(text)) {
            JLabel label = new JLabel(text);
            if (required) {
                // 需要自行獲取圖片
                // ImageIcon icon = xxxx;
                // label.setIcon(icon);
                label.setText(label.getText() + " *");
            }
            ComponentUtils.setSize(label, labelWidth);
            subPanel.add(label);
        }
        ComponentUtils.setSize(component, componentWidth);
        subPanel.add(component);
        if (null != gbc) {
            parentPanel.add(subPanel, gbc);
        } else {
            parentPanel.add(subPanel);
        }
    }

    /**
     * 向面板添加“標(biāo)簽 + 文本域”(自動(dòng)帶滾動(dòng)條)
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param textArea 文本域
     * @param gbc 布局約束
     */
    public static void addLabelAndTextArea(JPanel parentPanel, String text, JTextArea textArea, GridBagConstraints gbc) {
        addLabelAndTextArea(parentPanel, text, textArea, gbc, false);
    }

    /**
     * 向面板添加“標(biāo)簽 + 文本域”(可選必填)
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param textArea 文本域
     * @param gbc 布局約束
     * @param required 是否必填
     */
    public static void addLabelAndTextArea(JPanel parentPanel, String text, JTextArea textArea, GridBagConstraints gbc, boolean required) {
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        JScrollPane scrollPane = new JScrollPane(textArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        addLabelAndTextField(parentPanel, text, scrollPane, gbc, required);
    }

    /**
     * 向面板添加“標(biāo)簽 + 文本域”(指定寬度)
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param labelWidth 標(biāo)簽寬度
     * @param textArea 文本域
     * @param textAreaWidth 文本域?qū)挾?
     * @param gbc 布局約束
     */
    public static void addLabelAndTextArea(JPanel parentPanel, String text, int labelWidth, JTextArea textArea, int textAreaWidth, GridBagConstraints gbc) {
        addLabelAndTextArea(parentPanel, text, labelWidth, textArea, textAreaWidth, gbc, false);
    }

    /**
     * 向面板添加“標(biāo)簽 + 文本域”(完整參數(shù))
     * @param parentPanel 父面板
     * @param text 標(biāo)簽文字
     * @param labelWidth 標(biāo)簽寬度
     * @param textArea 文本域
     * @param textAreaWidth 文本域?qū)挾?
     * @param gbc 布局約束
     * @param required 是否必填
     */
    public static void addLabelAndTextArea(JPanel parentPanel, String text, int labelWidth, JTextArea textArea, int textAreaWidth, GridBagConstraints gbc, boolean required) {
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        JScrollPane scrollPane = new JScrollPane(textArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        addLabelAndTextField(parentPanel, text, labelWidth, scrollPane, textAreaWidth, gbc, required);
    }

    // ==================== 表單標(biāo)簽 ====================

    /**
     * 創(chuàng)建表單標(biāo)簽(右對齊)
     * @param text 標(biāo)簽文字
     * @param required 是否必填
     * @return 標(biāo)簽
     */
    public static JLabel createFormLabel(String text, boolean required) {
        JLabel label = new JLabel(text);
        if (required) {
            // 需要自行獲取圖片
            // label.setIcon();
            label.setText(label.getText() + " *");
        }
        label.setFont(new Font("Microsoft YaHei", Font.PLAIN, 16));
        label.setHorizontalAlignment(SwingConstants.RIGHT);
        label.setVerticalAlignment(SwingConstants.TOP);
        return label;
    }

    /**
     * 創(chuàng)建指定高度的表單標(biāo)簽
     * @param text 標(biāo)簽文字
     * @param height 高度
     * @param required 是否必填
     * @return 標(biāo)簽
     */
    public static JLabel createFormLabel(String text, int height, boolean required) {
        JLabel label = createFormLabel(text, required);
        label.setPreferredSize(new Dimension(label.getPreferredSize().width, height));
        return label;
    }

    // ==================== 滾動(dòng)文本域 ====================

    /**
     * 創(chuàng)建帶滾動(dòng)條的文本域
     * @param textArea 文本域(可為null,內(nèi)部會創(chuàng)建)
     * @param height 高度
     * @return 滾動(dòng)面板
     */
    public static JScrollPane createScrollTextArea(JTextArea textArea, int height) {
        if (null == textArea) {
            textArea = new JTextArea(5, 1);
        }
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        JScrollPane scrollPane = new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setPreferredSize(new Dimension(textArea.getPreferredSize().width, height));
        return scrollPane;
    }
}

四、使用示例

4.1 創(chuàng)建統(tǒng)一樣式的文本框

// 普通文本框
JTextField nameField = ComponentUtils.createTextField();
nameField.setText("張三");
// 密碼框
JPasswordField pwdField = ComponentUtils.createPasswordField();

4.2 創(chuàng)建 Tab 標(biāo)簽頁

JLabel tab1 = ComponentUtils.createTabLabel("用戶管理", 16, "#409EFF", true);
JLabel tab2 = ComponentUtils.createTabLabel("角色管理", 16, "#409EFF", false, () -> {
    System.out.println("切換到角色管理");
});

4.3 執(zhí)行后臺任務(wù)

ComponentUtils.handleSwingWorker(
    () -> userService.getUserList(),      // 后臺執(zhí)行(可能耗時(shí))
    userList -> {                          // 完成后在 EDT 更新 UI
        table.setData(userList);
        statusLabel.setText("加載完成");
    }
);

4.4 表單布局

JPanel formPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(5, 5, 5, 5);

// 添加一行:標(biāo)簽 + 文本框
FormPanelUtils.addLabelAndTextField(formPanel, "用戶名:", ComponentUtils.createTextField(), gbc);

// 添加一行:標(biāo)簽 + 數(shù)字輸入框
FormPanelUtils.addLabelAndTextField(formPanel, "年齡:", FormPanelUtils.getIntegerField(), gbc, true);  // 必填

// 添加一行:標(biāo)簽 + 文本域
JTextArea remarkArea = new JTextArea(3, 20);
FormPanelUtils.addLabelAndTextArea(formPanel, "備注:", remarkArea, gbc);

4.5 創(chuàng)建標(biāo)題標(biāo)簽

JLabel title = ComponentUtils.createTitleLabel("用戶信息");
panel.add(title, BorderLayout.NORTH);

五、注意事項(xiàng)

  • 涉及圖標(biāo)的地方,需要自行實(shí)現(xiàn)或替換
  • FlatLaf 樣式:createWrapPanel 中的 putClientProperty 是 FlatLaf 特有的,不使用 FlatLaf 可刪除
  • 數(shù)字輸入框:只做了簡單的按鍵過濾,復(fù)雜校驗(yàn)建議配合文檔監(jiān)聽器使用
  • 線程安全:handleSwingWorker 已正確處理 EDT 和后臺線程的切換

六、小結(jié)

ComponentUtils 和 FormPanelUtils 是兩個(gè)基礎(chǔ)工具類,提供了 Swing 開發(fā)中最常用的組件操作封裝。

  • ComponentUtils:通用組件能力(文本框、邊框、Tab、SwingWorker)
  • FormPanelUtils:表單布局能力(標(biāo)簽+組件一行、數(shù)字輸入框)

以上就是Java Swing自定義實(shí)現(xiàn)組件與表單工具的詳細(xì)內(nèi)容,更多關(guān)于Java Swing自定義組件的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Java將DOCX文檔解析為Markdown文檔的代碼實(shí)現(xiàn)

    使用Java將DOCX文檔解析為Markdown文檔的代碼實(shí)現(xiàn)

    在現(xiàn)代文檔處理中,Markdown(MD)因其簡潔的語法和良好的可讀性,逐漸成為開發(fā)者、技術(shù)寫作者和內(nèi)容創(chuàng)作者的首選格式,然而,許多文檔仍然以Microsoft Word的DOCX格式保存,本文將介紹如何使用Java和相關(guān)庫將DOCX文檔解析為Markdown文檔,需要的朋友可以參考下
    2025-04-04
  • 關(guān)于SpringMVC對Restful風(fēng)格的支持詳解

    關(guān)于SpringMVC對Restful風(fēng)格的支持詳解

    Restful就是一個(gè)資源定位及資源操作的風(fēng)格,不是標(biāo)準(zhǔn)也不是協(xié)議,只是一種風(fēng)格,是對http協(xié)議的詮釋,下面這篇文章主要給大家介紹了關(guān)于SpringMVC對Restful風(fēng)格支持的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • Java實(shí)現(xiàn)多人聊天室的原理與源碼

    Java實(shí)現(xiàn)多人聊天室的原理與源碼

    這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)多人聊天室的原理與源碼的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 淺談java 執(zhí)行jar包中的main方法

    淺談java 執(zhí)行jar包中的main方法

    下面小編就為大家?guī)硪黄獪\談java 執(zhí)行jar包中的main方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-09-09
  • Java8?Stream流多字段求和、匯聚的實(shí)例

    Java8?Stream流多字段求和、匯聚的實(shí)例

    這篇文章主要介紹了Java8?Stream流多字段求和、匯聚的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • java實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出

    java實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • 解析JAVA深度克隆與淺度克隆的區(qū)別詳解

    解析JAVA深度克隆與淺度克隆的區(qū)別詳解

    本篇文章是對JAVA深度克隆與淺度克隆的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • JAVA中Integer值的范圍實(shí)例代碼

    JAVA中Integer值的范圍實(shí)例代碼

    這篇文章主要介紹了JAVA中Integer值的范圍實(shí)例代碼,需要的朋友可以參考下
    2017-09-09
  • maven安裝與環(huán)境配置圖文教程

    maven安裝與環(huán)境配置圖文教程

    這篇文章主要為大家詳細(xì)介紹了maven安裝與環(huán)境配置圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • SpringIoC與SpringDI詳解

    SpringIoC與SpringDI詳解

    本文介紹了Spring框架中的IoC(控制反轉(zhuǎn))和DI(依賴注入)概念,以及如何在Spring中使用這些概念來管理對象和依賴關(guān)系,感興趣的朋友一起看看吧
    2025-03-03

最新評論

金阳县| 南乐县| 乐安县| 明星| 清水河县| 洞头县| 衡水市| 庄浪县| 华坪县| 剑阁县| 福安市| 陕西省| 治县。| 呼伦贝尔市| 临沧市| 邮箱| 桓仁| 榆社县| 曲阜市| 清原| 黄大仙区| 商丘市| 曲松县| 法库县| 宁晋县| 历史| 辽宁省| 阿拉善盟| 兖州市| 额尔古纳市| 岳池县| 青神县| 北碚区| 黎川县| 阳西县| 句容市| 兰坪| 洛浦县| 珠海市| 顺义区| 龙游县|