Java Swing-4.样式,边距及布局管理器的灵活使用

环境

jdk17(jdk14 以后自带将jar 打成安装包工具,版本从1.8调整到17)

Maven:3.2.5

pom.xml:在上篇文章中《Java Swing-2.环境搭建及窗口背景

效果

下一章:如何通过jdk 自带的工具 打包成 exe ,msi ,或者面安装版的exe 文件(自带jre环境),无需安装这安装jdk

  • exe4j: 免费版会有弹框 提示用户使用的免费版exe4j打包工具
  • Launch4j: 开源,但目前没找到如何把jre 环境直接放到exe 中,需要把exe和jre 打成一个压缩包形式使用

说明

Swing 控制样式总体来说分为两种

  • 通过布局管理器
  • 组件提供的修改样式方法(部分组件,有限调整)
  • 继承组件后通过画布 重写绘制该组件(按钮变圆,背景色等)

1.布局管理器

布局管理器之前要先了解Swing AWT 的容器(窗口)概念,因为布局管理器是针对容器的,每个容器可以设置一个属于自己的布局管理器。基本概念在这;同时容器可以添加其他容器,组件。

一个容器的整体分布、布局方式。

FlowLayout

流式布局,依次排序,遇到边界挪至下一行

BorderLayout

边界布局(区域布局),分为北、南、西、东、中(上、下、左、右、中) 五个区域

GridLayout

纵横风格的网络,每个网格所占区域大小相同。默认从左向右

GridBagLayout

功能最强大的布局管理器,纵横网格,可以跨越一个或多个网格,设置网格的大小(类似Excel中的合并单元格 ,上下 左右合并)比较难控制

CardLayout

将加入容器的租价看成一叠卡片,只有最上层的才可见(类似轮播图)

绝对定位

setLayout(null)

设置后不会再自动填充这个容器,

BoxLayout

GridBagLayout布局管理器的简化版,配合 Box 一起使用,如果想要简单控制组件间距,可以使用该组件

组件方法

不是所有组件都有以下方法。

.setBounds();
java 复制代码
// x起点,y起点 宽,高
button.setBounds(5, 5, 80, 25);
.setFont();
java 复制代码
// 设置字体 形状,大小
zlabel.setFont(new Font("Serif", Font.BOLD, 36));
.setSize();
java 复制代码
// 宽,高
        newLabel.setSize(10,20);
.setIcon();
java 复制代码
// 设置图标(按钮图标,树状图图标)
        newLabel.setIcon(new ImageIcon("/path/xxx/ccc"));
        // 设置背景色(边框)
        jPanel.setBackground(Color.black);

继承重绘组件

主要依赖于以下两种画布

  • Graphics
    继承组件 重新 paintComponent(Graphics g) 方法
  • Canvase

主要代码

项目目录

控制样式部分都在 首页及编辑页面,主要使用了布局管理器,组件方法来控制按钮的位置

首页代码

java 复制代码
package com.tiger.four;

import com.tiger.four.table.GoodsJTable;
import com.tiger.four.table.LableJTable;
import com.tiger.four.util.DataUtil;
import com.tiger.four.util.FileTUtil;

import javax.swing.*;
import javax.swing.border.AbstractBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.RoundRectangle2D;
import java.util.Random;
import java.util.Set;

public class InitWindow {
    public static JComboBox<String> comboBox;

    private static Timer timer;

    /**
     * 创建窗口
     */
    public static void createWindow() {
        JFrame jFrame = new JFrame("随便");
        //jFrame.setIconImage(new ImageIcon("src/main/resources/static/imgs/yu.png").getImage());
        jFrame.setIconImage(FileTUtil.readImage("static/imgs/yu.png").getImage());
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 设置窗口宽高
        jFrame.setSize(600, 500);
        // 添加菜单
        jFrame.setJMenuBar(createMenus(jFrame));
        // 添加开始按钮
        JPanel jPanel = new JPanel();
        jPanel.setBackground(Color.black);

        // 添加标签
        jFrame.add(createLable(jFrame,jPanel), BorderLayout.NORTH);

        startFace(jFrame, jPanel);

        jFrame.add(jPanel, BorderLayout.CENTER);

        jFrame.setLocationRelativeTo(null);
        jFrame.setVisible(true);
    }

