如何按某个值对 Stack 进行排序并显示在 java 中的 DefaultListModel 中?

How to sort Stack by certain value and show it in DefaultListModel in java?

我有下一个任务: 实施 Java Swing 应用程序,它允许添加新的矩形(由 X、Y 坐标和 a 和 b 边描述)到堆栈。应用程序还应允许使用 LIFO 模型从堆栈中删除矩形。 所有矩形都应在 JList 中显示。像这样:

我是这样实现的:

public class Stack extends JFrame {

private JPanel contentPane;
private Deque<String> stack = new ArrayDeque<String>();
private DefaultListModel<String> dlm = new DefaultListModel<String>();



JList lstRectangle = new JList();
lstRectangle.setModel(dlm);     
scrollPane.setViewportView(lstRectangle);


JButton btnAdd = new JButton("Add rectangle");
        btnAdd.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                DlgRectangle dlgRectangle = new DlgRectangle();
                dlgRectangle.setVisible(true);
                if(dlgRectangle.isOk) {
                    dlm.add(0, "Upper left point: (" + dlgRectangle.txtX.getText() + "," + dlgRectangle.txtY.getText() + ") " + "width: " + dlgRectangle.txtWidth.getText() + " " + "height: " + dlgRectangle.txtHeight.getText());
                
                String rectangle = new String();
                rectangle = "Upper left point: (" + dlgRectangle.txtX.getText() + "," + dlgRectangle.txtY.getText() + ") " + "width: " + dlgRectangle.txtWidth.getText() + " " + "height: " + dlgRectangle.txtHeight.getText();
                stack.addFirst(rectangle);
                System.out.println(stack);
            }           
        }
    });


JButton btnDelete = new JButton("Delete rectangle");
        btnDelete.addActionListener(new ActionListener() {          
            @Override
            public void actionPerformed(ActionEvent e) {
                if(dlm != null && !dlm.isEmpty()) {
                    dlm.remove(0);
                    stack.pop();
                    System.out.println(stack);
                } else {
                    System.out.println("Stack is empty");
                }
            }
        });

首先我想问一下这是解决这个任务的好做法和好方法。 它正在工作,但我认为它可以做得更好,然后将对象推送到堆栈和 DefaultListModel。一些如何同时进行并直​​接在 DLM 中显示堆栈对象的方法。

下一个也是主要的问题(对于类似的任务)是如何根据矩形的面积对堆栈进行排序?

我尝试改进上面的代码,但我只是计算了面积,然后卡住了...

int sideA = Integer.parseInt(dlgRectangle.txtWidth.getText());
                    int sideB = Integer.parseInt(dlgRectangle.txtHeight.getText());
                    int surfaceArea = sideA*sideB;
                    
                    System.out.println(surfaceArea);
                    
                    dlm.add(0, "Upper left point: (" + dlgRectangle.txtX.getText() + "," + dlgRectangle.txtY.getText() + ") " + "width: " + dlgRectangle.txtWidth.getText() + " " + "height: " + dlgRectangle.txtHeight.getText() + " " + "Surface area: " + String.valueOf(surfaceArea));                  
                    
                    String rectangle = new String();
                    rectangle = "Upper left point: (" + dlgRectangle.txtX.getText() + "," + dlgRectangle.txtY.getText() + ") " + "width: " + dlgRectangle.txtWidth.getText() + " " + "height: " + dlgRectangle.txtHeight.getText()+ " " + "Surface area: " + String.valueOf(surfaceArea);
                    stack.addFirst(rectangle);
                    stack.toArray();
                    
                    System.out.println(stack);

At first I would like to ask is this good practice and good approach of solving this task

一般不会。您是 运行 支持 Model/View/Controller 概念的 API。

模型的重点是对数据建模。观点是以某种有意义的方式向用户呈现数据。

对模型应用 String 没有任何意义。相反,您应该管理模型中“矩形”的表示,并配置 JList 以某种有意义的方式呈现此值。

How to Use Lists and Writing a Custom Cell Renderer

例如

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Rectangle;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Stack {

    public static void main(String[] args) {
        new Stack();
    }

    public Stack() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JList<Rectangle> list;
        private DefaultListModel<Rectangle> model;

        public TestPane() {
            setLayout(new BorderLayout());
            list = new JList();
            model = new DefaultListModel<Rectangle>();

            list.setCellRenderer(new RectangeListCell());
            list.setModel(model);

            model.addElement(new Rectangle(100, 100, 10, 10));

            add(new JScrollPane(list));
        }

    }

    public class RectangeListCell extends DefaultListCellRenderer {

        @Override
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            if (value instanceof Rectangle) {
                Rectangle rect = (Rectangle) value;
                value = "Rectangle " + rect.x + "x" + rect.y + " by " + rect.width + "x" + rect.height;
            }
            return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        }

    }
}

Next and main question (for similar task) is how to sort stack according to the area of ​​the rectangle?

这是一个更难的问题。我建议从创建您自己的 POJO 表示开始,它可以存储矩形的属性并计算它自己的面积。

下一个问题归结为欲望。

您可以计算新元素的位置并手动插入到模型中。这有点笨拙。

您可以创建一个“排序列表模型”。这提出了将数据实际排序到模型上的要求,例如...

public class SortedListModel<T> extends AbstractListModel<T> {

    private SortedSet<T> model;

    public SortedListModel(Comparator<T> comparator) {
        model = new TreeSet<>(comparator);
    }

    public void add(T value) {
        if (!model.contains(value)) {
            model.add(value);
            int insertIndex = model.headSet(value).size();

            fireIntervalAdded(value, insertIndex, insertIndex);
        }
    }

    @Override
    public int getSize() {
        return model.size();
    }

    @Override
    public T getElementAt(int index) {
        Object value = model.toArray()[index];
        return (T)value;
    }
}

这有点受限,因为它依赖于 Set(我还没有实现删除,但这并不难)

另一种选择可能是在 JTable 可排序之前,实用程序使用我们使用的“更古老”的概念,制作一个“包装器”模型,该模型将维护映射到的索引列表使数据显示排序,.

当然,这可能暗示只使用一个列 JTable

最后,您可以维护一个 List 数据,并在每次添加新对象时手动对其进行排序,然后将其应用到模型中。不过,这有些沉重。

澄清

This is some what heavy handed though

这指的是每次您想要实施该解决方案时需要“重新发明”的工作量。

一个简单的解决方案可能使用数据的单独“源模型”,当添加新数据时,需要对其进行排序,然后需要将“源模型”应用于 ListModel,这会增加另一个开销,因为 JList 将重新验证并重新绘制自身。

“更好”的解决方案是:

  1. 易于重复使用
  2. 自给自足

最初的解决方案是基于一段非常古老的代码,它既不优雅也不高效。

稍加搜索和研究,我们可以使用 Collections API 来计算插入点,这使我们可以使用简单的 ArrayList 来代替,例如:

public class SortedListModel<T> extends AbstractListModel<T> {

    private List<T> model;
    private Comparator<T> comparator;

    public SortedListModel(Comparator<T> comparator) {
        model = new ArrayList<>(32);
        this.comparator = comparator;
    }

    public Comparator<T> getComparator() {
        return comparator;
    }

    public void add(T value) {
        int index = Collections.binarySearch(model, value, getComparator());
        if (index < 0) {
            index = -index - 1;
        }
        model.add(index, value);
        fireIntervalAdded(value, index, index);
    }

    @Override
    public int getSize() {
        return model.size();
    }

    @Override
    public T getElementAt(int index) {
        return model.get(index);
    }
}