简体   繁体   English

触发Java GUI更新

[英]Triggering Java GUI to update

There's probably a better question/answer for this but what I've been finding hasn't worked out and I have had trouble phrasing the question for google query. 对此可能有一个更好的问题/答案,但是我一直发现的问题尚未解决,我很难将问题表达为Google查询。 Basically I have a JFrame with several panels and components that pull their data from xml files. 基本上,我有一个带有几个面板和组件的JFrame,这些面板和组件从xml文件中提取其数据。 I use the JFrame's instance variable private Date focusDate = new Date(); 我使用JFrame的实例变量private Date focusDate = new Date(); to store which day's info I'd like each panel to display, so far so good. 到目前为止,我希望每个面板都能显示哪一天的信息。

My problem comes now that I'm trying to set the various actions of the navigation components to update after I change 'focusDate'. 现在我的问题来了,我试图设置导航组件的各种操作,以便在更改“ focusDate”后进行更新。 I have a toolbar in a JPanel NavButtons navPanel = new NavButtons(focusDate); 我在JPanel NavButtons navPanel = new NavButtons(focusDate);有一个工具栏NavButtons navPanel = new NavButtons(focusDate); which I setup as an Inner Class and the console reports focusDate being changed but I can't get the JFrame to validate(), repaint(), etc... when I call my setFocus(Date d) method. 我将其设置为内部类,并且控制台报告focusDate被更改,但是当我调用setFocus(Date d)方法时validate(), repaint(), etc...无法使JFrame进行validate(), repaint(), etc...

I can include more of my code if that would be helpful but here's the method in question: 如果有帮助,我可以包括更多代码,但这是有问题的方法:

public void setFocus(Date d) throws IOException {
    focusDate = d;

    dispose();
//  validate();  //Tried revalidate too, but DisplayView extends JFrame
//  repaint(); 
//  revalidate();
//  pack();
//  DisplayView view = new DisplayView(focusDate);
    setVisible(true); }

and here's how I'm setting the ActionListener in the constructor: 这是我在构造函数中设置ActionListener的方法:

public NavButtons(Date d) {
    newDate = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(d));

        weekBack.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) { 
                newDate = newDate.plusDays(-7); 
                try { setFocus(Date.from(newDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                } catch (IOException e) {
                    e.printStackTrace(); } 
                //validate();
                //repaint(); 
                }
        });

I'm not very familiar with swing, so I'm sure this is some minor detail I'm just not getting but if someone can explain how to re-trigger the argument passing and update the child components of the frame to an amateur that would be most appreciated. 我对挥杆不是很熟悉,所以我确定这只是我没有得到的一些小细节,但是如果有人可以解释如何重新触发传递的参数并将框架的子组件更新为业余爱好者,将不胜感激。

Update Here's the entire JFrame 更新这里是整个JFrame

package interfaceComponents;

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import java.io.IOException;
import java.text.*;
import java.util.*;
import java.time.*;

public class DisplayView extends JFrame {
    //instance variables
    private Date focusDate = new Date();

    //constructor
    public DisplayView(Date d) throws IOException {
        DisplayMenus menus = new DisplayMenus();
        setJMenuBar(menus);

        JPanel body = new JPanel();
        body.setLayout(new BoxLayout(body, BoxLayout.Y_AXIS));
        body.add(new DayView(focusDate));
        LocalDate focusNextDay = LocalDate.now();
        body.add(new DayView(Date.from(focusNextDay.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()))); 
        add(new JScrollPane(body), BorderLayout.CENTER);

        JPanel footer = new JPanel();
        NavButtons navPanel = new NavButtons(focusDate);
        JLabel focusPoint = new JLabel(new SimpleDateFormat("E, dd MMM yyyy").format(focusDate).toString());
        focusPoint.setForeground(Color.RED);
        footer.setLayout(new BorderLayout());
        footer.add(focusPoint, BorderLayout.CENTER);
        footer.add(navPanel, BorderLayout.EAST);
        footer.setBackground(Color.BLACK);
        add(footer, BorderLayout.SOUTH);

        pack(); }

    public DisplayView() throws IOException { this(new Date()); }

    public void setFocus(Date d) throws IOException { 
        focusDate = d;

        SwingUtilities.updateComponentTreeUI(this);
//      dispose();
//      invalidate();
//      validate();                                     //Tried revalidate too, but DisplayView extends JFrame
        repaint(); 
//      revalidate();
//      pack();
//      DisplayView view = new DisplayView(focusDate);
//      setVisible(true);
        }
    public Date getFocus() { return focusDate; }    

    class NavButtons extends JPanel {
        private JToolBar toolBar = new JToolBar("Navigation");
        private JButton weekBack = new JButton("<<");
        private JButton dayBack = new JButton("<");
        private JButton returnToday = new JButton("Today");
        private JButton nextDay = new JButton(">");
        private JButton nextWeek = new JButton(">>");
        private JButton calendar = new JButton("L");
        private LocalDate newDate = LocalDate.now();