    /**
     * 开始界面
     * @param jFrame
     * @param jPanel
     */
    private static void startFace(JFrame jFrame, JPanel jPanel) {
        // 清空当前容器所有组件
        jPanel.removeAll();
        if(timer!=null&&timer.isRunning()){
            timer.stop();
        }
        // 加载开始图片
        JLabel imageLabel = new JLabel();
        ImageIcon secondImage = FileTUtil.readImage("static/imgs/startb1.png");//new ImageIcon("src/main/resources/static/imgs/startb1.png");
        imageLabel.setIcon(secondImage);
        jPanel.add(imageLabel);
//        增加图片点击时间
        imageLabel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // 跳转抽签页面
                drawLotsFace(jFrame, jPanel);
            }
        });
        jFrame.revalidate();
        jFrame.repaint();
    }

    /**
     * 抽签界面
     */
    private static void drawLotsFace(JFrame jFrame, JPanel jPanel) {
        // 清空当前容器所有组件
        jPanel.removeAll();
        // 加载抽签界面
        JLabel imageLabel = new JLabel();
        ImageIcon secondImage = FileTUtil.readImage("static/imgs/move/chou2.gif"); //new ImageIcon("src/main/resources/static/imgs/move/chou2.gif");
        imageLabel.setIcon(secondImage);
        jPanel.add(imageLabel);
        // 重新渲染窗口
        jFrame.revalidate();
        jFrame.repaint();

        // 创建一个Timer,在2秒后触发ActionEvent
        timer = new Timer(2000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                // 跳转结束画面
                endFace(jFrame, jPanel, (Timer) evt.getSource());
            }
        });

        timer.start();
    }


    /**
     * 结束界面
     * @param jFrame
     * @param jPanel
     * @param timer1
     */
    private static void endFace(JFrame jFrame, JPanel jPanel, Timer timer1) {
        // 清空容器中所有组件
        jPanel.removeAll();
        // 绘制结束画面
        // 首级容器 让文字和按钮换行展示
        JPanel firstPanel = new JPanel();
        firstPanel.setLayout(new BoxLayout(firstPanel, BoxLayout.Y_AXIS)); // 设置垂直布局

        // 获取当前选择的下来框
        String selectedItem = comboBox.getSelectedItem() + "";
        Set<String> strings = DataUtil.getGoods().get(selectedItem);
        // 生成随机数,随机生成结果
        Object[] array = strings.toArray();
        int i = new Random().nextInt(array.length);
        String good = array[i] + "";

        // 二级容器(为了让文字 和 按钮都居中展示,不加会错位)
        JPanel secondPanel = new JPanel();

        // 创建物品标签
        JLabel newLabel = new JLabel(good);
        newLabel.setFont(new Font("Serif", Font.BOLD, 24));
        newLabel.setForeground(Color.GREEN);
        secondPanel.add(newLabel);


        // 创建菜单容器,保证两个菜单在一行上,且有一些间距
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
        JButton again = new JButton("再来一次");
        JButton ok = new JButton("就这个");
        //        按钮点击事件
        again.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 当按钮被点击时执行的代码
                drawLotsFace(jFrame, jPanel); // 确保这个方法在你的类中已经定义
            }
        });

        ok.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 当按钮被点击时执行的代码
                startFace(jFrame, jPanel); // 确保这个方法在你的类中已经定义
            }
        });


        // 为了在垂直布局中保持组件之间的间距,可以使用 Box.createVerticalStrut() 或添加一些空白的组件
        buttonPanel.add(again);
        buttonPanel.add(Box.createHorizontalStrut(10)); // 可选:添加水平间距
        buttonPanel.add(ok);

        firstPanel.add(secondPanel);
        firstPanel.add(Box.createVerticalStrut(249)); // 可选:添加垂直间距
        firstPanel.add(buttonPanel);


        jPanel.add(firstPanel);

        // 重新渲染
        jFrame.revalidate();
        jFrame.repaint();
        timer.stop();
    }

    /**
     * 创建菜单
     * 1.编辑物品
     * 2.编辑物品标签
     *
     * @return
     */
    public static JMenuBar createMenus(JFrame jFrame) {
        JMenuBar jMenuBar = new JMenuBar();
        JMenu setting = new JMenu("设置");
        JMenuItem editGoods = new JMenuItem("编辑物品");
//        点击菜单时触发
        editGoods.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
//                绘制编辑标签界面
                LableJTable.showLableJDialog(jFrame);
            }
        });


        JMenuItem editGoodsType = new JMenuItem("编辑物品标签");
        editGoodsType.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 编辑物品界面
                GoodsJTable.showLableJDialog(jFrame);
            }
        });
        setting.add(editGoods);
        setting.add(editGoodsType);
        jMenuBar.add(setting);
        return jMenuBar;
    }


    /**
     * 创建主页标签下拉框
     * 1.读取标签信息
     * 2.加载标签页面
     * @return
     */
    public static JPanel createLable(JFrame jFrame, JPanel jPanel) {
        JPanel nPanel = new JPanel(new GridBagLayout());

        // 创建一个字符串数组作为下拉框的选项
        Object[][] tableData = DataUtil.getLable();
        String[] options = new String[tableData.length];
        for (int i = 0; i < tableData.length; i++) {
            options[i] = tableData[i][0] + "";
        }
        JPanel son = new JPanel();
        JLabel label = new JLabel("标签:");

        // 创建一个 JComboBox 并添加选项
        InitWindow.comboBox = new JComboBox<>(options);
        InitWindow.comboBox.setSize(1, comboBox.getHeight());

        // 创建个首页按钮
        JPanel pagePanel = new JPanel();
        JButton page = new JButton("首页");
        /*page.setContentAreaFilled(false); // 去除按钮的默认填充,以便边框更明显
        page.setBorderPainted(true); // 确保边框被绘制
        page.setBorder(new RoundedBorder(10)); // 应用圆角边框*/


        page.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                startFace( jFrame,  jPanel);
            }
        });
        pagePanel.add(page);

        son.add(label);
        son.add(comboBox);
        // 设置GridBag约束
        GridBagConstraints gbc = new GridBagConstraints();
        //
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0.1; // 左侧占90%
        gbc.anchor = GridBagConstraints.LINE_START; // 右对齐
        gbc.fill = GridBagConstraints.HORIZONTAL;
        nPanel.add(pagePanel, gbc);


        // 添加空面板占位左侧90%宽度
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 0.8; // 左侧占90%
        gbc.fill = GridBagConstraints.BOTH;
        nPanel.add(new JPanel(), gbc);

        // 设置单选框约束
        gbc.gridx = 2;      // 第二列
        gbc.gridy = 0;
        gbc.weightx = 0.1; // 右侧占10%
        gbc.anchor = GridBagConstraints.LINE_END; // 右对齐
        gbc.fill = GridBagConstraints.HORIZONTAL; // 水平填充
        nPanel.add(son, gbc);
        return nPanel;
    }

    static class RoundedBorder extends AbstractBorder {
        private int radius;

        public RoundedBorder(int radius) {
            this.radius = radius;
        }

        @Override
        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setStroke(new BasicStroke(2));
            g2d.setPaint(Color.BLACK);

            // 绘制圆角矩形边框
            g2d.draw(new RoundRectangle2D.Double(x, y, width - 1, height - 1, radius, radius));

            g2d.dispose();
        }

        @Override
        public Insets getBorderInsets(Component c) {
            return new Insets(radius, radius, radius, radius);
        }

        @Override
        public boolean isBorderOpaque() {
            return false;
        }
    }
}

