gpt4 book ai didi

java - GUI 反序列化期间 Swing 触发监听器

转载 作者:行者123 更新时间:2023-12-01 14:24:38 30 4
gpt4 key购买 nike

今天我遇到了一个非常讨厌的错误,该错误涉及在使用标准 Java 序列化 API 进行 GUI 反序列化期间触发 swing 监听器。简洁地解释如何复制此行为有点困难,因此我在下面发布了一个小测试用例。该测试用例不会引发任何异常,不会触发任何编译器警告,并且当然似乎没有明确定义的行为。 这是 Oracle 包互操作文档中的一个错误、灰色区域,还是只是 on-one 之前尝试过的东西?

为了说明我最初的用例,我尝试在从磁盘重新加载配置组件时自动更新 Assets 编辑器中的多个选项卡。

package com.ihateswing.ssce;

import java.awt.BorderLayout;

public class SSCE implements Serializable {



private class Internal extends JPanel {
private final JComboBox<String> m_cb = new JComboBox<String>();

Internal(final JComboBox<String> cb) {
cb.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
DefaultComboBoxModel<String> dcbm = new DefaultComboBoxModel<String>();
for (int i = 0; i < cb.getModel().getSize(); ++i) {
dcbm.addElement(cb.getModel().getElementAt(i));
}
m_cb.setModel(dcbm);
}
});
super.add(m_cb);
}
}

private JFrame frame;
private JComboBox<String> jce = new JComboBox<String>();

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SSCE window = new SSCE();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}


public SSCE() {
initialize();
}

private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
jce.setSelectedIndex(0); // <-- Seems to have undefined behavior?
}

private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

jce.setModel(new DefaultComboBoxModel<String>());
frame.getContentPane().add(new Internal(jce), BorderLayout.NORTH);
frame.getContentPane().add(jce, BorderLayout.CENTER);

JButton btnAddRandomItem = new JButton("Break");
btnAddRandomItem.addActionListener(new AbstractAction() {
private static final long serialVersionUID = 1L;
private int i;

public void actionPerformed(ActionEvent e) {
try {
((DefaultComboBoxModel<String>) jce.getModel())
.addElement(String.valueOf(i++));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(SSCE.this);
ByteArrayInputStream in = new ByteArrayInputStream(baos
.toByteArray());
ObjectInputStream oin = new ObjectInputStream(in);
oin.readObject();

// The line below updates 'Internal' as expected, uncomment
// to see...
// however with the listener fired from the serialization
// method, it breaks?
// jce.setSelectedIndex(0);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
frame.getContentPane().add(btnAddRandomItem, BorderLayout.SOUTH);
}

}

带有输出的示例(单击“Break”5 次)

package com.ihateswing.ssce;

import java.awt.BorderLayout;

public class SSCE implements Serializable {



private class Internal extends JPanel {
private final JComboBox<String> m_cb = new JComboBox<String>();

Internal(final JComboBox<String> cb) {
cb.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
DefaultComboBoxModel<String> dcbm = new DefaultComboBoxModel<String>();
for (int i = 0; i < cb.getModel().getSize(); ++i) {
dcbm.addElement(cb.getModel().getElementAt(i));
}
m_cb.setModel(dcbm);
System.out.println("Set Internal.m_cb's model with " + m_cb.getModel().getSize() + " elements");
}
});
super.add(m_cb);
}
}

private JFrame frame;
private JComboBox<String> jce = new JComboBox<String>();

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SSCE window = new SSCE();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}


public SSCE() {
initialize();
}

private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
jce.setSelectedIndex(0); // <-- Seems to have undefined behavior?
}

private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Internal internal = new Internal(jce);
jce.setModel(new DefaultComboBoxModel<String>());
frame.getContentPane().add(internal, BorderLayout.NORTH);
frame.getContentPane().add(jce, BorderLayout.CENTER);

JButton btnAddRandomItem = new JButton("Break");
btnAddRandomItem.addActionListener(new AbstractAction() {
private static final long serialVersionUID = 1L;
private int i;

public void actionPerformed(ActionEvent e) {
try {
((DefaultComboBoxModel<String>) jce.getModel())
.addElement(String.valueOf(i++));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(SSCE.this);
ByteArrayInputStream in = new ByteArrayInputStream(baos
.toByteArray());
ObjectInputStream oin = new ObjectInputStream(in);
oin.readObject();
System.out.println("After returning, Internal.m_cb's model size is " + internal.m_cb.getModel().getSize() + " elements");
// The line below updates 'Internal' as expected, uncomment
// to see...
// however with the listener fired from the serialization
// method, it breaks?
// jce.setSelectedIndex(0);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
frame.getContentPane().add(btnAddRandomItem, BorderLayout.SOUTH);
}

}

Set Internal.m_cb's model with 1 elements
Set Internal.m_cb's model with 1 elements
After returning, Internal.m_cb's model size is 1 elements
Set Internal.m_cb's model with 2 elements
After returning, Internal.m_cb's model size is 1 elements
Set Internal.m_cb's model with 3 elements
After returning, Internal.m_cb's model size is 1 elements
Set Internal.m_cb's model with 4 elements
After returning, Internal.m_cb's model size is 1 elements
Set Internal.m_cb's model with 5 elements
After returning, Internal.m_cb's model size is 1 elements

最佳答案

我认为您没有更新您认为正在更新的内容。如果附加到每个 println m_cb.hashCode(),这里是相同的输出。请注意,下面的“Set...”错误消息表明模型每次都在不同的 m_cb 实例上设置。

Set Internal.m_cb's model with 1 elements: 44160343
Set Internal.m_cb's model with 1 elements: 1436306574
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 2 elements: 2094948113
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 3 elements: 915510800
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 4 elements: 853795873
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 5 elements: 616759228
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 6 elements: 1385385632
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 7 elements: 1283006722
After returning, Internal.m_cb's model size is 1 elements: 44160343

在每个序列化中都会创建一个新的 m_cb 实例,并且您正在设置其模型 - 但这些新的组合框不会显示在您的框架中。

关于java - GUI 反序列化期间 Swing 触发监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17266076/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com