java - 实时切换内容窗格
问题描述
我尝试制作带有介绍的java小项目,并在完整的视频或按键后跳到菜单。我为“游戏”的状态做了枚举。我如何切换 JPanel 并停止旧 JPanel 所做的一切,因为 intro 也在 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);
}
}
解决方案
我建议的第一件事是使用CardLayout
- 有关更多详细信息,请参阅如何使用 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
s,这对系统的其他部分隐藏了实现细节,并为我提供了更好的定制点。例如,组件不关心“如何”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
并退出线程上下文。
也许如何杀死 Java 线程将是一个起点
推荐阅读
- bash - 通过 SFTP 传输后创建文件
- c# - 如何修复 Visual Studio 2019 中的错误“windows sdk 未正确安装”?
- c++ - 无法为 Sublime Text 设置 EasyClangComplete
- flutter - 大写文本字段,但仅当我单击颤动中的按钮时
- csv - 如何读取 csv 文件并将值传递给 List
在颤抖? - jekyll - 条件模板是否覆盖了 Jekyll 框架的一部分?
- powershell - NoServiceFoundForGivenName 当使用调用命令停止另一个服务器的服务时
- java - 使用 EntityManager 保存时出现 Spring JPA 性能问题
- security - OneSignal - 安全问题
- angular - 角材料 - 表格 - 改变列宽