        public NavButtons(Date d) {
            newDate = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(d));

            weekBack.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) { 
                    newDate = newDate.plusDays(-7); 
                    try { setFocus(Date.from(newDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                    } catch (IOException e) {
                        e.printStackTrace(); } 
//                  invalidate();
//                  validate();
//                  repaint(); 
                    }
            });
            dayBack.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) { newDate = newDate.plusDays(-1); }
            });
            returnToday.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) { newDate = LocalDate.now(); }
            });
            nextDay.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) { newDate = newDate.plusDays(1); }
            });
            nextWeek.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) { newDate = newDate.plusDays(7); }
            });

            toolBar.add(weekBack);
            toolBar.add(dayBack);
            toolBar.add(returnToday);
            toolBar.add(nextDay);
            toolBar.add(nextWeek);
            toolBar.add(new GalileoMode());
            toolBar.add(calendar);
            add(toolBar); }         
    }
}

As @MadProgrammer pointed out, I should have the date stored in a separate object (shown here): 正如@MadProgrammer指出的那样,我应该将日期存储在一个单独的对象中(如下所示):

package interfaceComponents;

import java.util.*;

public class FocusDate {
    //instance variables
    Date focus = new Date();

    //constructors
    //intentionally blank: public FocusDate() {}

    //methods:
    public void setFocus(Date d) {
        focus = d; }
    public Date getFocus() {
        return focus; }
}

and I edited the Frame as such: 我这样编辑框架:

public class DisplayView extends JFrame {
    //instance variables
    FocusDate focus = new FocusDate();
//  private Date focusDate = new Date();

    //constructor
    public DisplayView(Date d) throws IOException {
//      focusDate = d;
        Date focusDate = focus.getFocus();

...

    public void setFocus(Date d) throws IOException { 
//      focusDate = d;
        focus.setFocus(d);

Still not doing something right though... 仍然没有做正确的事...

So, the basic idea is to wrap the "current" date value in an observable pattern and pass this to each interested party. 因此,基本思想是将“当前”日期值包装成可观察的模式,并将其传递给每个感兴趣的方。 This allows the navigation to make changes to the date value, but not need to know about any other part of the program, decoupling it and allow for a more flexible outcome. 这使导航可以更改日期值,而无需了解程序的任何其他部分,将其去耦并获得更灵活的结果。

So, I started with two basic contracts... 所以,我从两个基本合同开始...

public interface DateModel {

    public LocalDate getDate();

    public void addObserver(Observer o);

    public void removeObserver(Observer o);
}

public interface MutableDateModel extends DateModel {

    public void setDate(LocalDate date);

}

One is non-mutable (for those parts of the programs that don't need to be able to change the date) and one is mutable, for those parts of the program that do (like the navigation) 一个是不可更改的(对于程序中不需要更改日期的那些部分),而另一个是可变的,对于程序中那些可以更改日期的部分(例如导航)

Then I created a "default" implementation of the model... 然后,我创建了该模型的“默认”实现...

public class DefaultDateModel extends Observable implements MutableDateModel {

    private LocalDate date;

    public DefaultDateModel(LocalDate date) {
        this.date = date;
    }

    @Override
    public void setDate(LocalDate date) {
        this.date = date;
        setChanged();
        notifyObservers();
    }

    @Override
    public LocalDate getDate() {
        return date;
    }

    @Override
    public void removeObserver(Observer o) {
        // I like the "remove" ;)
        deleteObserver(o);
    }

}

I'm been lazy and using the Observer and Observable API from java.util , you can create your own based on your needs, but this just suits the example. 我很懒,使用java.utilObserverObservable API时,您可以根据需要创建自己的API,但这仅适合示例。

What this means is, I can create an instance of DefaultDateModel and pass it to those parts of the program that want a DateModel and those that want a MutableDateModel without needing to create separate instances, neat. 这意味着,我可以创造的一个实例DefaultDateModel并把它传递给那些需要一个程序的那些部分DateModel和那些想MutableDateModel ,而不需要创建单独的实例,整齐。

Because we're working to interface contract, those parts of the program that only want a DateModel will only ever be able to access the methods defined within the interface (and if the cast it, then they are doing the wrong thing)... 因为我们正在努力进行合同约定,所以程序中仅需要DateModel那些部分将只能访问接口内定义的方法(如果进行了DateModel ,则它们做错了事)...

As an example... 举个例子...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DisplayView extends JFrame {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                DisplayView view = new DisplayView();
                view.setDefaultCloseOperation(EXIT_ON_CLOSE);
                view.pack();
                view.setLocationRelativeTo(null);
                view.setVisible(true);
            }
        });
    }

