【问题标题】:JFileChooser "Save As" compound document - overwrite existingJFileChooser“另存为”复合文档 - 覆盖现有
【发布时间】:2014-05-17 14:12:53
【问题描述】:

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

一切都运行良好 - 我什至有漂亮的图标和双击打开在打开的对话框上工作。

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

但是,如果您输入现有复合文档的名称并单击“保存”,则会出现问题,就像您单击了“取消”一样。

我正在使用 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 对象与您自己的代码一起使用来生成 复合文档 - 通常会删除旧文档(如果它存在并且用户说他想要覆盖)并创建目录并填充它与您的文件。

(在我看来)是 5 是错误的。它应该返回 APPROVE_OPTION 并且 getSelectedFile() 应该返回一个 File 对象,该对象代表您键入的文件,该文件驻留在 JFileChooser 所在的目录中(即与 3 相同)。

编辑:

缩小范围。当文件夹不可遍历并且您将其名称输入选择器并按回车时,看起来 JFileChooser 不喜欢它 - 它试图遍历它并且它失败了,并且不知道如何处理它,因此,只需将您从返回 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();
    }
}

【问题讨论】:

  • 我查了“复合文档”的意思。在我看来,它只是一个可能被“Word”或“Excel”使用的文件。 5.You type the name of an existing compound document and either press "Save" or the return key. The CANCEL_OPTION index is returned, and getSelectedFile() returns null, or - 当我输入“abc.xlsx”然后按“保存”时,控制台上会显示“abc.xlsx”。文件名只是一个文件名。 File API 不知道 File 的内容代表什么。我在 Windows 7 上使用 JDK7。也许文件名在另一个平台上意味着不同的东西。
  • 我注意到您正在使用自定义过滤器和 FileView。这些可能是问题吗?
  • 在 Java 中,“复合文档”的概念只是一个包含其他文件的文件夹,其中整个文件夹代表要加载的文档。请参阅 Swing 帮助 (docs.oracle.com/javase/tutorial/uiswing/components/…) 中有关“如何使用文件选择器”的页面。它在“Boolean isTraversable(File f)”标题下提及它们。过滤器和视图是复合文档概念起作用的原因。
  • 我刚刚剥离了我的代码以尝试制作 SSCCE,但剥离后的版本运行正常。它一定与过滤有关。编辑:是的,这与过滤系统有关。它破坏了 JFileChooser。
  • 是的,它看起来像是 isTraversable() 功能。没有那个,如果你输入一个现有的目录名并点击返回,它就会变成那个目录。如果它不可遍历,那么它不知道如何处理它,所以它惨遭失败。它想更改目录但不能。我也会把我的 SSCCE 贴在上面,你可以自己试试。

标签: java swing jfilechooser


【解决方案1】:

如果您输入现有复合文档的名称并单击“保存”,它的行为就像您单击了“取消”一样。

我认为您的意思是文件选择器关闭,但您希望它保持打开状态,让用户有机会更改文件名。如果是这样,那么您可以覆盖 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 正常工作(虽然看起来很糟糕)。
  • I just tried that code out of curiosity, and it works just the same. 也许您不了解 JFileChooser 的功能。文件选择实际上并没有为您“保存”文件。您需要编写代码将文件保存到磁盘。所有文件选择器都会为您获取文件的名称。当您单击“保存”按钮然后在确认对话框中单击“是”时,我提供的代码将返回此文件名。
  • 是的,是的,我明白这一切。我有代码来保存。没关系。问题是“所有文件选择器都会为您获取文件名。”是错误的。如果出现以下情况,它会为您获取名称: 1. “复合文档”不存在并且您键入名称,或者 2:“复合文档”确实存在并且您双击它。如果确实存在,但您输入了名称,则“保存”按钮的作用类似于“取消”按钮,getSelectedFile() 为 null,返回值为 1 而不是 0(保存为索引 0,取消为索引 1) .我想简单的文件没问题,但复合文件不行。
  • 宾果游戏! setFileSelectionMode 是缺少的!这现在完全按照我的意愿工作。谢谢!
猜你喜欢
  • 2023-02-17
  • 2015-09-23
  • 1970-01-01
  • 2012-11-13
  • 2018-05-20
  • 2015-01-20
  • 2013-10-10
  • 2013-11-25
相关资源
最近更新 更多