Java?Swing自定義實(shí)現(xiàn)組件與表單工具
一、這兩個(gè)類解決什么問題
Swing 原生組件缺少一些常用的便捷方法,比如:
- 統(tǒng)一文本框的邊框和聚焦樣式
- 快速創(chuàng)建帶邊框的面板
- 表單中常用的“標(biāo)簽 + 組件”一行添加
- 安全執(zhí)行后臺任務(wù)(SwingWorker)
ComponentUtils 和 FormPanelUtils 就是對這類操作的封裝。
兩個(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)文章!
- Java Swing實(shí)現(xiàn)自定義日期時(shí)間選擇器組件
- Java?Swing實(shí)現(xiàn)自定義按鈕組件的完整代碼
- Java語言中Swing組件編程詳解
- 基于Java swing組件實(shí)現(xiàn)簡易計(jì)算器
- Java Swing組件實(shí)現(xiàn)進(jìn)度監(jiān)視功能示例
- Java實(shí)現(xiàn)Swing組件定制Button示例
- Java Swing組件定制RadioButton示例
- Java Swing組件定制CheckBox示例
- java實(shí)現(xiàn)的計(jì)算器功能示例【基于swing組件】
- Java Swing組件編程之JTable表格用法實(shí)例詳解
相關(guā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)格的支持詳解
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)Excel的導(dǎo)入導(dǎo)出
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06

