java - java - 如何按某个值对堆栈进行排序并在java中的DefaultListModel中显示它?
问题描述
我有下一个任务:实现 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);
解决方案
首先我想问一下解决这个任务的好习惯和好方法
一般来说,没有。您正在运行一个支持模型/视图/控制器概念的 API。
模型的重点是对数据进行建模。观点是以某种有意义的方式向用户呈现数据。
将 a 应用于模型是没有意义String
的。相反,您应该在模型中管理“矩形”的表示并配置JList
以某种有意义的方式呈现此值。
例如
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);
}
}
}
下一个主要问题(对于类似任务)是如何根据矩形的面积对堆栈进行排序?
这是一个更难的问题。我建议从创建自己的 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
是可排序的,制作一个“包装器”模型,该模型将维护一个映射的索引列表,以便使数据看起来是排序的,例如。
当然,这可能暗示只使用一个 column JTable
。
最后,您可以维护List
数据并在每次添加新对象时手动对其进行排序,然后将其应用于模型。这是一些沉重的东西。
澄清
这是一些沉重的东西
这是指每次您想要实施解决方案时需要“重新发明”的工作量。
一个简单的解决方案可能会使用数据的单独“源模型”,当添加新数据时,需要对其进行排序,然后需要将“源模型”应用于ListModel
,这会增加另一个开销,因为JList
它将重新验证并重新粉刷自己。
“更好”的解决方案是:
- 易于重复使用
- 自给自足
最初的解决方案是基于一段非常古老的代码,它并不完全优雅或高性能。
稍微搜索研究一下,我们可以使用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);
}
}
推荐阅读
- javascript - 在 dc.js 中填充行上方的区域
- android - 在包含字符串名称和字符串子文本的 RecyclerView 中搜索字符串名称时出现问题
- c++ - 为什么以下循环运行无限次
- java - 在另一个字符串中找到字符串的字符多少次
- python - pandas groupby 返回额外的索引
- azure-logic-apps - Azure 逻辑应用 - 重新托管查看器
- r - 有没有办法使用 shinyWidgets 包中的 pickerInput 函数对变量进行分组?
- android - google-maps 如何验证 REST api 调用?
- python - 我的问题是否适合凸优化,如果适合,如何用 cvxpy 表达?
- python - 未绑定方法的第一个参数必须具有类型“QWidget”