一个用户要求我在应用程序重新启动时保留JFileChooser的状态。具体而言,他要求我保留详细信息/列表视图类型选择的状态。两个相关问题:
如何在详细视图中启动JFileChooser?
按日期排序的文件启动JFileChooser
这两个都显示了使用特定默认行为启动JFileChooser的方法。缺失的部分是一种确定用户何时处于活动状态(视图类型,排序顺序)的方法,当JFileChooser窗口关闭时,以便稍后保存和恢复。有什么想法吗?
Properties
API或Preferences
API来保存/恢复用户数据。
PropertyChangeListener
并侦听viewType
事件。然后,您将使用新值更新用户数据。RowSorter
添加RowSorterListener
以侦听排序顺序的更改。然后,您需要保存排序顺序。我不知道存储排序数据的最佳方法。JFileChooser
添加一个PropertyChangeListener
,当在列表和详细信息之间切换时它从来不会触发。我尝试添加一个没有指定要监听的属性的PropertyChangeListener
,但在创建/显示窗口时会触发几个事件,但是在打开窗口时,当更改视图类型时根本不会触发任何事件。我的做法有问题吗? - danBhentschelFilePane
而不是JFileChooser
。我认为这样会起作用。 - danBhentschelFilePane
? - camickrFilePane
是“受限制”的非API Swing代码的一部分。通常情况下,我会感到不舒服使用这个代码,但在这种情况下,JVM与我的应用程序捆绑在一起,因此我相对于实现变化是相对受保护的。 - danBhentschelsun/swing/FilePane
,如下所述:
访问限制:由于对所需库..\jre\lib\rt.jar的限制而无法访问
编辑:清理资源泄漏JFileChooser
实例的情况,因此我改进了它,提供了一个可在try-with-resources语句中使用的AutoCloseable
实体。对于这种变动造成的不便,我深感抱歉。import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.prefs.Preferences;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.swing.FilePane;
import darrylbu.util.SwingUtils;
@SuppressWarnings("restriction")
public class JFileChooserPersisterFactory {
private static final String VIEW_TYPE_LIST = "viewTypeList"; //$NON-NLS-1$
private static final String VIEW_TYPE_DETAILS = "viewTypeDetails"; //$NON-NLS-1$
private static final String CHOOSER_CLOSING_PROPERTY = "JFileChooserDialogIsClosingProperty"; //$NON-NLS-1$
private static final String VIEW_TYPE_PROPERTY = "viewType"; //$NON-NLS-1$
private static final String IS_DETAILS = "isDetails"; //$NON-NLS-1$
private static final String SORT_ORDER = "sortOrder"; //$NON-NLS-1$
private JFileChooserPersisterFactory() {
}
public static JFileChooserPersister createJFileChooserPersister() {
JFileChooserPersisterImpl persister = new JFileChooserPersisterImpl();
persister.init();
return persister;
}
public interface JFileChooserPersister extends AutoCloseable {
JFileChooser getJFileChooser();
@Override
void close();
}
private static class JFileChooserPersisterImpl implements JFileChooserPersister {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Preferences persistentPrefs = Preferences.userNodeForPackage(getClass());
private final JFileChooser chooser;
private boolean isDetails;
private OnChooserClosing chooserClosingListener;
private FilePane filePane;
private OnViewTypeChanged viewTypeChangedListener;
public JFileChooserPersisterImpl() {
chooser = new JFileChooser();
}
public void init() {
restoreSettings();
registerForViewTypeChangeEvents();
chooserClosingListener = new OnChooserClosing();
chooser.addPropertyChangeListener(CHOOSER_CLOSING_PROPERTY, chooserClosingListener);
}
@Override
public JFileChooser getJFileChooser() {
return chooser;
}
private void persistSettings() {
persistentPrefs.putBoolean(IS_DETAILS, isDetails);
if (isDetails) persistSortOrder();
}
private void persistSortOrder() {
byte[] serializedSortOrder = serializeSortOrder();
if (serializedSortOrder != null)
persistentPrefs.putByteArray(SORT_ORDER, serializedSortOrder);
}
private byte[] serializeSortOrder() {
List<? extends SortKey> keys = getRowSorter().getSortKeys();
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(byteStream)) {
out.writeObject(new SortOrderInfo(keys));
return byteStream.toByteArray();
} catch (IOException e) {
logger.error("Could not serialize JFileChooser row sort order.", e); //$NON-NLS-1$
}
return null;
}
private void restoreSettings() {
isDetails = persistentPrefs.getBoolean(IS_DETAILS, false);
if (isDetails) {
setToDetailsView();
applyInitialSortOrder();
} else {
setToListView();
}
}
private void setToDetailsView() {
Action details = chooser.getActionMap().get(VIEW_TYPE_DETAILS);
details.actionPerformed(null);
}
private void setToListView() {
Action details = chooser.getActionMap().get(VIEW_TYPE_LIST);
details.actionPerformed(null);
}
private void applyInitialSortOrder() {
byte[] serializedSortOrder = persistentPrefs.getByteArray(SORT_ORDER, null);
if (serializedSortOrder == null) return;
ByteArrayInputStream byteStream = new ByteArrayInputStream(serializedSortOrder);
try (ObjectInputStream in = new ObjectInputStream(byteStream)) {
setSortInfo((SortOrderInfo) in.readObject());
} catch (IOException | ClassNotFoundException e) {
logger.error("Could not deserialize JFileChooser row sort order.", e); //$NON-NLS-1$
}
}
private void setSortInfo(SortOrderInfo info) {
info.setSortOrder(getRowSorter());
}
private RowSorter<?> getRowSorter() {
JTable table = SwingUtils.getDescendantsOfType(JTable.class, chooser).get(0);
RowSorter<?> rowSorter = table.getRowSorter();
return rowSorter;
}
private void registerForViewTypeChangeEvents() {
filePane = SwingUtils.getDescendantsOfType(FilePane.class, chooser).get(0);
viewTypeChangedListener = new OnViewTypeChanged();
filePane.addPropertyChangeListener(VIEW_TYPE_PROPERTY, viewTypeChangedListener);
}
private final class OnChooserClosing implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
persistSettings();
}
}
private class OnViewTypeChanged implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
isDetails = ((int) evt.getNewValue()) == FilePane.VIEWTYPE_DETAILS;
}
}
public static class SortOrderInfo implements Serializable {
private static final long serialVersionUID = -5393878644049680645L;
private final List<ColumnSortInfo> keyInfo = new ArrayList<>();
public SortOrderInfo(List<? extends SortKey> keys) {
for (SortKey sortKey : keys) {
keyInfo.add(new ColumnSortInfo(sortKey));
}
}
public void setSortOrder(RowSorter<?> rowSorter) {
rowSorter.setSortKeys(makeSortKeys());
}
private List<SortKey> makeSortKeys() {
List<SortKey> keys = new ArrayList<>();
for (ColumnSortInfo info : keyInfo) {
keys.add(info.makeSortKey());
}
return keys;
}
public static class ColumnSortInfo implements Serializable {
private static final long serialVersionUID = 5406885180955729893L;
private final SortOrder sortOrder;
private final int column;
public ColumnSortInfo(SortKey sortKey) {
column = sortKey.getColumn();
sortOrder = sortKey.getSortOrder();
}
public SortKey makeSortKey() {
return new SortKey(column, sortOrder);
}
}
}
@Override
public void close() {
chooser.removePropertyChangeListener(CHOOSER_CLOSING_PROPERTY, chooserClosingListener);
filePane.removePropertyChangeListener(VIEW_TYPE_PROPERTY, viewTypeChangedListener);
}
}
}