【问题标题】:JLabel setText won't update but getText returns correct valueJLabel setText 不会更新,但 getText 返回正确的值
【发布时间】:2017-05-03 01:16:36
【问题描述】:

我有一个小程序,它从 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 的方式造成的。

菲利普

【问题讨论】:

    标签: model-view-controller netbeans jlabel jdatechooser


    【解决方案1】:

    我觉得这里是如何设置 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();
                 }
            });
        }   
    }
    

    【讨论】:

    • 添加了 paintImmediately 和 oldValue 变量。仍然没有更新标签。
    • @philip-stephens,此标签是否会在以后随时更新其文本 - 还是始终保持相同的值?
    • 除非我在函数中明确设置,否则它总是显示 0。
    • 在标签上执行setText 后,标签显示新值需要多长时间?
    • 感谢您的建议和摆弄了一下,我得到了它的工作。我将在 10 月 20 日放假,所以我想编写一个程序来计算还剩多少天。今天的答案是还剩 167 天。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多