Can't call third page through second page

I would like to create software that has three pages: "Home" (this is drawn in a JFrame), "Page 2" and "Page 3".

Pages 2 and 3 are drawn on the "frame".

One uses the navbar located on the left side of the page and the main content is held down to the right.

Currently I can only go to the second page. The class called to draw page 2 on a JFrame doesn't appear to be calling Page 3.

My code looks like this:

// The Home Page

package Try;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class HomePage {
    JPanel panelHomeWrapper = new JPanel();
    JPanel panelNavigation = new JPanel();
    JPanel panelDisplay = new JPanel();

    JButton buttonNavigation = new JButton("Button Home = Menu Items");
    JButton buttonBody = new JButton("Button body Page Home = Home body Items");

    public static void main (String[] args) {
        HomePage home = new HomePage();
        home.homePanel();
    }

    public void homePanel () {
        JFrame frame = new JFrame("Home");

        JButton button = new JButton("Button");

        ActionListener actionListener = new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                System.out.println("Panel 2 was called.");

                Page2 panel2 = new Page2();

                panelNavigation.remove(buttonNavigation);
                panelDisplay.remove(buttonBody);

                panelNavigation.add(panel2.buttonNavigation);
                panelDisplay.add(panel2.buttonBody);

                panelNavigation.validate();
                panelNavigation.repaint();

                panelDisplay.validate();
                panelDisplay.repaint();
            }
        };

        button.addActionListener(actionListener);


        buttonNavigation.addActionListener(actionListener);

        panelNavigation.add(buttonNavigation);
        panelDisplay.add(buttonBody);

        panelHomeWrapper.add(panelNavigation);
        panelHomeWrapper.add(panelDisplay);

        frame.add(panelHomeWrapper);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(455, 355);
        frame.setVisible(true);
    }
} // End of Home Page

      

Page 2

// Page 2

package Try;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Page2 {
    JButton buttonNavigation = new JButton("Button 2 = Menu Items");
    JButton buttonBody = new JButton("Button body Page 2 = Page 2 body Items");

    ActionListener actionListenerCallAnotherPage = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            System.out.println("Button Body 3 was called.");

            HomePage home = new HomePage();
            Page3 panel3 = new Page3();

            home.panelDisplay.remove(buttonBody);
            home.panelDisplay.add(panel3.buttonBody3);

            home.panelDisplay.validate();
            home.panelDisplay.repaint();

        }
    };

    public void addAction () {
        buttonNavigation.addActionListener(actionListenerCallAnotherPage);
    }
}

      

Page 3

// Page 3

package Try;

import javax.swing.JButton;

public class Page3 {
    JButton buttonBody3 = new JButton("Page 3");
} // End of Page 3

      

Please help me figure out how to make 2nd grade (page 2) call 3rd grade (page 3). Thanks everyone in advance.

0


source to share


1 answer


The problem is that the method addAction

in your class is Page2

never called. Seems responsible for registering actionListenerCallAnotherPage

before buttonNavigation

JButton

....

Now, having said that ... it seems like hard work for a small payoff.

Instead of trying to hard-code the navigation in this way, you should use some sort of model that drives the navigation.

Basically, you should pass this model's link to each page in turn, and each page, when ready, will ask the model to go to the next page. The model will fire some sort of change event to indicate to the main view that the current page has changed and the view will update accordingly.

You can do this in conjunction with CardLayout

, which means you don't even need to reference the model component, but instead use the "page name" that is associated with CardLayout

, further splitting your program ...

Model-driven approach

The basic idea is to separate your views from each other, even if they need to exchange data, I am still using some kind of data model, but let's focus on the navigation model.

What you need...

  • Some idea about all the available views and the order in which they are displayed in
  • The current "active" view
  • How to change the view, previous / next, for example ...
  • How State Change Notifications are Provided ...
  • You also want to separate the model from the real components. While this is not "strictly" speaking, I just don't like it when my components start being transferred to places that they can modify without my knowledge, if I can help. It is also not the responsibility of the model to update the views, which is the responsibility of the dispatchers ... This also means that the actual component used to display 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 that 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 design different implementations to suit my needs ...

For example, here I have presented a "linear" view model, this model will move completely to the last view and stop, or completely open and stop. It wouldn't be much to create a circular view model that, when it reaches either end of the mode, flips 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 need to map the names of the views to the representational components somehow. You will also need some way of monitoring changes in 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 my view goes to the next / previous view ...?

This is not true. Instead, I would create a navbar that will exist on the home screen that will be used to interact with the model itself ... leaving each page / view separate from the whole process ...

+2


source







All Articles