编辑页面代码-标签编辑页

java 复制代码
package com.tiger.four.table;

import com.tiger.four.InitWindow;
import com.tiger.four.util.DataUtil;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 标签列表
 */
public class LableJTable {
    public static void showLableJDialog(JFrame jFrame) {
        JDialog dialog = new JDialog(jFrame, "物品列表", true);
        dialog.setSize(500, 300);
        dialog.setLayout(new BorderLayout());
        dialog.setLocationRelativeTo(null);
        JPanel jPanel = new JPanel(new BorderLayout());
        JButton add = new JButton("新增");
        // 表格
        Object[] columnTitle = {"标签", "操作"};
        DefaultTableModel model = new DefaultTableModel(DataUtil.getLable(), columnTitle);

        JTable jTable = new JTable(model);
        // 新增点击时触发
        add.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                model.addRow(new Object[]{""});
                dialog.pack();
            }
        });

        // 添加 TableModelListener
        model.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                String[][] tableData = DataUtil.getLable();
                int firstRow = e.getFirstRow();
                int column = e.getColumn();
                TableModel source = (TableModel) e.getSource();

                if (column < 0) return;

                Object valueAt = source.getValueAt(firstRow, column);
                if (("删除").equals(valueAt)) return;

                // 同步首页标签下拉框
                int itemCount = InitWindow.comboBox.getItemCount();
                if (itemCount - 1 < firstRow) {
                    InitWindow.comboBox.addItem(valueAt + "");
                } else {
                    Object o = tableData[firstRow][column];
                    InitWindow.comboBox.removeItem(o + "");
                    InitWindow.comboBox.insertItemAt(valueAt + "", firstRow);
                }
                DataUtil.changeLable(firstRow, column, valueAt + "");
            }
        });

        jTable.setRowHeight(35);
        jTable.getColumnModel().getColumn(1).setCellEditor(new DeleteLableEditor(jTable));

        jTable.getColumnModel().getColumn(1).setCellRenderer(new DelectButtonRender());
        jPanel.add(add, BorderLayout.NORTH);
        jPanel.add(new JScrollPane(jTable), BorderLayout.CENTER);

        dialog.add(jPanel);
        dialog.pack();
        dialog.setVisible(true);


    }

}

