You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JList在JFileChooser中同时保存多个MIDI文件?

实现批量保存选中的MIDI文件

首先,咱们先拆解你现有代码的局限:当前saveMidiFileAction里只通过playlistModel.getSelectedSequenceModel()获取了单个选中的序列,这就是只能存一个文件的核心原因。接下来我基于你提到的思路,给出两种可行的实现方案。

方案一:逐个保存选中的MIDI文件(重复执行保存操作)

这个思路是获取所有选中的序列模型,然后逐个处理保存逻辑。为了提升用户体验,我们可以让用户先选择一个目标目录,再将所有选中的MIDI文件按原文件名保存到该目录下。

修改后的代码如下:

private class MidiFileChooser extends JFileChooser { 
    { 
        setFileFilter(new FileNameExtensionFilter("MIDI sequence (*.mid)", "mid")); 
        setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 先让用户选择保存目录
    } 

    /** 
     * 批量保存MIDI文件操作
     */ 
    public Action saveMidiFileAction = getModel().new SelectedSequenceAction( 
        "保存选中项", 
        "将所有选中的MIDI序列保存到指定目录" 
    ) { 
        @Override 
        public void actionPerformed(ActionEvent event) { 
            PlaylistTableModel playlistModel = getModel();
            // 获取所有选中的序列模型,需要你的PlaylistTableModel提供多选获取方法
            List<SequenceTrackListTableModel> selectedSequences = playlistModel.getSelectedSequenceModels();
            
            if (selectedSequences.isEmpty()) {
                showMessage("未选中任何MIDI序列!");
                return;
            }

            // 让用户选择保存目录
            if (showSaveDialog((Component)event.getSource()) != JFileChooser.APPROVE_OPTION ) {
                return;
            }
            File targetDir = getSelectedFile();
            
            // 逐个保存每个选中的文件
            for (SequenceTrackListTableModel sequenceModel : selectedSequences) {
                String fn = sequenceModel.getFilename();
                if (fn == null || fn.isEmpty()) {
                    continue; // 跳过无文件名的序列
                }
                File saveFile = new File(targetDir, fn);
                
                // 处理文件已存在的确认
                if (saveFile.exists()) {
                    if (!confirm("是否覆盖文件 " + saveFile.getName() + " ?")) {
                        continue; // 用户取消则跳过该文件,继续保存下一个
                    }
                }
                
                // 写入MIDI数据到文件
                try (FileOutputStream out = new FileOutputStream(saveFile)) {
                    out.write(sequenceModel.getMIDIdata());
                    sequenceModel.setModified(false);
                    playlistModel.fireSequenceModified(sequenceModel, false);
                } catch (IOException ex) {
                    ex.printStackTrace();
                    showError("保存 " + fn + " 失败:" + ex.getMessage());
                }
            }
            showMessage("选中的MIDI文件已成功保存!");
        } 
    };
}

注意:你需要给PlaylistTableModel添加getSelectedSequenceModels()方法,用来返回所有选中的序列模型列表,示例实现如下:

public List<SequenceTrackListTableModel> getSelectedSequenceModels() {
    List<SequenceTrackListTableModel> selected = new ArrayList<>();
    // 假设你用JTable的选中行索引来获取对应模型
    int[] selectedRows = playlistTable.getSelectedRows();
    for (int row : selectedRows) {
        selected.add(getSequenceModelAt(row));
    }
    return selected;
}

方案二:打包成Zip文件保存

如果希望用户一次性将所有选中文件保存为一个压缩包,这个方案更便捷,也能避免用户重复操作。

修改后的代码示例:

private class MidiFileChooser extends JFileChooser { 
    { 
        setFileFilter(new FileNameExtensionFilter("ZIP压缩包 (*.zip)", "zip"));
    } 

    /** 
     * 批量保存为Zip压缩包操作
     */ 
    public Action saveMidiZipAction = getModel().new SelectedSequenceAction( 
        "保存为Zip", 
        "将所有选中的MIDI序列打包保存为Zip压缩包" 
    ) { 
        @Override 
        public void actionPerformed(ActionEvent event) { 
            PlaylistTableModel playlistModel = getModel();
            List<SequenceTrackListTableModel> selectedSequences = playlistModel.getSelectedSequenceModels();
            
            if (selectedSequences.isEmpty()) {
                showMessage("未选中任何MIDI序列!");
                return;
            }

            if (showSaveDialog((Component)event.getSource()) != JFileChooser.APPROVE_OPTION ) {
                return;
            }
            File zipFile = getSelectedFile();
            // 确保文件名以.zip结尾
            if (!zipFile.getName().toLowerCase().endsWith(".zip")) {
                zipFile = new File(zipFile.getParent(), zipFile.getName() + ".zip");
            }
            
            // 处理压缩包已存在的确认
            if (zipFile.exists()) {
                if (!confirm("是否覆盖压缩包 " + zipFile.getName() + " ?")) {
                    return;
                }
            }
            
            // 创建Zip输出流并写入数据
            try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
                for (SequenceTrackListTableModel sequenceModel : selectedSequences) {
                    String fn = sequenceModel.getFilename();
                    if (fn == null || fn.isEmpty()) {
                        continue;
                    }
                    // 添加Zip条目
                    ZipEntry entry = new ZipEntry(fn);
                    zipOut.putNextEntry(entry);
                    // 写入MIDI数据
                    zipOut.write(sequenceModel.getMIDIdata());
                    zipOut.closeEntry();
                    
                    // 更新模型状态
                    sequenceModel.setModified(false);
                    playlistModel.fireSequenceModified(sequenceModel, false);
                }
                showMessage("选中的MIDI文件已成功打包为Zip!");
            } catch (IOException ex) {
                ex.printStackTrace();
                showError("创建Zip压缩包失败:" + ex.getMessage());
            }
        } 
    };
}

额外建议

如果你想同时保留“单个保存”和“批量保存”功能,可以添加两个独立的Action,分别绑定到不同的按钮或菜单选项上,让用户自主选择保存方式。

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:45:42