【问题标题】:Adding and removing checkboxes dynamically动态添加和删除复选框
【发布时间】:2018-06-16 18:30:10
【问题描述】:

我想制作 ToDoList 应用程序。成功添加任务后(其中包含复选框、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);
}

【问题讨论】:

    标签: java swing checkbox


    【解决方案1】:

    您永远不会从 taskBoxdoneCheck 数组中删除元素。

    现在,如果您将第一个条目标记为完成,则您的 ItemListener 在循环遍历 doneCheck 数组时将始终找到第一个条目。

    以相反的顺序将条目标记为已完成(始终是最后显示的条目)将依次删除一个条目。


    至于您的软件设计:在多个并行阵列中管理数据被认为是不好的做法。

    请考虑为管理单个待办事项的所有元素的待办事项创建一个自定义类。

    【讨论】:

      【解决方案2】:

      除非您在某处初始化 doneCheck 项目,否则:

      Checkbox[] doneCheck = new Checkbox[1000];
      

      还有这个:

      int k = 0;
      for (int j = 0; j < doneCheck.length; j++) {
          if (doneCheck[j].getState()) {
      --------^^^^^^^^^^^^
      

      可能是它失败的原因之一:您可能在某个地方得到了NullPointerException,例如:当j &gt; 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.
      

      【讨论】:

        【解决方案3】:

        我的猜测是你有 2 个变量 global int i = 0 和 local int k = 0 in here

                   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。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-25
          • 1970-01-01
          • 2018-10-30
          • 1970-01-01
          • 2011-06-27
          相关资源
          最近更新 更多