I try to make java small project with intro and after full video or keypressed skip to menu. I made enums for state of "game". How i can switch JPanels and stop everything that old one is doing, because intro is also playing music in 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);
}
}
The first thing I would recommend is, making use of a CardLayout
- See How to use CardLayout for more details.
It will make switching between the views much simpler.
Next, I would recommend devising some kind of "navigation" system which is independent of the views themselves. The idea is, any one view really should know or care which view is next (or previous) and should only be making "simple" requests to the navigation system, like "show next view". It's up to the navigation system to decide exactly what that means (and how to drive it).
This allows you more control over defining and managing the overall navigation process.
I would then couple that with a optional "life cycle" concept, which would allow the navigation system to notify those implementations when the navigation state was changing.
"How" you actually do this, will depend on a lot on your overall design and intentions, but it might look something like...
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();
}
Default implementations...
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();
}
}
}
As you can see, I like working to interface
s, this hides the implementation details from other parts of the system and provides me with a better point of customisation. For example, components don't care "how" the NavigationController
is implemented, only that it follows a specific and definable work flow.
Okay, but how might this work? Let's start with a basic implementation of a component that support LifeCycle
, it might look something like...
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
}
}
And you might set it up using something like...
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());
"But wait" you say, "this is a linear navigation, I need something more dynamic!"
Far point. In that case I would create, yes, another interface
!! This would extend from the (linear) NavigationController
and provide a means to "show" arbitrary named views.
Why do it this way? Because not all the views need the power to decide which view should be shown, some just want to show the next (or previous) view, for example, MenuPane
might be the only view which actually needs a non-linear navigation controller, all the others just need to be able to move back or forward
But how do I stop a Thread
That's a complicated question, which isn't always easily answered. The "basic" answer is, you need to define a controlling mechanism which can work together with the "interruptable" support of the Thread
and exit the thread context.
Maybe How to Kill a Java Thread would be a starting point