问题
I have been doing research on here and have been searching for a solution to the problem. I am new to java so I don't know all of the syntax. I am trying to get my code to transfer items from create methods for the save and load menu items. The save event handler should call a method save() and save the list of parts in the right panel to an XML file. The load event handler should call a method load() and it should display the unmarshalled data in the right panel. I am not familiar with JAXB or XML whatsoever. I have tried to see if anyone else has done something similar but I cannot complete the code. Can anyone help me out please? Below is the entire code. I have found the solution to make it exit using event handlers, but I am stuck on marshalling and unmarshalling the save and load menu items.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class Window {
private final JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Window window = new Window();
window.frame.setVisible(true);
});
}
public Window() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
initialize();
}
public void initialize() {
//Creating the Panel for Menu Bar
JPanel panel = new JPanel();
panel.setBounds(0, 0, 434, 23);
frame.getContentPane().add(panel);
panel.setLayout(new BorderLayout(0, 0));
//Creating the Menu File Bar
JMenuBar bar = new JMenuBar();
panel.add(bar, BorderLayout.NORTH);
JMenu file = new JMenu("File");
JMenuItem load = new JMenuItem("Load");
JMenuItem save = new JMenuItem("Save");
JMenuItem exit = new JMenuItem("Exit");
file.add(load);
load.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
}
});
file.add(save);
save.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
}
});
file.add(exit);
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
bar.add(file);
//Populate Left List with part names
final DefaultListModel parts = new DefaultListModel();
parts.addElement("Case");
parts.addElement("Motherboard");
parts.addElement("CPU");
parts.addElement("GPU");
parts.addElement("PSU");
parts.addElement("RAM");
parts.addElement("HDD");
final JList leftList = new JList(parts);
leftList.setBounds(10, 26, 142, 224);
frame.getContentPane().add(leftList);
//create right list
final DefaultListModel partSelected = new DefaultListModel();
final JList rightList = new JList(partSelected);
rightList.setBounds(282, 26, 142, 224);
frame.getContentPane().add(rightList);
//add event to the button to move items from left list to right list
JButton btnNewButton = new JButton(">>");
btnNewButton.addActionListener((ActionEvent arg0) -> {
for (Object selectedValue : leftList.getSelectedValuesList()) {
partSelected.addElement(selectedValue);
parts.removeElement(selectedValue);
int iSelected = leftList.getSelectedIndex();
if (iSelected == -1) {
return;
}
}
});
btnNewButton.setBounds(172, 86, 89, 23);
frame.getContentPane().add(btnNewButton);
//Remove Button
JButton remove = new JButton("<<");
remove.addActionListener((ActionEvent arg0) -> {
for (Object selectedValue : rightList.getSelectedValuesList()) {
parts.addElement(selectedValue);
partSelected.removeElement(selectedValue);
int selected = rightList.getSelectedIndex();
if (selected == -1) {
return;
}
}
});
remove.setBounds(172, 140, 89, 23);
frame.getContentPane().add(remove);
}
}
回答1:
Okay, so you first need to understand that JAXB is meant for the serialization of Objects to and from XML (via the use of annotations).
So, the first thing you need is some kind of object to serialize which contains your produces. A ListModel
would seem like a perfect choice, except, it's not setup for the task, it has no annotations by which JAXB can make decisions about what should be serialized or not
So, we need to create one...
@XmlRootElement
public static class ProductListModel extends AbstractListModel<String> {
private List<String> products;
public ProductListModel() {
products = new ArrayList<>(25);
}
@XmlElementWrapper
public List<String> getProducts() {
return products;
}
public void add(String product) {
products.add(product);
fireIntervalAdded(this, products.size() - 1, products.size() - 1);
}
public void remove(String product) {
int index = products.indexOf(product);
products.remove(product);
fireIntervalAdded(this, index, index);
}
@Override
public int getSize() {
return products.size();
}
@Override
public String getElementAt(int index) {
return products.get(index);
}
}
(Now, you could argue that something like ArrayList
might be better, but I'd say that's extending the class for little or no gain and would probably account for a lot more work as you try and figure out how to serialize it's buffer)
Next, we need access to the rightList
outside of the initialize
method, because your load
and save
methods will want this. We could use the ListModel
, but when we load it, we need something to apply it to any way...
//...
private JList rightList;
public void initialize() {
//...
final ProductListModel parts = new ProductListModel();
parts.add("Case");
parts.add("Motherboard");
parts.add("CPU");
parts.add("GPU");
parts.add("PSU");
parts.add("RAM");
parts.add("HDD");
leftList = new JList(parts);
leftList.setBounds(10, 26, 142, 224);
frame.getContentPane().add(leftList);
//create right list
final ProductListModel partSelected = new ProductListModel();
//JList rightList = new JList(partSelected);
rightList = new JList(partSelected);
This also changes the use of DefaultListModel
to ProductListModel
. Technically, this is only required for rightList
, but since I've changed the add
and remove
method names of the ListModel
(which will cause you a compiler error, so you will need to update those), it just makes life easier.
Now all we need are the save
and load
methods...
protected void save() {
ProductListModel model = (ProductListModel) rightList.getModel();
try {
File file = new File("Products.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(ProductListModel.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(model, file);
jaxbMarshaller.marshal(model, System.out);
} catch (JAXBException exp) {
exp.printStackTrace();
}
}
protected void load() {
try {
File file = new File("Products.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(ProductListModel.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
ProductListModel model = (ProductListModel) jaxbUnmarshaller.unmarshal(file);
rightList.setModel(model);
} catch (JAXBException exp) {
exp.printStackTrace();
}
}
Which you need to call from the ActionListener
s registered to your load
and save
JMenuItem
s
Take a look at JAXB hello world example (which I used to devise the solution) and Introduction to JAXB for more details.
You'll probably also want to have a look at How to Use Lists, How to Use Scroll Panes and Laying Out Components Within a Container to help improve your UI
Now, when you load the ProductList
, you will need to figure out how to modify the leftList
to remove the items which now appear in the right ;)
来源:https://stackoverflow.com/questions/31579019/marshal-save-menu-item-of-jlist-to-xml-and-unmarshal-load-menu-items