2017-05-03 4 views
0

Ich habe ein kleines Programm, das ein Datum von einer JDateChooser-Komponente eingibt und die Anzahl der Tage von jetzt bis zum eingegebenen Datum berechnet. Es verwendet ein MVC-Muster, wurde in der Netbeans-IDE codiert und berechnet die korrekte Anzahl von Tagen, zeigt es aber nicht in "labelDays" an, was ein JLabel ist. Wenn ich labelDays.setText ("29") eintippe, funktioniert es und wenn ich den Wert von labelDays.getText() bekomme, wird die richtige Anzahl von Tagen in die Zukunft abgerufen, und strDays ist korrekt, aber das Etikett zeigt das aktualisierte nicht an Wert. Hier ist der Beispielcode:JLabel setText wird nicht aktualisiert, aber getText gibt den korrekten Wert zurück

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 
    ================ 

Danke. Was muss ich tun, damit es funktioniert? PS: Ich frage mich, ob mein Fehler aufgrund der Art, wie ich meine MVC eingerichtet habe.

Philip

Antwort

0

Ich finde es ein bisschen seltsam, wie MVC hier eingerichtet ist.

Zunächst einmal denke ich, es gibt keinen Grund, CountDownView jedes Mal neu zu erstellen, wenn Sie setDays tun. Das kann der Grund sein, warum ein Etikett seinen neuen Text nicht anzeigt - eine neue Instanz von CountDownView kann einfach unsichtbar sein: eine alte Instanz von CountDownView ist sichtbar, während eine neue nicht ist. Daher kann der Controller hier eine Instanz von CountDownView als Objekt-Level-Feld haben. Ich kann dasselbe über CountDownModel sagen.

Darüber hinaus erstellt eine Ansicht einen eigenen Controller, der nicht effizient ist, da es zu Querverbindungen und Speicherlecks führt. Ich denke, ein Konstruktor von CountDownView kann eine Instanz von CountDownController als eine Anweisung akzeptieren und sie als schwache Referenz auf Objektebene speichern.

Darüber hinaus ist es eine übliche Praxis, alle Swing-Arbeitsplätze in einer neuen Instanz von Runnable, zum Beispiel zu starten:

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

Sie können den Code auf folgende Weise ändern (hoffen, es hilft):

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(); 
      } 
     }); 
    } 
} 
+0

Variable paintImmediately und oldValue hinzugefügt. Etikett wird immer noch nicht aktualisiert. –

+0

@ philip-stephens, aktualisiert dieses Label seinen Text zu einem späteren Zeitpunkt - oder bleibt es immer mit dem gleichen Wert? – arcquim

+0

Es wird immer 0 angezeigt, es sei denn, ich habe es explizit in der Funktion festgelegt. –

Verwandte Themen