/**
 * 将指定列渲染成按钮
 * 举一反三
 * 也可以时图片 单选框 多选框 等非文字组件
 *
 */

class DelectButtonRender implements TableCellRenderer {
    private JPanel panel;

    private JButton button;

    public DelectButtonRender() {
        this.initButton();

        this.initPanel();

        // 添加按钮。
        this.panel.add(this.button);
    }

    private void initButton() {
        this.button = new JButton();
        // 设置按钮的大小及位置。
        this.button.setBounds(5, 5, 80, 25);
    }

    private void initPanel() {
        this.panel = new JPanel();
        this.panel.setLayout(null);
    }


    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        this.button.setText("删除");
        return this.panel;
    }
}

/**
 * 指定列中 的单元格触发修改时调用
 * 触发修改时 可以将其位置的文字或组件 改成其他下拉框,按钮等
 */
class DeleteLableEditor extends DefaultCellEditor {
    private static final long serialVersionUID = -6546334664166791132L;

    private JPanel deletePanel;

    private JButton deleteButton;
    private JTable lableTable;

    public DeleteLableEditor(JTable table) {
        super(new JTextField());
        lableTable = table;
        this.setClickCountToStart(1);
        this.init();
        this.deletePanel.add(this.deleteButton);
    }

    /**
     * 初始化按钮
     * 当列表开始渲染时触发
     */
    private void init() {
        this.deletePanel = new JPanel();
        this.deletePanel.setLayout(null);

        this.deleteButton = new JButton();
        this.deleteButton.setBounds(0, 0, 80, 25);
        this.deleteButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JButton btn = (JButton) (e.getSource());
                ChangeEvent ce = new ChangeEvent(btn);
                lableTable.editingStopped(ce);

                int selectedRow = lableTable.getSelectedRow();
                DefaultTableModel model = (DefaultTableModel) (lableTable.getModel());
                String value = model.getValueAt(selectedRow, 0) + "";
                model.removeRow(selectedRow);
                InitWindow.comboBox.removeItem(value);
                DataUtil.deleteLable(selectedRow, 0, value);
            }
        });
    }




    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        this.deleteButton.setText("删除");
        return this.deletePanel;
    }

    @Override
    public Object getCellEditorValue() {
        return this.deleteButton.getText();
    }

}

