JFileChooser“另存为”复合文档 - 覆盖现有文档

时间:2014-05-17 14:12:53

标签: java swing jfilechooser

我正在研究一个使用复合文档存储数据的系统。

一切都工作得很漂亮 - 我甚至在打开的对话框中都有漂亮的图标和双击打开工作。

我的问题是“另存为”对话框。如果我保存为一个尚未存在的复合文档,那么一切都很好。如果我双击现有的复合文档,那么我的代码会询问您是否要覆盖它,这也没关系。

但是,如果您键入现有复合文档的名称并单击“保存”,那么它的工作原理是错误的,就像您单击取消一样。

我正在使用FileFilter和FileView来配置文件的所有显示和过滤。

这是我的主要对话框打开功能:

public void saveAs() {
    JFileChooser fc = new JFileChooser();
    javax.swing.filechooser.FileFilter filter = new SketchFolderFilter();
    fc.setFileFilter(filter);

    javax.swing.filechooser.FileView view = new SketchFileView();
    fc.setFileView(view);

    fc.setCurrentDirectory(Base.getSketchbookFolder());

    int rv = fc.showSaveDialog(this);

    System.err.println("Option: " + rv);
    if (rv == JFileChooser.APPROVE_OPTION) {
        File newFile = fc.getSelectedFile();
        System.err.println("Save As: " + newFile.getAbsolutePath());
        if (newFile.exists()) {
            int n = twoOptionBox(
                JOptionPane.WARNING_MESSAGE,
                "Overwrite File?",
                Translate.w("Do you really want to overwrite the file %1?", 40, "\n", newFile.getName()),
                "Yes", "No");
            if (n != 0) {
                return;
            }
            newFile.delete();
        }
        loadedSketch.saveAs(newFile);
    }
}

在这里,如果你需要它,是我的过滤器和视图类:

public class SketchFileView extends javax.swing.filechooser.FileView {
    public String getTypeDescription(File f) {
        if (Base.isSketchFolder(f)) {
            return Translate.t("UECIDE Sketch Folder");
        }
        return Translate.t("Directory");
    }

    public Boolean isTraversable(File f) {
        if (Base.isSketchFolder(f)) {
            return false;
        }
        return true;
    } 

    public Icon getIcon(File f) {
        if (Base.isSketchFolder(f)) {
            ImageIcon icon = Base.loadIconFromResource("icon16.png");
            return icon;
        }
        return null;
    }
}

public class SketchFolderFilter extends javax.swing.filechooser.FileFilter {
    public boolean accept(File f) {
        if (Base.isSketchFolder(f)) {
            return true;
        }
        if (f.isDirectory()) {
            return true;
        }
        return false;
    }

    public String getDescription() {
        return Translate.t("Sketch Folders");
    }
}

当它工作时,我看到,在stderr上:

Option: 0
Save As: /foo/bar/baz

当它不起作用时,我看到:

Option: 1

澄清:

据我所知,这纯粹是复合文件的问题。

重申这个场景:

  1. 打开JFileChooser将数据保存到复合文档
  2. 您有一份现有复合文件的列表。
  3. 双击一次 - 返回APPROVE_OPTION索引,getSelectedFile()返回File对象,或
  4. 您键入不存在的复合文档的名称,然后按“保存”或返回键。返回APPROVE_OPTION索引,getSelectedFile()返回File对象,但
  5. 您键入现有复合文档的名称,然后按“保存”或返回键。返回CANCEL_OPTION索引,getSelectedFile()返回null或
  6. 按“取消”按钮。返回CANCEL_OPTION索引,getSelectedFile()返回null。
  7. 然后使用File对象和您自己的代码生成复合文档 - 通常删除旧文件(如果它在那里并且用户说他想要覆盖)并制作目录并填写它与你的文件。
  8. 这是(在我看来无论如何)错误的5。它应该返回APPROVE_OPTION并且getSelectedFile()应该返回一个File对象,该对象表示您在JFileChooser所在的目录中驻留的文件(即,与3相同)。

    编辑:

    缩小范围。看起来JFileChooser不喜欢它,当一个文件夹是不可遍历的,你把它的名字输入选择器并点击返回 - 它试图遍历它并且它失败了,并且不知道该如何处理它,所以只是将你从JFileChooser中转出来返回0.这是一个SSCCE来演示它。在包含名为“test.X”的文件夹的文件夹上运行此命令,然后键入“test.X”。它应该失败。

    import java.io.*;
    import javax.swing.*;
    
    
    class fctest {
    
        public class SketchFileView extends javax.swing.filechooser.FileView {
            public Boolean isTraversable(File f) {
                if (f.getName().endsWith(".X")) {
                    return false;
                }
                if (f.isDirectory()) {
                    return true;
                }
                return true;
            } 
        }
    
        public class SketchFolderFilter extends javax.swing.filechooser.FileFilter {
            public boolean accept(File f) {
                if (f.getName().endsWith(".X")) {
                    return true;
                }
                if (f.isDirectory()) {
                    return true;
                }
                return false;
            }
    
            public String getDescription() {
                return "Sketch Folders";
            }
        }
    
        public void saveAs() {
            JFileChooser fc = new JFileChooser();
            javax.swing.filechooser.FileFilter filter = new SketchFolderFilter();
            fc.setFileFilter(filter);
    
            javax.swing.filechooser.FileView view = new SketchFileView();
            fc.setFileView(view);
    
            fc.setCurrentDirectory(new File("."));
    
            int rv = fc.showSaveDialog(null);
    
            System.err.println("Option: " + rv);
            if (rv == JFileChooser.APPROVE_OPTION) {
                File newFile = fc.getSelectedFile();
                System.err.println("Save As: " + newFile.getAbsolutePath());
            }
        }
    
        public static void main(String[] args) {
            fctest main = new fctest();
            main.saveAs();
        }
    }
    

