1

我试图在我的程序中使用的概念基本上是:

-Main Window:一个主类,保存着程序的主框架,即:

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 的触发器在 JPanel 之间进行远程切换?我认为类之间必须有一些共享组件,但这似乎不起作用。我在正确的轨道上吗?

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

我不再是初学者,但也没有令人难以置信的经验,所以如果有明显的我遗漏的东西,请耐心等待。谢谢你的帮助。

4

3 回答 3

7

你绝对是在正确的轨道上,并且几乎拥有它。请注意您add(sp);在构造函数中的使用方式,但在底部示例中使用getContentPane().remove(sp);and 。getContentPane().add(someOtherPanel);'s肯定有一种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().

于 2013-08-06T05:32:47.853 回答
5

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

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

此外,您可以使用类似 a 的东西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

于 2013-08-06T05:46:00.610 回答
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);
    }

}
于 2013-08-06T09:00:33.367 回答