编辑页面代码-物品编辑页

java 复制代码
package com.tiger.four.table;

import com.tiger.four.util.DataUtil;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 物品列表
 */
public class GoodsJTable {

    public static void showLableJDialog(JFrame jFrame) {
        JDialog dialog = new JDialog(jFrame, "物品列表", true);
        dialog.setSize(500, 300);
        dialog.setLayout(new BorderLayout());
        dialog.setLocationRelativeTo(null);
        JPanel jPanel = new JPanel(new BorderLayout());
        JButton add = new JButton("新增");

        // 表格
        Object[] columnTitle = {"物品", "标签", "操作"};
        DefaultTableModel model = new DefaultTableModel(DataUtil.getGoodsArray(), columnTitle);
        JTable jTable = new JTable(model);
        add.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                model.addRow(new Object[]{""});
                dialog.pack();
            }
        });

        // 添加 TableModelListener
        model.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                int firstRow = e.getFirstRow();
                int column = e.getColumn();
                if (column < 0) return;
                TableModel source = (TableModel) e.getSource();
                Object valueAt = source.getValueAt(firstRow, column);
                if (("删除").equals(valueAt)) {
                    return;
                }
                DataUtil.changeGoods(firstRow, column, valueAt + "");
            }
        });

        jTable.setRowHeight(35);
        jTable.getColumnModel().getColumn(2).setCellEditor(new DeleteEditor(jTable));
        jTable.getColumnModel().getColumn(1).setCellEditor(new CheckBoxEditor(jTable));
        jTable.getColumnModel().getColumn(2).setCellRenderer(new DeleteRenderer());
        jPanel.add(add, BorderLayout.NORTH);
        jPanel.add(new JScrollPane(jTable), BorderLayout.CENTER);
        dialog.add(jPanel);
        dialog.pack();
        dialog.setVisible(true);
    }
}

/**
 * 单元格渲染时 会按照指定格式渲染
 */
class DeleteRenderer implements TableCellRenderer {
    private JPanel panel;

    private JButton button;

    public DeleteRenderer() {
        this.initButton();
        this.initPanel();
        this.panel.add(this.button);
    }

    private void initButton() {
        this.button = new JButton();
        // 设置按钮的大小及位置。
        this.button.setBounds(5, 5, 80, 25);
    }

    private void initPanel() {
        this.panel = new JPanel();
        // panel使用绝对定位,这样button就不会充满整个单元格。
        this.panel.setLayout(null);
    }


    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        this.button.setText("删除");
        return this.panel;
    }
}

/**
 * 单元格触发编辑时 会按照指定格式渲染
 */
class DeleteEditor extends DefaultCellEditor {
    private static final long serialVersionUID = -6546334664166791132L;
    private JPanel buttonPanel;
    private JButton deleteButton;
    private JTable goodsTable;

    public DeleteEditor(JTable table) {
        super(new JTextField());
        goodsTable = table;
        this.setClickCountToStart(1);
        this.init();
    }

