Java JFileChooser";另存为;复合文档-覆盖现有文档

Java JFileChooser";另存为;复合文档-覆盖现有文档,java,swing,jfilechooser,Java,Swing,Jfilechooser,我正在开发一个使用复合文档存储数据的系统 一切都运行得很好-我甚至有漂亮的图标,双击打开对话框 我的问题是“另存为”对话框。如果我保存为尚未存在的复合文档,则一切正常。如果我双击一个现有的复合文档,那么我的代码会询问您是否要覆盖它,这也可以 但问题是,如果您键入现有复合文档的名称并单击“保存”,它的行为就好像您单击了“取消” 我使用一个文件过滤器和一个文件视图来配置所有文件的显示和过滤 以下是我的主要对话框打开功能: public void saveAs() { JFileChooser

我正在开发一个使用复合文档存储数据的系统

一切都运行得很好-我甚至有漂亮的图标,双击打开对话框

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

但问题是,如果您键入现有复合文档的名称并单击“保存”,它的行为就好像您单击了“取消”

我使用一个文件过滤器和一个文件视图来配置所有文件的显示和过滤

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

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
澄清: 据我所知,这纯粹是复合文档的问题

重申这一设想:

  • 打开JFileChooser将数据保存到复合文档中
  • 您有一个现有的复合文档列表
  • 双击其中一个-将返回APPROVE_选项索引,getSelectedFile()将返回文件对象,或者
  • 键入不存在的复合文档的名称,然后按“保存”或返回键。返回APPROVE\u选项索引,getSelectedFile()返回文件对象,但
  • 键入现有复合文档的名称,然后按“保存”或返回键。返回CANCEL_选项索引,getSelectedFile()返回null,或
  • 你按下“取消”按钮。返回CANCEL_选项索引,getSelectedFile()返回null
  • 然后,将文件对象与您自己的代码一起使用,以生成复合文档——通常删除旧文档(如果它在那里,并且用户说他想覆盖),并创建目录并用您的文件填充它
  • (无论如何,在我看来)是错的。它应该返回APPROVE_选项,getSelectedFile()应该返回一个File对象,该对象表示您在JFileChooser所在目录中键入的文件(即与3相同)

    编辑: 缩小范围。当文件夹不可遍历时,JFileChooser似乎不喜欢它,而您将其名称输入选择器并单击return-它尝试遍历到该文件夹,但失败惨重,并且不知道如何处理它,因此将您从返回0的JFileChooser中转储。这里有一个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();
        }
    }
    
    如果键入现有复合文档的名称并单击“保存”,则其行为与单击“取消”类似


    我认为您的意思是文件选择器关闭,但您希望它保持打开状态,以便用户有机会更改文件名。如果是,则可以覆盖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();
        }
    }
    
    如果键入现有复合文档的名称并单击“保存”,则其行为与单击“取消”类似


    我认为您的意思是文件选择器关闭,但您希望它保持打开状态,以便用户有机会更改文件名。如果是,则可以覆盖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();
        }
    }
    

    “我想你的意思是文件选择器关闭,但你希望它保持打开状态,以便用户有机会更改文件名。”不,我希望它关闭,但关闭时就像按“保存”一样,然后返回路径/path/to/my/dir/enteredfilename,与文件不存在或双击现有文件时一样。出于好奇,我尝试了该代码,但效果相同。这就像JFileChooser(错误地)假设我将保存一个普通文件,所以输入一个作为目录(复合文档)存在的名称肯定是错误的,所以取消。顺便说一句,所有这些过去在使用FileDialog而不是JFileChooser时都可以正常工作(尽管看起来很糟糕)。
    我只是出于好奇才尝试了这些代码,结果都是一样的。
    也许你不了解JFileChooser的功能。选择的文件实际上并没有为您“保存”该文件。您需要编写代码将文件保存到磁盘。所有文件选择器都会为您获取文件名。当您单击“保存”按钮,然后在确认对话框中单击“是”时,我提供的代码将返回此文件名。是的,我理解所有这些。我有代码来保存。那很好。问题是“所有的文件选择器都会为您获取文件名。”是错误的。如果:1,它将为您命名。“复合文档”不存在,请键入名称,或2:“复合文档”存在,请键入名称