    //constructor
    public DisplayView(LocalDate d) {
//      DisplayMenus menus = new DisplayMenus();
//      setJMenuBar(menus);

        DefaultDateModel model = new DefaultDateModel(d);

        JPanel body = new JPanel();
        body.setLayout(new BoxLayout(body, BoxLayout.Y_AXIS));

        DayView nowView = new DayView();
        nowView.setModel(model);
        DayView nextView = new DayView(1);
        nextView.setModel(model);

        body.add(nowView);
        body.add(nextView);
        add(new JScrollPane(body), BorderLayout.CENTER);

        JPanel footer = new JPanel();
        NavButtons navPanel = new NavButtons(model);
        JLabel focusPoint = new JLabel(DateTimeFormatter.ISO_DATE.format(model.getDate()));
        focusPoint.setForeground(Color.RED);
        footer.setLayout(new BorderLayout());
        footer.add(focusPoint, BorderLayout.CENTER);
        footer.add(navPanel, BorderLayout.EAST);
        footer.setBackground(Color.BLACK);
        add(footer, BorderLayout.SOUTH);

        pack();
    }

    public DisplayView() {
        this(LocalDate.now());
    }

    public interface DateModel {

        public LocalDate getDate();

        public void addObserver(Observer o);

        public void removeObserver(Observer o);
    }

    public interface MutableDateModel extends DateModel {

        public void setDate(LocalDate date);

    }

    public class DefaultDateModel extends Observable implements MutableDateModel {

        private LocalDate date;

        public DefaultDateModel(LocalDate date) {
            this.date = date;
        }

        @Override
        public void setDate(LocalDate date) {
            this.date = date;
            setChanged();
            notifyObservers();
        }

        @Override
        public LocalDate getDate() {
            return date;
        }

        @Override
        public void removeObserver(Observer o) {
            // I like the "remove" ;)
            deleteObserver(o);
        }

    }

    public class DayView extends JPanel implements Observer {
        private JLabel dateLabel;
        private DateModel model;
        private int offset;

        public DayView(int offset) {
            this.offset = offset;
            dateLabel = new JLabel("...");
            setLayout(new GridBagLayout());
            add(dateLabel);
        }

        public DayView() {
            this(0);
        }

        public void setModel(DateModel value) {
            if (model != null) {
                model.removeObserver(this);
            }
            this.model = value;
            if (model != null) {
                model.addObserver(this);
            }
            updateLabel();
        }

        public DateModel getModel() {
            return model;
        }

        protected void updateLabel() {
            DateModel model = getModel();
            if (model != null) {
                LocalDate offsetDate = model.getDate().plusDays(offset);
                dateLabel.setText(DateTimeFormatter.ISO_DATE.format(offsetDate));
            } else {
                dateLabel.setText("...");
            }
        }

        @Override
        public void update(Observable o, Object arg) {
            updateLabel();
        }

    }

    class NavButtons extends JPanel implements Observer {

        private JToolBar toolBar = new JToolBar("Navigation");
        private JButton weekBack = new JButton("<<");
        private JButton dayBack = new JButton("<");
        private JButton returnToday = new JButton("Today");
        private JButton nextDay = new JButton(">");
        private JButton nextWeek = new JButton(">>");
        private JButton calendar = new JButton("L");

        private MutableDateModel model;

        public NavButtons(MutableDateModel model) {
            weekBack.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    MutableDateModel model = getModel();
                    if (model != null) {
                        LocalDate newDate = model.getDate().minusDays(7);
                        model.setDate(newDate);
                    }
                }
            });
            dayBack.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    MutableDateModel model = getModel();
                    if (model != null) {
                        LocalDate newDate = model.getDate().minusDays(1);
                        model.setDate(newDate);
                    }
                }
            });
            returnToday.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    MutableDateModel model = getModel();
                    if (model != null) {
                        LocalDate newDate = LocalDate.now();
                        model.setDate(newDate);
                    }
                }
            });
            nextDay.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    MutableDateModel model = getModel();
                    if (model != null) {
                        LocalDate newDate = model.getDate().plusDays(1);
                        model.setDate(newDate);
                    }
                }
            });
            nextWeek.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    MutableDateModel model = getModel();
                    if (model != null) {
                        LocalDate newDate = model.getDate().plusDays(7);
                        model.setDate(newDate);
                    }
                }
            });

            toolBar.add(weekBack);
            toolBar.add(dayBack);
            toolBar.add(returnToday);
            toolBar.add(nextDay);
            toolBar.add(nextWeek);
//          toolBar.add(new GalileoMode());
            toolBar.add(calendar);
            add(toolBar);
            setModel(model);
        }

        public void setModel(MutableDateModel value) {
            if (model != null) {
                model.removeObserver(this);
            }
            this.model = value;
            if (model != null) {
                model.addObserver(this);
            }
        }

        public MutableDateModel getModel() {
            return model;
        }

        @Override
        public void update(Observable o, Object arg) {
            // models data has change!!
        }

        protected void setFocus(LocalDate newDate) {
            // No idea what this is suppose to do...
        }

    }
}

Oh, I'd kind of avoid moving between java.util.Date and java.time.LocalDate if you can, for your purposes, I'd stick with LocalDate , but that's me ;) 哦,如果可以的话,我会避免在java.util.Datejava.time.LocalDate之间移动,我会坚持使用LocalDate ,但这就是我;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM