JLabel setText 不会更新但 getText returns 正确值

JLabel setText won't update but getText returns correct value

我有一个小程序,它从 JDateChooser 组件输入日期并计算从现在到输入日期的天数。它使用 MVC 模式,在 Netbeans IDE 中编码,并计算正确的天数但不在 JLabel "labelDays" 中显示。当我输入 labelDays.setText("29") 它起作用,当我得到 labelDays.getText() 的值时,它检索到未来的正确天数,并且 strDays 是正确的,但标签确实如此不显示更新值。这是示例代码:

    model:
    public class CountDownModel {

        public LocalDate getCurrentDate() {
        return LocalDate.now();
    }

    public long getDays(LocalDate futureDate) {
        long daysBetween = DAYS.between(LocalDate.now(), futureDate);
        if(daysBetween <= 0) {
            return 0;
        }
        return daysBetween;
    }

    view:     
    public class CountDownView extends javax.swing.JFrame {
    ...       
        private CountDownController controller = new CountDownController();

        public CountDownView() {
            initComponents();
            Date input = new Date();
            Instant instant = input.toInstant();
            Date output = Date.from(instant);
            future_date.setDate(output);
        }

        private void button_calculateMouseClicked(java.awt.event.MouseEvent evt) {                                              

            Date futureDate;
            futureDate = future_date.getDate();
            String strDate = DateFormat.getDateInstance().format(futureDate);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-MMM-yyyy");
            LocalDate localDate = LocalDate.parse(strDate, formatter);

            controller.setDays(localDate);
        }                                             
        ...
        public void setDays(long days) {
            String strDays = String.valueOf(days);

            System.out.print("strDays:");
            System.out.println(strDays);

            String oldValue = labelDays.getText();

            labelDays.setText(strDays);
            labelDays.paintImmediately(labelDays.getVisibleRect());
            String newValue = labelDays.getText();

            System.out.print("oldValue:");
            System.out.println(oldValue);
            System.out.print("newValue:");
            System.out.println(newValue); 
            System.out.println("================");
        }
    }

    controller:

    public class CountDownController {
        public void startApplication() {
            CountDownView view = new CountDownView();
            view.setDays(0);
            view.setVisible(true);
        }

        public void setDays(LocalDate futureDate) {
            CountDownModel model = new CountDownModel();
            CountDownView view   = new CountDownView();

            long longDays = model.getDays(futureDate);
            if(longDays <= 0) {
                longDays = 0;
            }

            view.setDays(longDays);        
        }
    }

    main:
    public class DateCountDown {
        public static void main(String[] args) {
            // TODO code application logic here
            CountDownController controller = new CountDownController();
            controller.startApplication();
        }   
    }

    Output:
    run:
    strDays:0
    oldValue:200
    newValue:0
    ================
    strDays:28
    oldValue:200
    newValue:28
    ================

谢谢。我需要做什么才能让它发挥作用? PS: 我想知道我的错误是否是由于我设置 MVC 的方式造成的。

菲利普

我觉得这里的MVC设置有点奇怪。

首先,我认为没有理由在每次执行 setDays 时都重新创建 CountDownView。这可能是标签不显示其新文本的原因 - CountDownView 的新实例可能根本不可见:CountDownView 的旧实例可见,而新实例则不可见。因此,这里控制器可以将 CountDownView 的实例作为对象级字段。我可以对 CountDownModel.

说同样的话

此外,视图创建自己的控制器,效率不高,因为会导致交叉链接和内存泄漏。我认为 CountDownView 的构造函数可以接受 CountDownController 的实例作为参数,并将其存储为对象级弱引用。

此外,通常的做法是在 Runnable 的新实例中启动所有 Swing 作业,例如:

java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
           CountDownController controller = new CountDownController();
           controller.startApplication();
      }
});

您可以通过以下方式修改您的代码(希望对您有所帮助):

model:
public class CountDownModel {

    public LocalDate getCurrentDate() {
        return LocalDate.now();
    }

    public long getDays(LocalDate futureDate) {
        long daysBetween = DAYS.between(LocalDate.now(), futureDate);
        if(daysBetween <= 0) {
            return 0;
        }
        return daysBetween;
    }
}

view:     
public class CountDownView extends javax.swing.JFrame {
...       
    private WeakReference<CountDownController> controller;

    public CountDownView(CountDownController controller) {
        this.controller = new WeakReference<>(controller);
        initComponents();
        Date input = new Date();
        Instant instant = input.toInstant();
        Date output = Date.from(instant);
        future_date.setDate(output);
    }

    private void button_calculateMouseClicked(java.awt.event.MouseEvent evt) {                                              

        Date futureDate;
        futureDate = future_date.getDate();
        String strDate = DateFormat.getDateInstance().format(futureDate);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-MMM-yyyy");
        LocalDate localDate = LocalDate.parse(strDate, formatter);

        controller.get().setDays(localDate);
    }                                             
    ...
    public void setDays(long days) {
        String strDays = String.valueOf(days);

        System.out.print("strDays:");
        System.out.println(strDays);

        String oldValue = labelDays.getText();

        labelDays.setText(strDays);
        labelDays.paintImmediately(labelDays.getVisibleRect());
        String newValue = labelDays.getText();

        System.out.print("oldValue:");
        System.out.println(oldValue);
        System.out.print("newValue:");
        System.out.println(newValue); 
        System.out.println("================");
    }
}

controller:

public class CountDownController {
    private CountDownView view;
    private CountDownModel model;         

    public void startApplication() {
        view = new CountDownView(this);
        model = new CountDownModel();
        view.setDays(0);
        view.setVisible(true);
    }

    public void setDays(LocalDate futureDate) {
        long longDays = model.getDays(futureDate);
        if(longDays <= 0) {
            longDays = 0;
        }

        view.setDays(longDays);        
    }
}

main:
public class DateCountDown {
    public static void main(String[] args) {
        // TODO code application logic here
        java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                CountDownController controller = new CountDownController();
                controller.startApplication();
             }
        });
    }   
}