【问题标题】:Remember window positions in swing记住秋千中的窗户位置
【发布时间】:2012-09-24 13:25:10
【问题描述】:

我有一个非常大的 Swing 应用程序,我想让它记住所有窗口、jframe 等的大小。因此,如果用户根据自己的喜好调整窗口大小,下次窗口看起来完全一样。

我是否有更好的选择来解决它,但在Preferences 中手动写入每个窗口的位置/大小?有什么方便的方法来存储 JTable 中的列顺序吗?可能是一些框架?只是不想写样板。

不幸的是,整个大型应用程序的序列化不是一种选择。

【问题讨论】:

  • AFAIK 没有支持这些东西的 API。因为也没有 API 可以从 XML 创建表。
  • 可能我错了,但这个任务似乎很常见,可能是一些框架已经存在,或者没有样板的简单方法。

标签: java swing user-interface persistence


【解决方案1】:

不,没有。不要忘记写主 JFrame 的边界(位置/大小)。

并且在恢复窗口位置后不要忘记检查该位置是否真的在显示的桌面区域中。屏幕配置可能会在应用程序运行之间发生变化(例如,当用户断开笔记本电脑与桌面显示器的连接时)。

【讨论】:

  • 你能解释一下如何检查位置是否在显示的桌面区域中吗?关闭应用程序时,我存储来自 Frame.getLocation() 的值(如果框架在主监视器左侧的监视器上关闭,则可能为负数)。所以简单地添加所有的屏幕宽度并没有帮助。
【解决方案2】:

有没有比在Preferences 中写入每个窗口的位置/大小更好的选择?

不,没有。不要忘记写出主要JFrame 的边界(位置/大小)。您可以将参数写入 XML 文件而不是首选项文件,但这是一个实现细节。

有没有什么方便的方法可以将列的顺序存储在JTable 中?

将列名和位置写入首选项文件。

虽然此任务很常见,但此任务的实施取决于您要从 GUI 中保存的内容。

我保存这些 GUI 参数的方法是创建一个模型类,其中包含您有兴趣保存的所有边界和其他参数。我会读取一个包含这些参数的 XML 文件并填充模型类中的字段。如果没有文件,我会设置默认值。

GUI 将使用模型类中的字段来构建 GUI。当用户修改 GUI 时,我会用新值更新模型类。

当用户关闭 GUI 时,我会将模型类写入 XML 文件。

我更喜欢使用 XML 文件而不是属性文件,因为它更容易查看模型的结构,而且我发现 XML 文件在 GUI 更改时更容易修改。

【讨论】:

  • 它只是 x,y,w,h,但以可伸缩性的名义,我实际上很想放弃 INI/属性或 XML 业务并直接跳到 JSON。 Jackson 是一个 JSON 库,免费、简单,您可以构建您的迷你对象来保存您想要的内容(包括复合数据类型),将其存储出来并重新加载。因为 JSON 很巧妙(在非常简单的文本中)序列化对象本身,您可以随着时间的推移增加该设置对象的复杂性,而不必担心如何将其映射到 XML 等。
【解决方案3】:

这是一个开始。以下代码将找到最顶层的容器并将所有子组件的边界保存到首选项文件中,然后可以使用该首选项文件进行恢复。这可能无法处理所有情况,但它适用于我的应用程序。以后的改动可以be tracked here

public class WindowBoundsRestorer
{
    private final String filename;
    private Properties properties;

    public WindowBoundsRestorer( String filename )
    {
        this.filename = filename;
    }

    private void setBounds( String key, Component c )
    {
        key = key + c.getName();

        String position = properties.getProperty( key );
        if ( c.getName() != null && ! StringUtils.isBlank( position ) )
        {
            String[] nums = position.split( "," );
            c.setBounds( Integer.parseInt( nums[0] ), Integer.parseInt( nums[1] ),
                         Integer.parseInt( nums[2] ), Integer.parseInt( nums[3] ) );
        }

        if ( c instanceof Container )
        {
            key = key + "/";
            Container container = (Container) c;
            for ( Component child : container.getComponents() )
               setBounds( key, child );
        }
    }

    /**
     * Loads the properties from the .xml file and sets all named windows with a matching
     * name.
     *
     * @param component Any component in the Swing app.  The top-most container will be
     * determined from this component.
     */
    public void restore( Component component )
    {
        properties = new Properties();
        InputStream is = null;
        try
        {
            is = new FileInputStream( filename );
            properties.loadFromXML( is );
        }
        catch ( IOException e )
        {
            e.printStackTrace();
            return;
        }
        finally
        {
            IOUtils.closeQuietly( is );
        }

        Component top = component;
        while ( top.getParent() != null )
            top = top.getParent();

        setBounds( "", top );
    }

    private void getBounds( String key, Component c )
    {
        key = key + c.getName();
        String position = String.format( "%d,%d,%d,%d", c.getX(), c.getY(), c.getWidth(), c.getHeight() );
        properties.setProperty( key, position );
        if ( c instanceof Container )
        {
            key = key + "/";
            Container container = (Container) c;
            for ( Component child : container.getComponents() )
                getBounds( key, child );
        }
    }

    public void save( Component component )
    {
        Component top = component;
        while ( top.getParent() != null )
            top = top.getParent();

        properties = new Properties();
        getBounds( "", top );

        OutputStream os = null;
        try
        {
            os = new FileOutputStream( filename );
            properties.storeToXML( os, "Browser" );
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
        finally
        {
            IOUtils.closeQuietly( os );
        }
    }
}

【讨论】:

    【解决方案4】:

    无论您想在下一次调用时记住什么(窗口位置等),都可以写入文件,然后从启动时读取该文件。它需要持久化到磁盘,没有人知道你真正想要保存什么(可能不是时间敏感数据),任何“自动”解决方案都无法工作,除非它也保存时间敏感数据。

    您是否希望您的应用程序恢复显示已删除的记录?应该不会吧。

    【讨论】:

      【解决方案5】:

      我一直为此使用java.util.Preferences,但javax.jnlp.PersistenceService“即使对于在受限执行环境中运行的应用程序也有效”。

      【讨论】:

        猜你喜欢
        • 2014-09-02
        • 2011-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多