我尝试制作带有简介的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);
}
}
答案 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将是一个起点