3

我目前正在编写游戏,并且已经到了需要用户能够保存诸如 JFrame 大小、键绑定等首选项的地步。用户将通过从我的网站下载的 jar 运行游戏.

我决定使用“java.util.prefs.Preferences”下的 Preferences API。在阅读文档之类的东西时,我还是很陌生,希望有人能帮我解释一下。

到目前为止,我有这样的事情:

Preferences prefs = Preferences.userNodeForPackage(com.custardgames.horde2d.Game.class);
prefs.put(name, value);

那么,我如何才能将首选项文件保存在用户计算机上?现在,如果我再次运行程序并尝试:

Preferences prefs = Preferences.userNodeForPackage(com.custardgames.horde2d.Game.class);
System.out.println(prefs.get(name, null));

如果没有保存任何内容,它只返回 null 这是默认值。我知道我错过了实际保存文件的重要部分,然后以正确的方式打开它,但并没有从谷歌搜索中得到太多。

提前非常感谢!

编辑:仅供参考,为了阅读图像,我使用的是这样的东西:

BufferedImage currentImage=ImageIO.read(this.getClass().getClassLoader().getResource("res/images/image.jpg"));

我希望能够对偏好做类似的事情。

编辑: name并且value都是预先声明的字符串变量。

4

2 回答 2

2

您确定该name变量具有相同的值吗?因为它应该返回正确的存储值——也许值是空的?

尝试在存储和获取之前将它们打印出来。

您还可以尝试在存储后刷新首选项:

prefs.flush();

如果您使用的是 Windows,您可以检查首选项是否存储regedit

\HKEY_CURRENT_USER\Software\JavaSoft\Prefs\<your package path>

在 Linux 中我不确定,但你的主目录中应该有一个隐藏文件夹。就像是

~/.java/.prefs/<package path>

注册首选项

我开发了一个 JFrame 使用首选项来存储框架的最后位置和大小。你可以在这里查看:

可记忆框架

该库位于: java-utils

您可能感兴趣的一段代码:

    public void saveSize() {
            Preferences preferences = Preferences.userNodeForPackage(this.getClass());
            preferences.put(getId() + X_KEY, String.valueOf(getLocation().x));
            preferences.put(getId() + Y_KEY, String.valueOf(getLocation().y));
            preferences.put(getId() + W_KEY, String.valueOf(getSize().width));
            preferences.put(getId() + H_KEY, String.valueOf(getSize().height));
            preferences.put(getId() + MAX_KEY,
                            String.valueOf((getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH));
            try {
                    preferences.flush();
            }
            catch(BackingStoreException e) {
                    e.printStackTrace();
            }
    }

    public void setSavedSize() {
            Preferences preferences = Preferences.userNodeForPackage(this.getClass());
            String xs = preferences.get(getId() + X_KEY, "");
            String ys = preferences.get(getId() + Y_KEY, "");
            String ws = preferences.get(getId() + W_KEY, "");
            String hs = preferences.get(getId() + H_KEY, "");
            String max = preferences.get(getId() + MAX_KEY, "");

            if(max != null && !max.trim().isEmpty() && Boolean.valueOf(max) == true) {
                    setDefaultSize();
                    setExtendedState(JFrame.MAXIMIZED_BOTH);
                    return;
            }

            if(xs.length() == 0 || ys.length() == 0 || ws.length() == 0 || hs.length() == 0) {
                    setDefaultSize();
            }
            else {
                    sizeFromPreferences = true;
                    int x = Integer.parseInt(xs);
                    int y = Integer.parseInt(ys);
                    int w = Integer.parseInt(ws);
                    int h = Integer.parseInt(hs);
                    setLocation(x, y);
                    setSize(w, h);
            }
    }

编辑

如果您想创建某种设置存储系统,您可以使用与RememberableFrame使用中前缀相同的约定。

RememberableFrame我使用:

    private String getId() {
            return this.getClass().getSimpleName() + id;
    }

id开发人员提供的自定义字符串或空字符串在哪里。但请记住,您要设置的属性的键有长度限制。

从 API:

static int  MAX_KEY_LENGTH 
      Maximum length of string allowed as a key (80 characters).
static int  MAX_NAME_LENGTH 
      Maximum length of a node name (80 characters).
static int  MAX_VALUE_LENGTH 
      Maximum length of string allowed as a value (8192 characters).

您也可以考虑使用专门用于“存储设置”目的的类。例如类KeyboardSettings,甚至在不同的包中。

于 2013-05-18T19:04:16.513 回答
1

作为替代方案,我个人更喜欢保存配置文件(并避免使用注册表),Properties该类可以很好地启用它。就像您想象的那样,您通常在用户计算机上的逻辑位置创建文件,通常是应用程序启动的目录或用户的主目录。

jGrep,我不久前编写的一个 Swing 应用程序正是这样做的,欢迎您使用相关代码作为起点。源代码是一个公共的 Mercurial 存储库,jGrep 源代码,相关行从JGrep.java:140开始。

本质上,您需要执行三个步骤(下面的代码片段大致基于 jGrep 代码库):

  1. 确定文件的保存位置:

    jGrep 可以作为 JNLP、独立 Jar 或已安装的 Windows 应用程序运行。在第一种和第二种情况下,我们希望应用程序尽可能自包含,因此我们将属性文件保存在启动应用程序的目录中。在后一种情况下(或者如果您在 Linux 或 Mac 上“安装”它),它改为写入用户的主目录,使多个用户能够共享应用程序而不共享状态。

    public File getConfigFile(boolean isInstalled) {
      String filename = ".jGrep.conf"; // The . prefix means "hidden file" in Unix
      return isInstalled ? // indicates the application is "installed"
        new File(getUserDir(), filename) : // identifies the user's home directory
        new File(filename); // default to a file in the current directory
    }
    
  2. 在启动时/需要时加载您的属性文件(如果存在):

    如果文件不存在、无法读取或包含意外内容,此方法可能会引发多个异常。您将通过显式处理这些情况并为他们提供有用的错误消息来为您的用户提供最好的服务,但是您可以只返回一个空的属性文件;jGrep 这样做,提供了一个无用的通用“无法打开”消息 - 我可能应该去修复这个:)

    public Properties loadProperties(File f)
    throws FileNotFoundException, IOException, IllegalArgumentException {
        Properties prop = new Properties();
      try(FileInputStream in = new FileInputStream(f)) {
        prop.load(in); // Reads from the input stream
      }
      // catch (Exception e) { } // uncomment to suppress errors
      return prop;
    
  3. 在退出时保存您的属性文件 / 每当用户询问时:

    现在我们以同样的方式保存我们的配置文件。同样,您可以在此处抑制错误,但我特别不建议对这种方法执行此操作,因为用户希望保存他们的数据,并且应该清楚地告知错误是什么如果你不能。

    public void saveProperties(Properties prop, File f)
    throws FileNotFoundException, IOException {
      try(FileOutputStream out = new FileOutputStream(f)) {
        prop.store(out, "AwesomeProgram configuration file");
        // return true; // uncomment if suppressing errors
      }
      // catch (Exception e) { return false; } // uncomment to suppress errors
    }
    

请注意,在这两种方法中,我们都没有表达编码 - 属性文件以拉丁语 1写出,并带有\uXXXX用于非拉丁字符的Java 转义码(即)。如果您希望您的文件是人类可读的,您可以将Reader/Writer对象传递给属性文件,它可以是您想要的任何编码(UTF-8)。

显然,如果您需要保存多个文件,只需将单独的文件保存/加载到不同的 Properties 对象即可。

于 2013-05-18T19:45:07.767 回答