    private void init() {
        this.buttonPanel = new JPanel();
        this.buttonPanel.setLayout(null);

        this.deleteButton = new JButton();
        this.deleteButton.setBounds(0, 0, 80, 25);
        this.deleteButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (goodsTable.getCellEditor() != null) {
                    goodsTable.getCellEditor().stopCellEditing();
                }
                /*JButton btn = (JButton) (e.getSource());
                ChangeEvent ce = new ChangeEvent(btn);
                goodsTable.editingStopped(ce);*/
                int selectedRow = goodsTable.getSelectedRow();
                DefaultTableModel model = (DefaultTableModel) (goodsTable.getModel());
                String valueAt = model.getValueAt(selectedRow, 0) + "";
                model.removeRow(selectedRow);
                DataUtil.deleteGoods(selectedRow, 0, valueAt);
            }
        });
        this.buttonPanel.add(this.deleteButton);
    }



    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        this.deleteButton.setText("删除");
        return this.buttonPanel;
    }

    @Override
    public Object getCellEditorValue() {
        return this.deleteButton.getText();
    }

}

/**
 * 单元格触发编辑时 会按照指定格式渲染
 */
class CheckBoxEditor extends DefaultCellEditor {
    private JPanel boxPanel;

    private JComboBox<String> comboBox;

    private JTable goodsTable;

    public CheckBoxEditor(JTable table) {
        super(new JTextField());
        goodsTable = table;
        this.setClickCountToStart(2);
        this.init();
    }

    private void init() {
        this.boxPanel = new JPanel();
        this.boxPanel.setLayout(null);

        String[][] tableData = DataUtil.getLable();
        int goodsLength = tableData.length;
        String[] option = new String[goodsLength];
        for (int i = 0; i < goodsLength; i++) {
            option[i] = tableData[i][0] + "";
        }
        this.comboBox = new JComboBox<String>(option);
        this.comboBox.setBounds(0, 0, 80, 25);
        this.boxPanel.add(this.comboBox);
    }


    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        this.comboBox.setSelectedItem(value);
        return this.boxPanel;
    }

    @Override
    public Object getCellEditorValue() {
        return this.comboBox.getSelectedItem();
    }

}

异常

无法读取静态文件

开发阶段一切正常,打成jar 以后静态文件无法读取

原因

常规方法无法从jar(压缩包) 文件中读取文件

代码
java 复制代码
// 用此方法读取
InputStream inputStream = FileTUtil.class.getClassLoader().getResourceAsStream(path);
 

ImageIcon 加载动图 不动

原因

通过源码中观察 ,流的的方式 会导致缺少以下渲染加载动作,导致无法将动图完整加载到Icon 中,从而只显示动图的第一张图

Toolkit.getDefaultToolkit().createImage(imageData);

代码
java 复制代码
 public static ImageIcon readImage(String path){
        try (InputStream inputStream = FileTUtil.class.getClassLoader().getResourceAsStream(path)) {
            if (inputStream == null) throw new IllegalArgumentException("资源未找到: " + path);

            // 将流转换为字节数组
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, bytesRead);
            }
            byte[] imageBytes = buffer.toByteArray();
            // 此行是关键,直接new ImageIcon(inputStream);会让动图失效
            return new ImageIcon(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("资源加载失败", e);
        }

    }
相关推荐
TDengine (老段)2 分钟前
TDengine 中的日志系统
java·大数据·数据库·物联网·时序数据库·tdengine·iotdb
不想学习!!3 分钟前
linux之进程控制
java·linux·服务器
独好紫罗兰10 分钟前
洛谷题单3-P1420 最长连号-python-流程图重构
开发语言·python·算法
kingmax5421200814 分钟前
深入解析:使用Python爬取Bilibili视频
开发语言·python·音视频
申雪菱25 分钟前
Scheme语言的数据挖掘
开发语言·后端·golang
Aerkui34 分钟前
Python列表(List)深度解析
开发语言·python
啊阿狸不会拉杆37 分钟前
第二十章:Python-Matplotlib库实现函数可视化
开发语言·python·matplotlib
欧宸雅41 分钟前
HTML语言的空值合并
开发语言·后端·golang
nlog3n1 小时前
Java外观模式详解
java·开发语言·外观模式
方瑾瑜1 小时前
Visual Basic语言的物联网
开发语言·后端·golang