Java游戏XML关卡编辑器:实现用户自定义文件路径的问题
解决Java XML编辑器的文件路径自定义问题
当前代码的核心问题是XML文档在程序启动时就通过硬编码路径加载,无法响应后续用户选择的新文件。以下是重构后的完整实现,支持用户自定义XML文件路径:
import javax.swing.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.awt.*; import java.io.File; import org.w3c.dom.Document; import org.w3c.dom.Element; public class MapEdit { // 类成员变量,存储当前选中的文件和XML文档 private File selectedFile; private Document xmlDoc; private Element xmlRoot; public static void main(String[] args) { // 在事件调度线程中启动UI,符合Swing规范 SwingUtilities.invokeLater(MapEdit::new); } private MapEdit() { JFrame frame = new JFrame("Map Size Editor"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setMinimumSize(new Dimension(500, 250)); // 文件选择面板 JPanel filePanel = new JPanel(new BorderLayout(5, 5)); JTextField filePathField = new JTextField(); filePathField.setEditable(false); JButton browseBtn = new JButton("Browse XML File"); filePanel.add(new JLabel("Target XML File: "), BorderLayout.WEST); filePanel.add(filePathField, BorderLayout.CENTER); filePanel.add(browseBtn, BorderLayout.EAST); // 高度设置面板 JPanel heightPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); heightPanel.add(new JLabel("Rows of tiles to add (height): ")); JTextField heightInput = new JTextField(10); heightPanel.add(heightInput); // 宽度设置面板 JPanel widthPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); widthPanel.add(new JLabel("Rows of tiles to add (width): ")); JTextField widthInput = new JTextField(10); widthPanel.add(widthInput); // 操作按钮面板 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); JButton setSizeButton = new JButton("Set Size"); buttonPanel.add(setSizeButton); // 文件选择按钮监听 browseBtn.addActionListener(e -> { JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("XML Files", "xml")); int result = fileChooser.showOpenDialog(frame); if (result == JFileChooser.APPROVE_OPTION) { selectedFile = fileChooser.getSelectedFile(); filePathField.setText(selectedFile.getAbsolutePath()); // 加载XML文档 loadXmlDocument(); } }); // 设置尺寸按钮监听 setSizeButton.addActionListener(e -> { // 校验文件是否已加载 if (xmlDoc == null || xmlRoot == null) { JOptionPane.showMessageDialog(frame, "Please select an XML file first!", "Error", JOptionPane.ERROR_MESSAGE); return; } // 校验输入是否合法 String heightText = heightInput.getText().trim(); String widthText = widthInput.getText().trim(); if (heightText.isEmpty() || widthText.isEmpty()) { JOptionPane.showMessageDialog(frame, "Please enter valid numbers for height and width!", "Error", JOptionPane.ERROR_MESSAGE); return; } try { int addHeight = Integer.parseInt(heightText); int addWidth = Integer.parseInt(widthText); // 更新XML属性 float currentHeight = Float.parseFloat(xmlRoot.getAttribute("height")); float newHeight = currentHeight + (addHeight * 256); xmlRoot.setAttribute("height", String.valueOf(newHeight)); float currentWidth = Float.parseFloat(xmlRoot.getAttribute("width")); float newWidth = currentWidth + (addWidth * 256); xmlRoot.setAttribute("width", String.valueOf(newWidth)); // 保存修改后的XML TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(xmlDoc); StreamResult result = new StreamResult(selectedFile); transformer.transform(source, result); JOptionPane.showMessageDialog(frame, "Changes saved successfully!", "Success", JOptionPane.INFORMATION_MESSAGE); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(frame, "Please enter valid integers!", "Error", JOptionPane.ERROR_MESSAGE); } catch (Exception ex) { JOptionPane.showMessageDialog(frame, "Failed to save changes: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); } }); // 组装主面板 JPanel contentPanel = new JPanel(); contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); contentPanel.add(filePanel); contentPanel.add(Box.createVerticalStrut(15)); contentPanel.add(heightPanel); contentPanel.add(widthPanel); contentPanel.add(Box.createVerticalStrut(15)); contentPanel.add(buttonPanel); frame.setContentPane(contentPanel); frame.pack(); frame.setVisible(true); } // 加载XML文档的工具方法 private void loadXmlDocument() { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); xmlDoc = db.parse(selectedFile); xmlRoot = xmlDoc.getDocumentElement(); JOptionPane.showMessageDialog(null, "XML file loaded successfully!", "Success", JOptionPane.INFORMATION_MESSAGE); } catch (Exception ex) { JOptionPane.showMessageDialog(null, "Failed to load XML file: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); // 加载失败后重置变量 xmlDoc = null; xmlRoot = null; selectedFile = null; } } }
关键改动说明
- UI组件新增:添加文件选择文本框和浏览按钮,使用
JFileChooser限制仅选择XML文件,提升操作准确性 - 变量作用域调整:将XML相关变量改为类成员,确保文件选择和编辑操作能共享状态
- XML延迟加载:仅在用户选择文件后才执行XML解析,彻底摆脱硬编码路径的限制
- 输入校验增强:添加文件加载状态校验、输入空值校验和数字格式校验,避免运行时异常
- 用户体验优化:使用
JOptionPane提供直观的成功/错误提示,替代控制台输出 - Swing规范遵循:在事件调度线程中启动UI,避免线程安全问题
内容的提问来源于stack exchange,提问作者Remag Minecraft
相关产品推荐
相关产品推荐

