Java Swing栈式矩形管理应用代码优化及按面积排序并在DefaultListModel展示的实现咨询
问题解答
一、关于维护栈和DefaultListModel的实践优化
当前你分别向栈和DefaultListModel重复添加格式化字符串的方式不是良好实践,主要存在两个问题:
- 数据冗余:同一个矩形的信息被存储了两次(栈里的字符串和ListModel里的字符串),后续如果需要修改矩形属性,极易出现数据不一致的情况。
- 可维护性差:格式化字符串的代码重复出现,后续要调整展示格式时,得在多个地方修改,容易出错。
更好的实现方式:封装矩形数据模型
建议创建一个专门的Rectangle类来封装矩形的所有属性,这样既能统一存储数据,又能彻底避免重复代码:
public class Rectangle { private int x; private int y; private int width; private int height; public Rectangle(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } // 计算面积的方法 public int getArea() { return width * height; } // 重写toString,统一格式化展示内容 @Override public String toString() { return String.format("Upper left point: (%d,%d) width: %d height: %d Surface area: %d", x, y, width, height, getArea()); } // Getter方法(排序时需要用到属性) public int getX() { return x; } public int getY() { return y; } public int getWidth() { return width; } public int getHeight() { return height; } }
基于模型同步栈和ListModel
现在栈里存储Rectangle对象,DefaultListModel完全基于栈的内容同步更新,这样只需要维护栈这一个数据源,彻底避免数据不一致:
// 修改栈的定义为存储Rectangle对象 private Deque<Rectangle> stack = new ArrayDeque<>(); private DefaultListModel<String> dlm = new DefaultListModel<>(); // 添加矩形时的逻辑 btnAdd.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { DlgRectangle dlgRectangle = new DlgRectangle(); dlgRectangle.setVisible(true); if (dlgRectangle.isOk) { try { int x = Integer.parseInt(dlgRectangle.txtX.getText()); int y = Integer.parseInt(dlgRectangle.txtY.getText()); int width = Integer.parseInt(dlgRectangle.txtWidth.getText()); int height = Integer.parseInt(dlgRectangle.txtHeight.getText()); Rectangle rect = new Rectangle(x, y, width, height); stack.addFirst(rect); // 同步更新ListModel,直接复用rect的toString方法 dlm.add(0, rect.toString()); System.out.println(stack); } catch (NumberFormatException ex) { // 处理输入非数字的情况,比如弹出提示框 JOptionPane.showMessageDialog(null, "Please enter valid numbers!"); } } } }); // 删除矩形时的逻辑 btnDelete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!stack.isEmpty()) { stack.pop(); dlm.remove(0); System.out.println(stack); } else { System.out.println("Stack is empty"); JOptionPane.showMessageDialog(null, "Stack is empty!"); } } });
这样改造后,你只需要维护栈这一个数据源,ListModel完全基于栈的内容更新,不仅减少了重复代码,还从根源上避免了数据不一致的问题。
二、按矩形面积对栈进行排序
首先要明确:栈(LIFO)本身是一种无序结构,核心特性是后进先出,不支持直接排序。如果你需要对栈中的矩形按面积排序,可以通过以下步骤实现:
- 将栈中的所有元素转移到一个可排序的集合(比如
ArrayList)中; - 对集合按面积进行排序(升序或降序);
- 将排序后的集合重新放回栈中;
- 同步更新
DefaultListModel。
具体实现代码
比如添加一个“Sort by Area”按钮,点击后执行排序逻辑:
JButton btnSort = new JButton("Sort by Area"); btnSort.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (stack.isEmpty()) { JOptionPane.showMessageDialog(null, "Stack is empty, nothing to sort!"); return; } // 1. 将栈元素转移到ArrayList List<Rectangle> rectList = new ArrayList<>(stack); // 2. 按面积排序(这里是升序,要降序的话用Comparator.reverseOrder()) rectList.sort(Comparator.comparingInt(Rectangle::getArea)); // 3. 清空原栈,将排序后的元素重新压入栈 // 注意:栈是LIFO,若希望JList中展示最大面积在前,需反向遍历列表压入 stack.clear(); for (int i = rectList.size() - 1; i >= 0; i--) { stack.addFirst(rectList.get(i)); } // 若希望最小面积在前,直接正向遍历压入即可 // rectList.forEach(stack::addFirst); // 4. 同步更新ListModel dlm.clear(); stack.forEach(rect -> dlm.addElement(rect.toString())); } });
关键说明
- 排序后重新压入栈时,要注意栈的LIFO特性:如果希望
JList中展示的顺序是从面积最大到最小,需要把排序后的列表反向遍历,将最大的元素先压入栈(这样栈顶就是最大的,JList的第一个元素也是最大的);如果希望升序展示,直接正向遍历压入即可。 - 排序时使用
Comparator.comparingInt(Rectangle::getArea)非常简洁,你也可以自定义比较逻辑(比如面积相同时按宽度排序)。
内容的提问来源于stack exchange,提问作者Paleolog
相关产品推荐
相关产品推荐

