0

我想创建一个具有三个页面的软件:“主页”(绘制在 JFrame“框架”上)、“第 2 页”和“第 3 页”。

第 2 页和第 3 页绘制在“框架”上。

一个使用位于页面左侧的导航窗格,主要内容位于右侧。

我目前只能导航到第二页。调用在 JFrame 上绘制第 2 页的类似乎不能调用第 3 页。

我的代码如下:

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

第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);
    }
}

第 3 页

// Page 3

package Try;

import javax.swing.JButton;

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

请帮我弄清楚如何让第二课(第 2 页)调用第三课(第 3 页)。谢谢大家。

4

1 回答 1

2

问题似乎是addAction您的Page2类中的方法从未被调用过。它似乎负责actionListenerCallAnotherPagebuttonNavigation JButton...注册。

现在,话虽如此……这似乎是很多努力工作却收效甚微。

与其尝试以这种方式硬链接导航,不如使用某种管理导航的模型。

基本上,您会依次将这个模型的引用传递给每个页面,并且每个页面在准备好时会要求模型移动到下一页。该模型将触发某种更改事件以向主视图指示当前页面已更改,并且视图将相应地更新自身。

您可以与 a 一起执行此操作CardLayout,这意味着您甚至不需要将组件的引用提供给模型,而是使用与关联的“页面名称” CardLayout,进一步解耦您的程序......

基于模型的方法

基本思想是将您的视图彼此分开,即使它们需要共享数据,我仍然会使用某种数据模型,但让我们专注于导航模型。

你需要什么...

  • 对所有可用视图及其显示顺序的一些想法
  • 当前的“活动”视图
  • 一些改变视图的方法,例如上一个/下一个......
  • 提供有关状态更改的通知的某种方式...
  • 您还希望将模型与实际组件分离。虽然“严格”地说这并没有错,但我只是不喜欢让我的组件开始传递到如果我能提供帮助的话,它们可能会在我不知情的情况下被修改的地方。更新视图也不是模型的责任,而是控制器的责任......这也意味着用于显示在屏幕上的实际组件与模型无关......

就像是...

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);

}

...例如

现在,我喜欢有一个抽象的实现来完成所有无聊、重复的工作......

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);
            }
        }
    }    
}

这使我可以设计不同的实现来满足我的需求......

例如,在这里,我提供了一个“线性”视图模型,该模型将一直移动到最后一个视图并停止,或者一直移动到第一个视图并停止。创建一个圆形视图模型并不需要太多,当它到达模式的任一端时,会翻转到另一端......

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

首先,您需要一些方法将视图名称映射到具有代表性的组件。您还需要一些方法来监视模型的更改...

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

}

现在,您可能想知道,我的视图如何移动到下一个/上一个视图...?

它没有。相反,我会创建一个导航栏,该导航栏将存在于主屏幕上,用于与模型本身进行交互......让每个页面/视图与整个过程分离......

于 2013-08-21T06:34:01.307 回答