实时切换内容窗格

时间:2018-08-01 20:15:59

标签: java multithreading swing jpanel

我尝试制作带有简介的Java小项目,并在播放完整视频或按键后跳到菜单。我为“游戏”状态做了枚举。我如何切换JPanels并停止旧版本正在做的所有事情,因为简介也在Thread中播放音乐。

contentPane.addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent e) {
                    System.out.println("Clicked");
                    State = GameState.MainMenu;
                }
            });
            if (State == GameState.Intro) {
                contentPane.removeAll();
                contentPane.add(intro);
                contentPane.revalidate();
                contentPane.repaint();
                intro.music.interrupt();
                System.out.println(State);
            } else if (State == GameState.MainMenu) {
                contentPane.removeAll();
                contentPane.add(menu);
                contentPane.revalidate();
                contentPane.repaint();
                System.out.println(State);
            }
        }

1 个答案:

答案 0 :(得分:1)

我建议的第一件事是利用CardLayout-有关更多详细信息,请参见How to use CardLayout

这将使视图之间的切换更加简单。

接下来,我建议您设计一种独立于视图本身的“导航”系统。这个想法是,任何一个视图实际上都应该知道或关心哪个视图是下一个(或上一个),并且应该仅向导航系统发出“简单”请求,例如“显示下一个视图”。由导航系统决定确切的含义(以及如何驱动)。

这使您可以更好地控制定义和管理整个导航过程。

然后,我将其与可选的“生命周期”概念相结合,这将使导航系统在导航状态发生变化时通知那些实现。

您实际上是如何做到的,将在很大程度上取决于您的总体设计和意图,但看起来可能类似于...

LifeCycle

public interface LifeCycle {
    public void willShow();
    public void didShow();
    public void willHide();
    public void didHide();
}

NavigationController

public interface NavigationController {
    public void next();
}

public interface View {
    public String getName();
    public JComponent getView();
}

默认实现...

public class DefaultView implements View {

    private String name;
    private JComponent view;

    public DefaultView(String name, JComponent view) {
        this.name = name;
        this.view = view;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public JComponent getView() {
        return view;
    }

}

public class DefaultNavigationController implements NavigationController {
    private List<View> views;
    private Container parent;
    private CardLayout layout;

    private View currentView;

    public DefaultNavigationController(Container parent, CardLayout layout) {
        this.parent = parent;
        this.layout = layout;
    }

    protected Container getParent() {
        return parent;
    }

    protected CardLayout getLayout() {
        return layout;
    }

    public void add(String name, JComponent comp) {
        getParent().add(comp, name);
        views.add(new DefaultView(name, comp));
    }

    protected List<View> getViews() {
        return views;
    }

    @Override
    public void next() {
        List<View> views = getViews();
        if (views.isEmpty()) {
            return;
        }
        int index = (currentView == null ? -1 : views.indexOf(currentView)) + 1;
        if (index >= views.size()) {
            // This is the last view
            return;
        }
        View previousView = currentView;
        View nextView = views.get(index);
        willHide(previousView);
        willShow(nextView);
        getLayout().show(getParent(), nextView.getName());
        didHide(previousView);
        didShow(nextView);

        currentView = nextView;
    }

    protected void willHide(View view) {
        if (view != null && view.getView() instanceof LifeCycle) {
            LifeCycle cycle = (LifeCycle)view.getView();
            cycle.willHide();
        }
    }

    protected void willShow(View view) {
        if (view != null && view.getView() instanceof LifeCycle) {
            LifeCycle cycle = (LifeCycle)view.getView();
            cycle.willShow();
        }
    }

    protected void didHide(View view) {
        if (view != null && view.getView() instanceof LifeCycle) {
            LifeCycle cycle = (LifeCycle)view.getView();
            cycle.didHide();
        }
    }

    protected void didShow(View view) {
        if (view != null && view.getView() instanceof LifeCycle) {
            LifeCycle cycle = (LifeCycle)view.getView();
            cycle.didShow();
        }
    }
}

如您所见,我喜欢工作interface,这将实现细节从系统的其他部分隐藏起来,并为我提供了更好的定制点。例如,组件并不关心NavigationController的“实现方式”,仅关注它遵循特定且可定义的工作流程。

好的,但是这怎么工作?让我们从支持LifeCycle的组件的基本实现开始,它看起来可能类似于...

public class IntroPane extends JPanel implements LifeCycle {
    private NavigationController navigationController;

    protected NavigationController getNavigationController() {
        return navigationController;
    }

    protected void next() {
        getNavigationController().next();
    }

    @Override
    public void willShow() {
        // Prepare any resources
        // Lazy load resources
        // Do other preparation work which doesn't need to be done in the
        // constructor or which needs to be recreated because of actions
        // in will/didHide
    }

    @Override
    public void didShow() {
        // Start animation loops and other "UI" related stuff
    }

    @Override
    public void willHide() {
        // Pause the animation loop and other "UI" related stuff
    }

    @Override
    public void didHide() {
        // Dispose of system intensive resources which can be recreated
        // in willShow
    }
}

您可以使用...来设置它。

CardLayout cardLayout = new CardLayout();
JPanel contentPane = new JPanel(cardLayout);

DefaultNavigationController navigationController = new DefaultNavigationController(contentPane, cardLayout);
navigationController.add("intro", new IntroPane());
navigationController.add("menu", new MenuPane());
navigationController.add("game", new GamePane());

“等等,”您说,“这是线性导航,我需要更动态的东西!”

重点。在那种情况下,我会创建另一个interface!这将从({线性)NavigationController开始,并提供一种“显示”任意命名视图的方法。

为什么要这样?由于并非所有视图都有权决定应显示哪个视图,因此有些视图只想显示下一个(或上一个)视图,例如,MenuPane可能是唯一实际需要非线性导航的视图控制器,所有其他控制器只需要能够向前或向后移动

  

但是如何停止Thread

这是一个复杂的问题,并不总是容易回答。 “基本”的答案是,您需要定义一种控制机制,该机制可以与Thread的“可中断”支持一起工作并退出线程上下文。

也许How to Kill a Java Thread将是一个起点