如何远程切换JPanel?

时间:2013-08-06 05:20:03

标签: java swing jframe jpanel

我正在尝试使用我的程序的概念基本上是:

- 主窗口:包含程序主框架的主类,即:

public class MainWindow extends JFrame {
    ...
}

- 其他类:扩展JPanel的类,以便它们可以作为一个对象或实体轻松添加到MainWindow,即:

public class SomePanel extends JPanel {
    ...
}

这样,我可以说,对于主窗口:

public MainWindow() {
...
SomePanel sp = new SomePanel();
add(sp);
...
}

当触发某个ActionEvent时,我可以说,在MainWindow类中:

// remove the current panel
getContentPane().remove(sp);
// insert the new panel
getContentPane().add(someOtherPanel);
validate();
repaint();

我想,这个概念就像CardLayout一样,除了我还没有学习过CardLayout之外,我觉得我想尝试这个概念。我可能会在某些时候学习CardLayout,这取决于什么更容易。

但是我的主要问题是,如果所有内容都在不同的类中,我如何根据ActionEvent的触发器远程切换JPanels?我认为类之间必须有一些共享组件,但这似乎不起作用。我是在正确的轨道上吗?

我正在尝试删除()和add()的代码似乎没有工作,因为当我触发组件的ActionEvent(添加了侦听器和所有内容)时没有任何变化。我还包括validate()和repaint()但仍然没有任何反应。

我不再是初学者了,但也不是非常有经验的人,所以如果有一些明显我缺少的话,请耐心等待。谢谢你的帮助。

3 个答案:

答案 0 :(得分:7)

你肯定是在正确的轨道上,几乎拥有它。请注意您在构造函数中如何使用add(sp);,但在底部示例中使用getContentPane().remove(sp);getContentPane().add(someOtherPanel);remove(Component c)的方法绝对是JPanel方法,所以请使用它。

此外,如果您在一个位置操作组件,一切都会更容易。我喜欢在主要方法或主要类中做到这一点。例如:

public class Start implements ActionListener {
    Window theWindow = new Window();
    CustomPanel mainMenu = new CustomPanel();
    CustomPanel optionsMenu = new CustomPanel();
    Button myButton = new Button();
    public static void main(String[] args) {
        theWindow.add(mainMenu);
        mainMenu.add(myButton);
        myButton.addActionListener(this);

        theWindow.setVisible(true);
        theWindow.repaint();
    }

    public void actionPerformed(Event e) {
        theWindow.remove(mainMenu);
        theWindow.add(optionsMenu);
        theWindow.repaint();
    }

请注意,即使不必使用自定义类,也可以轻松完成所有这些操作。我建议构建你的程序,gui就像这样。

同样如下文MadProgrammer所述,您可以使用theWindow.revalidate()代替repaint()

答案 1 :(得分:5)

您可以设计一个模型来控制不同操作显示的内容。然后将共享此模型,以便底层操作可以访问它,并且不需要不必要地暴露组件。但这取决于你的要求......

所以,例如。您可以建立一个模型,允许您将组件与命名操作相关联(例如)。当您的应用程序中发生某些操作时,您会告诉模型setCurrentAction并将其传递给可用的操作名称。

你可以进一步使用像ChangeListener这样的东西来通知感兴趣的一方,当前的观点已经发生变化,并且应该相应地增加。

这样您可以将模型与UI分离

更新了示例

这是一个概念证明。重点是展示一种可以将模型与UI分离的方法,因此模型不关心谁控制输出,只关心它可以告诉某人......

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;

public class PageFlipper {

  public static void main(String[] args) {
    new PageFlipper();
  }

  public PageFlipper() {
    startUI();
  }

  public void startUI() {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
          ex.printStackTrace();
        }

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new MainView());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    });
  }

  public class MainView extends JPanel {

    private DefaultViewModel model;

    public MainView() {
      setLayout(new BorderLayout());
      model = new DefaultViewModel();
      model.addChangeListener(new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
          System.out.println("Current view = " + model.getCurrentViewName());
          removeAll();
          add(model.getCurrentView());
          revalidate();
          repaint();
        }
      });
      model.addView("Menu", new ActionPane("Menu", "Settings", model));
      model.addView("Settings", new ActionPane("Settings", "Menu", model));
      model.setCurrentView("Menu");
    }

  }

  public class ActionPane extends JPanel {

    private final String nextView;
    private final ViewModel model;

    public ActionPane(String name, String nextView, ViewModel model) {
      this.nextView = nextView;
      this.model = model;
      setLayout(new BorderLayout());
      JLabel label = new JLabel(name);
      label.setHorizontalAlignment(JLabel.CENTER);
      label.setVerticalAlignment(JLabel.CENTER);
      add(label);

      JButton btn = new JButton("Next");
      btn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          ActionPane.this.model.setCurrentView(ActionPane.this.nextView);
        }
      });
      add(btn, BorderLayout.SOUTH);
    }

  }

  public interface ViewModel {

    public void setCurrentView(String name);
    public Component getCurrentView();
    public void addChangeListener(ChangeListener listener);
    public void removeChangeListener(ChangeListener listener);

  }

  public class DefaultViewModel implements ViewModel {

    private final Map<String, Component> views;
    private final EventListenerList listenerList;
    private String currentView;

    public DefaultViewModel() {
      views = new HashMap<>(25);
      listenerList = new EventListenerList();
    }

    public void addView(String name, Component comp) {
      views.put(name, comp);
    }

    public void removeView(String name) {
      views.remove(name);
    }

    @Override
    public void setCurrentView(String name) {
      if (currentView == null ? name != null : !currentView.equals(name)) {
        currentView = name;
        fireStateChanged();
      }
    }

    public String getCurrentViewName() {
      return currentView;
    }

    @Override
    public Component getCurrentView() {
      return currentView == null ? null : views.get(currentView);
    }

    @Override
    public void addChangeListener(ChangeListener listener) {
      listenerList.add(ChangeListener.class, listener);
    }

    @Override
    public void removeChangeListener(ChangeListener listener) {
      listenerList.remove(ChangeListener.class, listener);
    }

    protected void fireStateChanged() {
      ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);
      if (listeners.length > 0) {
        ChangeEvent evt = new ChangeEvent(this);
        for (ChangeListener listener : listeners) {
          listener.stateChanged(evt);
        }
      }
    }

  }

}

您可以轻松修改它以获得更有意义的视图/操作名称(即使用某种Object代替String)以及提供更高级的导航(例如next和例如previous

答案 2 :(得分:0)

你可以试试这个:

〜添加两个jpanels

〜每当有事件发生时,切换面板的可见性......

示例:

//global variables
int i = 0;
JPanel p2 = new JPanel();
JPanel p = new JPanel();

当有事件调用此方法时:switchPanels(),但您可以根据需要命名...:D

public void switchPanels() {
    i++;
    if(i % 2 == 0){
        p.setVisible(true);
        p2.setVisible(false);
    }else{
        p.setVisible(false);
        p2.setVisible(true);
    }

}