JLabel setText不会更新,但getText会返回正确的值

时间:2017-05-03 01:16:36

标签: model-view-controller netbeans jlabel jdatechooser

我有一个小程序,它从JDateChooser组件输入日期,并计算从现在到输入日期的天数。它使用MVC模式,在Netbeans IDE中编码,并计算正确的天数,但不会在“labelDays”(JLabel)中显示。当我输入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的方式。

菲利普

1 个答案:

答案 0 :(得分:0)

我发现在这里设置MVC有点奇怪。

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

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

此外,通常的做法是在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();
             }
        });
    }   
}