Can't call a the third page via the 2nd Page

前端 未结 1 1627
刺人心
刺人心 2020-12-22 07:13

I\'d like to create a software that has three pages: The \"Home Page\" (That\'s drawn on a JFrame \"frame\"), \"Page 2\" and \"Page 3\".

Pages 2 and 3 are drawn on \

相关标签:
1条回答
  • 2020-12-22 08:05

    The problem seems to be the fact that the method addAction in your Page2 class is never called. It seems responsible for registering the actionListenerCallAnotherPage to the buttonNavigation JButton....

    Now, having said that...this seems like a lot of hard work for little gain.

    Instead of trying to hard chain the navigation in this manner, you should use some kind of model that manages the navigation.

    Basically, you would pass a reference of this model to each page in turn and each page would, when it's ready, ask the model to move to the next page. The model would fire some kind of change event to indicate to the main view that the current page has changed and the view would update itself accordingly.

    You could do this in conjuntion with a CardLayout, meaning that you wouldn't even need to give a reference of the component to the model, but instead use the "page name" which is associated with the CardLayout, further decoupling your program...

    A model based approach

    The basic idea is to separate your views from each other, even if they need to share data, I'd still use some kind of data model, but lets stay focused on the navigation model.

    What you need...

    • Some idea of all the available views and the order they should be displayed in
    • The current "active" view
    • Some way to change the views, previous/next for example...
    • Some way to provide notifications about the change in state...
    • You also want to decouple the model from the actual components. While "strictly" speaking it's not wrong, I just don't like having my components begin passed around to places that they might get modified without my knowledge if I can help it. It's also not the responsibility of the model to update the views, that's the controllers responsibility...This also means that the actual component used to be displayed on the screen is irrelevant to the model...

    Something like...

    public interface ViewModel {
    
        /**
         * Returns the name of the current "active" view name
         * @return
         */
        public String getCurrentView();
    
        /**
         * Instructs the model to move to the next view if one is
         * available...
         */
        public void nextView();
    
        /**
         * Instructs the model to move to the previous view if one is
         * available...
         */
        public void previousView();
    
        /**
         * Returns the number of views in this model
         */
        public int size();
    
        /**
         * Returns the name of the view at the specified index...
         * @param index
         * @return 
         */
        public String getViewAt(int index);
    
        /**
         * Adds a ChangeListeners to the model, which will be notified when
         * the current view changes
         */
        public void addChangeListener(ChangeListener listener);
    
        /**
         * Remove a ChangeListeners from the model
         */
        public void removeChangeListener(ChangeListener listener);
    
    }
    

    ...For example

    Now, I like to have an abstract implementation which does all the boring, repetitive work...

    public abstract class AbstractViewModel implements ViewModel {
    
        private EventListenerList listenerList;
        private List<String> views;
    
        public void addView(String name) {
            getViews().add(name);
        }
    
        public void removeView(String name) {
            getViews().remove(name);
        }
    
        @Override
        public int size() {
            return views.size();
        }
    
        @Override
        public String getCurrentView() {
            return getViewAt(getCurrentViewIndex());
        }
    
        protected abstract int getCurrentViewIndex();
    
        protected List<String> getViews() {
            if (views == null) {
                views = new ArrayList<>(25);
            }
            return views;
        }
    
        @Override
        public String getViewAt(int index) {
            return index >= 0 && index < size() ? getViews().get(index) : null;
        }
    
        @Override
        public void addChangeListener(ChangeListener listener) {
            getListenerList().add(ChangeListener.class, listener);
        }
    
        @Override
        public void removeChangeListener(ChangeListener listener) {
            getListenerList().remove(ChangeListener.class, listener);
        }
    
        protected EventListenerList getListenerList() {
            if (listenerList == null) {
                listenerList = new EventListenerList();
            }
            return listenerList;
        }
    
        protected void fireStateChanged() {
            ChangeListener[] listeners = getListenerList().getListeners(ChangeListener.class);
            if (listeners.length > 0) {
                ChangeEvent evt = new ChangeEvent(this);
                for (ChangeListener listener : listeners) {
                    listener.stateChanged(evt);
                }
            }
        }    
    }
    

    This allows me to devise different implementations to meet my needs...

    For example, here, I've provided a "linear" view model, this model will move all the way to the last view and stop or all the way to first view and stop. It wouldn't take much to create a circular view model which when it reach either end of the mode, would flip around to the other end...

    public class LinearViewModel extends AbstractViewModel {
    
        private int currentIndex;
    
        @Override
        protected int getCurrentViewIndex() {
            return currentIndex;
        }
    
        @Override
        public void nextView() {
            if (currentIndex + 1 < size()) {
                currentIndex++;
                fireStateChanged();
            }
        }
    
        @Override
        public void previousView() {
            if (currentIndex - 1 >= 0) {
                currentIndex--;
                fireStateChanged();
            }
        }    
    }
    

    To get started, you would need some way to map the view names to there representative components. You would also need some way to monitor for changes to the model...

    private Map<String, Component> mapViews;
    private Component currentView;
    private LinearViewModel model;
    
    public ViewModelTest() {
    
        // Maps the view name to the component...
        mapViews = new HashMap<>(25);
        model = new LinearViewModel();
        mapViews.put("Page01", new Page01());
        mapViews.put("Page02", new Page02());
        mapViews.put("Page03", new Page03());
        mapViews.put("Page04", new Page04());
    
        // Add the view names to the model...
        model.addView("Page01");
        model.addView("Page02");
        model.addView("Page03");
        model.addView("Page04");
    
        // Initialise out view with the first page...
        currentView = mapViews.get("Page01");
        add(currentView);
    
        // Monitor for changes...
        model.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                remove(currentView);
                currentView = mapViews.get(model.getCurrentView());
                add(currentView);
                revalidate();
            }
        });
    
    }
    

    Now, you're probably wondering, how does my view move to the next/previous view...?

    It doesn't. Instead, I would create a navigation bar, which would exist on the main screen, which would be used to interact with the model itself...leaving each page/view decoupled from the whole process...

    0 讨论(0)
提交回复
热议问题