1 个答案:

答案 0 :(得分:3)

  

如果您输入现有复合文档的名称并单击“保存”,则表示该操作就像您单击“取消”一样。

我认为您的意思是文件选择器关闭,但您希望它保持打开状态以便让用户有机会更改文件名。如果是这样,那么您可以覆盖JFileChooser的approveSelection()方法以显示确认对话框:

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;

public class FileChooserSave
{
    private static void createAndShowUI()
    {
        final JFileChooser chooser = new JFileChooser( new File(".") )
        {
            public void approveSelection()
            {
                if (getSelectedFile().exists())
                {
                    int n = JOptionPane.showConfirmDialog(
                        this,
                        "Do You Want to Overwrite File?",
                        "Confirm Overwrite",
                        JOptionPane.YES_NO_OPTION);

                    if (n == JOptionPane.YES_OPTION)
                        super.approveSelection();

                }
                else
                    super.approveSelection();
            }
        };

        chooser.setSelectedFile( new File("something.rob") );
        int returnVal = chooser.showSaveDialog(null);

        if(returnVal == JFileChooser.APPROVE_OPTION)
        {
           System.out.println(chooser.getSelectedFile() );
        }
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

编辑:

我添加了以下内容:

fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

它允许您直接选择"化合物"但你也可以选择一个非复合目录,这是一些进步。

然后我覆盖" approveSelection"文件选择器的方法只批准复合目录,现在它似乎工作得相当好?

必须承认我不知道为什么它会做它所做的事情所以更多的是蛮力方法。

以下是我测试的代码:

import java.io.*;
import javax.swing.*;


class fctest {

    public class SketchFileView extends javax.swing.filechooser.FileView
    {
        @Override
        public Boolean isTraversable(File f) {
            if (f.getName().startsWith("images")) {
                return false;
            }
            if (f.isDirectory()) {
                return true;
            }
            return false; // added this
        }
    }

    public class SketchFolderFilter extends javax.swing.filechooser.FileFilter {
        public boolean accept(File f) {
            if (f.getName().startsWith("images")) {
                return true;
            }
            if (f.isDirectory()) {
                return true;
            }
            return false;
        }

        public String getDescription() {
            return "Sketch Folders";
        }
    }

    public void saveAs() {
        JFileChooser fc = new JFileChooser()
        {
            public void approveSelection()
            {
                if (getSelectedFile().getName().startsWith("images"))
                    super.approveSelection();
            }
        };

        javax.swing.filechooser.FileFilter filter = new SketchFolderFilter();
        fc.setFileFilter(filter);

        javax.swing.filechooser.FileView view = new SketchFileView();
        fc.setFileView(view);

//      fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        fc.setCurrentDirectory(new File("."));
        fc.setSelectedFile( new File("blog") );

        int rv = fc.showSaveDialog(null);

        System.err.println("Option: " + rv);
        if (rv == JFileChooser.APPROVE_OPTION) {
            File newFile = fc.getSelectedFile();
            System.err.println("Save As: " + newFile.getAbsolutePath());
        }
    }

    public static void main(String[] args) {
        fctest main = new fctest();
        main.saveAs();
    }
}