【问题标题】:Switching contentpane in real time实时切换内容窗格
【发布时间】:2018-08-01 20:15:59
【问题描述】:

我尝试制作带有介绍和完整视频或按键后跳到菜单的 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;其次,您需要定义某种“生命周期”,因此当您的控制器检测到“导航”事件时,它可以指示当前视图“停止”或“处置”或“准备解雇”——无论何时——何时它被切换到新视图。 “如何”有点复杂,因为您需要根据您的整体要求进行操作

标签: java multithreading swing jpanel


【解决方案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();
        }
    }
}

如您所见,我喜欢使用interfaces,这对系统的其他部分隐藏了实现细节,并为我提供了更好的定制点。例如,组件不关心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 会是一个起点

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多