• title: PersistenceServiceを使ってJFrameの位置・サイズを記憶 tags: [ServiceManager, PersistenceService, JFrame, SwingWorker, XMLEncoder, XMLDecoder] author: aterai pubdate: 2012-03-26T15:45:39+09:00 description: ServiceManagerからPersistenceServiceを取得し、JFrameなどの位置・サイズの保存、呼び出しを行います。

概要

ServiceManagerからPersistenceServiceを取得し、JFrameなどの位置・サイズの保存、呼び出しを行います。

サンプルコード

final WindowState ws = new WindowState();
SwingWorker<WindowAdapter,Void> worker = new SwingWorker<WindowAdapter,Void>() {
  @Override public WindowAdapter doInBackground() {
    PersistenceService ps;
    BasicService bs;
    try{
      bs = (BasicService)ServiceManager.lookup("javax.jnlp.BasicService");
      ps = (PersistenceService)ServiceManager.lookup("javax.jnlp.PersistenceService");
    }catch(UnavailableServiceException use) {
      use.printStackTrace();
      ps = null;
      bs = null;
    }
    if(ps != null && bs != null) {
      final PersistenceService persistenceService = ps;
      final URL codebase = bs.getCodeBase();
      loadWindowState(persistenceService, codebase, ws);
      return new WindowAdapter() {
        @Override public void windowClosing(WindowEvent e) {
          JFrame f = (JFrame)e.getComponent();
          if(f.getExtendedState()==JFrame.NORMAL) {
            ws.setSize(f.getSize());
            ws.setLocation(f.getLocationOnScreen());
          }
          saveWindowState(persistenceService, codebase, ws);
        }
      };
    }else{
      return null;
    }
  }
  @Override public void done() {
    WindowAdapter wa = null;
    try{
      wa = get();
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }catch(Exception e) {
      e.printStackTrace();
    }
    JFrame frame = new JFrame();
    if(wa!=null) frame.addWindowListener(wa);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new MainPanel());
    frame.setSize(ws.getSize());
    frame.setLocation(ws.getLocation());
    frame.setVisible(true);
  }
};
worker.execute();
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、PersistenceServiceで確保したファイルに、HashMap<String, Serializable>に格納したJFrameの位置、サイズをXMLEncoderXMLDecoderを使って読み書きしています。


  • Windows 7JDK 1.7.0_03では、C:\Users\(user)\AppData\LocalLow\Sun\Java\Deployment\cache\6.0\muffin以下にmufファイルなどが作成されるようです。
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_03" class="java.beans.XMLDecoder">
 <object class="java.util.HashMap">
  <void method="put">
   <string>location</string>
   <object idref="Point0"/>
  </void>
  <void method="put">
   <string>size</string>
   <object idref="Dimension0"/>
  </void>
 </object>
</java>

  • XMLEncoderで直接上記のJFrameを書きだす場合、以下のようなIllegalAccessExceptionが発生する
java.lang.IllegalAccessException: Class sun.reflect.misc.Trampoline can not access a member of class MainPanel$2 with modifiers ""
Continuing ...
  • 回避方法
    • WindowListenerを実装する匿名内部クラスをpublic class(Java Beans)に変更する
    • または、removeWindowListenerで取り除く
    • または、XMLEncoder#setExceptionListener(...)で、何もしないExceptionListenerを設定し、警告を捨ててしまう
//package example;
//-*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
//@homepage@
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import javax.swing.*;

public class MainPanel extends JPanel {
  private static final String PROPERTIES_XML = "properties.xml";
  public MainPanel() {
    super(new BorderLayout());
    JTextArea textArea = new JTextArea();
    try(Reader fr = new InputStreamReader(
        new FileInputStream(PROPERTIES_XML), "UTF-8")) {
      textArea.read(fr, "File");
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    add(new JScrollPane(textArea));
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {
      e.printStackTrace();
    }
    JFrame frame = loadFrame();
    frame.setVisible(true);
  }
  private static JFrame loadFrame() {
    JFrame frame = null;
    try(XMLDecoder d = new XMLDecoder(new BufferedInputStream(
        //MainPanel.class.getResourceAsStream(PROPERTIES_XML)))) {
        new FileInputStream(PROPERTIES_XML)))) {

      frame = (JFrame)d.readObject();
      //d.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    if (frame == null) {
      frame = new JFrame("title");
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      frame.getContentPane().add(new MainPanel());
      frame.setSize(320, 240);
      frame.setLocationRelativeTo(null);
    }
    frame.addWindowListener(new WindowAdapter() {
      @Override public void windowClosing(WindowEvent e) {
        JFrame frame = (JFrame)e.getComponent();
        frame.removeWindowListener(this);
        File file = new File(PROPERTIES_XML);
        try(XMLEncoder xe = new XMLEncoder(new BufferedOutputStream(
                                               new FileOutputStream(file)))) {
          xe.setExceptionListener(new ExceptionListener() {
            @Override public void exceptionThrown(Exception exception) {
              //XXX:
              exception.printStackTrace();
            }
          });
          xe.writeObject(frame);
          xe.flush();
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    });
    return frame;
  }
}

参考リンク

コメント