如何远程切换JPanel?

djm*_*gal 1 java swing jpanel jframe

我试图在我的程序中工作的概念基本上是:

-Main Window:一个包含程序主框架的主类,即:

public class MainWindow extends JFrame {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

public class SomePanel extends JPanel {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

public MainWindow() {
...
SomePanel sp = new SomePanel();
add(sp);
...
}
Run Code Online (Sandbox Code Playgroud)

当触发一些ActionEvent时,我可以说,在MainWindow类中:

// remove the current panel
getContentPane().remove(sp);
// insert the new panel
getContentPane().add(someOtherPanel);
validate();
repaint();
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

sni*_*10m 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();
    }
Run Code Online (Sandbox Code Playgroud)

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

另外,正如MadProgrammer在下面所述,您可能可以使用theWindow.revalidate()而不是repaint().


Mad*_*mer 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);
        }
      }
    }

  }

}
Run Code Online (Sandbox Code Playgroud)

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