我想制作ToDoList App。成功添加要执行的任务(其中包含复选框,JLabel和日期,所有都放在一个框中)后我想动态删除它们。添加它不是问题,但当我尝试删除(在复选框中单击已选中)时,它只能运行一次。然后它要么不删除一次,要么根本不删除它们。我不确定为什么它不起作用所以我粘贴下面的所有代码。
JSpinner dateSpin;
Box eventBox, boxBox;
Box[] taskBox = new Box[1000];
JTextField eventName;
Date date;
Checkbox[] doneCheck = new Checkbox[1000];
JLabel taskLabel;
JPanel panel;
JScrollPane scrollPane;
SimpleDateFormat simpleDate;
int i = 0;
public static void main(String[] args) {
new Main();
}
private Main(){
this.setSize(400, 600);
this.setTitle("To-Do List");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
boxBox = Box.createVerticalBox();
scrollPane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
eventBox = Box.createHorizontalBox();
eventBox.setBorder(BorderFactory.createEtchedBorder());
JLabel plusSign = new JLabel("+");
plusSign.setFont(new Font("Serafi", PLAIN, 20));
plusSign.setMaximumSize(new Dimension(Integer.MAX_VALUE, plusSign.getMinimumSize().height));
eventBox.add(plusSign);
eventName = new JTextField(20);
eventName.setFont(new Font("Times", Font.ITALIC, 15));
eventName.setMaximumSize(new Dimension(Integer.MAX_VALUE, eventName.getMinimumSize().height));
eventName.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == eventName){
/* to do: saving every task in some file, figure out how to remove
those tasks (checkbox + jlabel) -> whole box from screen or how to send them to "done"
also "done" to do*/
simpleDate = new SimpleDateFormat("E-dd-MM-yyyy");
taskBox[i] = Box.createHorizontalBox();
taskBox[i].setBorder(BorderFactory.createTitledBorder(simpleDate.format(date)));
doneCheck[i] = new Checkbox();
doneCheck[i].addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
int k = 0;
for (int j = 0; j < doneCheck.length; j++) {
if(doneCheck[j].getState()){
//remove(doneCheck[k]);
//System.out.println("?" + i + "?" + k + " " + e.getSource().toString());
System.out.println("xxxxx" + doneCheck[j].getState());
break;
}
System.out.println("oooooo");
k++;
}
System.out.println(doneCheck.length + taskBox[k].toString());
//System.out.println("! " + k + " " + e.getSource().toString());
boxBox.remove(taskBox[k]);
//boxBox.removeAll();
boxBox.revalidate();
boxBox.repaint();
}
});
taskBox[i].add(doneCheck[i]);
String taskName = eventName.getText();
taskLabel = new JLabel(taskName);
taskLabel.setMinimumSize(new Dimension(500,10));
taskLabel.setPreferredSize(new Dimension(300, 10));
taskBox[i].add(taskLabel);
boxBox.add(taskBox[i]);
boxBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, boxBox.getMinimumSize().height + 11));
panel.add(boxBox);
panel.revalidate();
panel.repaint();
i++;
}
}
});
eventBox.add(eventName);
date = new Date();
dateSpin = new JSpinner(new SpinnerDateModel(date, null, null, Calendar.DAY_OF_MONTH));
JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(dateSpin, "dd/MM/yy");
dateSpin.setEditor(dateEditor);
dateSpin.setMaximumSize(new Dimension(Integer.MAX_VALUE, dateSpin.getMinimumSize().height));
dateSpin.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if(e.getSource() == dateSpin){
date = (Date) dateSpin.getValue();
}
}
});
eventBox.add(dateSpin);
panel.add(eventBox, new FlowLayout());
this.add(scrollPane);
this.setVisible(true);
}
答案 0 :(得分:0)
除非您在某处初始化doneCheck
项目,否则:
Checkbox[] doneCheck = new Checkbox[1000];
而且:
int k = 0;
for (int j = 0; j < doneCheck.length; j++) {
if (doneCheck[j].getState()) {
--------^^^^^^^^^^^^
可能是失败的原因之一:你可能在某处有一个NullPointerException
,例如:j > 0
的值。 NPE可能会被EventDispatchThread捕获,它可能或者可能不足以在stderr上显示它......
我不明白你为什么要使用这个数组,你可以缩短代码并避免像这样的NPE:
Checkbox cb = new Checkbox();
cb.addItemListener(event -> {
if (cb.getState()) { // not null!
boxBox.remove(cb);
boxBox.revalidate();
boxBox.repaint();
}
});
doneCheck[i] = cb; // I still don't know why you need that.
答案 1 :(得分:0)
您永远不会从taskBox
和doneCheck
数组中删除元素。
现在,如果您将第一个条目标记为已完成,则ItemListener
将在循环遍历doneCheck
数组时始终找到第一个条目。
将条目标记为按相反顺序完成(始终是最后显示的条目)将删除一个条目后的另一个条目。
关于您的软件设计:在多个并行阵列中管理数据被认为是不好的做法。
请考虑为管理单个待办事项的所有元素的待办事项创建自定义类。
答案 2 :(得分:0)
我的猜测是,您在这里有2个变量全局int i = 0
和本地int k = 0
public void itemStateChanged(ItemEvent e) {
// int k = 0;//<-------- LOCAL
for (int j = 0; j < doneCheck.length; j++) {
if(doneCheck[j].getState()){
//Either k = j;
boxBox.remove(taskBox[j]);
//remove(doneCheck[k]);
//System.out.println("?" + i + "?" + k + " " + e.getSource().toString());
System.out.println("xxxxx" + doneCheck[j].getState());
break;
}
System.out.println("oooooo");
//k++;//<-- ALWAYS == last j value before the break;
}
System.out.println(doneCheck.length + taskBox[k].toString());
//System.out.println("! " + k + " " + e.getSource().toString());
//boxBox.remove(taskBox[k]);//
//boxBox.removeAll();
boxBox.revalidate();
boxBox.repaint();
}
每次调用itemStateChanged int k = 0;
时都会初始化为0,您将从taskBox数组中删除元素[j]。因为你的k ++语句将等于break之前的最后一个j值;因为它位于if(doneCheck[j].getState()){...
之后
尝试在for循环中移动boxBox.remove(taskBox[j]);
并使用j代替k。