Java 使用timestep更新JLayeredPane内重叠的JPanel时闪烁

Java 使用timestep更新JLayeredPane内重叠的JPanel时闪烁,java,swing,jpanel,jlayeredpane,Java,Swing,Jpanel,Jlayeredpane,我正在用Java做一个游戏。基本上,我需要处理两个不同的更新“平面”。基础层是实际的游戏绘画本身。它只是一个覆盖整个JFrame的JPanel,并被用于使用其图形对象 我使用固定的时间步长来处理这些第一次图形更新。我已经覆盖了paintComponent()方法以完全不做任何事情,因为我已经编写了一个定制的render(float interpolation)方法来处理这个问题,以防止不必要的更新 但是,除了基本的鼠标点击和键盘输入之外,此面板不能接受任何输入。我需要能够创建各种菜单,文本框等,

我正在用Java做一个游戏。基本上,我需要处理两个不同的更新“平面”。基础层是实际的游戏绘画本身。它只是一个覆盖整个JFrame的JPanel,并被用于使用其图形对象

我使用固定的时间步长来处理这些第一次图形更新。我已经覆盖了
paintComponent()
方法以完全不做任何事情,因为我已经编写了一个定制的
render(float interpolation)
方法来处理这个问题,以防止不必要的更新

但是,除了基本的鼠标点击和键盘输入之外,此面板不能接受任何输入。我需要能够创建各种菜单,文本框等,也在屏幕上。像各种能力,甚至是“菜单”按钮,通常出现在左上角的大多数游戏

为了处理输入,比如创建按钮,我有了第二个JPanel,它应用了
setOpaque(false)
。然后,我创建可能需要的各种Swing组件,例如JButton

为了包含这两个JPanel,我使用了一个JLayeredPane,并适当地设置了它们的层,如下所示。这样,输入层应始终位于实际游戏层的顶部

下面的代码显示了如何创建和添加Swing组件
addLoginDialog()
是一种为登录添加Swing组件的方法。它已经过测试,工作正常,不是问题

private void initComponents()
{
    //This code is inside of the JFrame
    wholePane = new JLayeredPane();
    add(wholePane);
    guiPanel = new GUIPanel();
    guiPanel.setOpaque(false);
    gamePanel = new RPGPanel();
    gamePanel.setOpaque(false);
    wholePane.add(gamePanel, JLayeredPane.DEFAULT_LAYER);
    wholePane.add(guiPanel, JLayeredPane.POPUP_LAYER);
    guiPanel.addLoginDialog();
}
所以当我运行代码时,我会看到可怕的闪烁。这是从我的固定时间步运行的代码,每秒约60次

public void handleRepaint()
{
    //I don't use repaint() for the game drawing so I can be sure that fps is controlled.
    Graphics g = gamePanel.getGraphics();
    gamePanel.render(g);
    g.dispose();
    wholePane.repaint();
}
问题是,我认为,两种不同的屏幕更新系统相互冲突。标准的
paintComponent()
系统非常适合静态屏幕,但是当我需要持续更新并跟踪fps时,我不能让更新随机进行

然而,对于输入层,我只想像Swing通常那样进行更新。当鼠标移动到按钮上时,当I组件移动或调整大小时,等等

另外,请注意屏幕闪烁的方式:背景图像变为空白,然后重复出现。输入面板始终在那里,但实际上是在游戏绘图后面绘制的,这不应该发生,因为它放在默认层中。我之所以知道它没有完全消失,是因为游戏画面是部分透明的,所以我可以看到它下面,我添加的按钮仍然存在

我的主要问题是,我怎样才能停止闪烁为什么在JLayeredPane较低层的面板上绘制游戏图形时,会在输入组件的顶部绘制游戏图形?我认为最重要的是,是什么导致了闪烁?谢谢你的帮助

为什么要在输入组件的顶部绘制游戏图形 在较低位置的面板上进行游戏绘图时 JLayeredPane中的图层

主要是因为你回避了Swing的工作原理

让我们从以下事实开始:
图形
上下文是一个共享资源(通常每个本地对等点都有一个
图形
上下文),也就是说,每个组件都获得相同的上下文,这意味着,当您使用自己的绘制例程时,您基本上是在绘制其他所有内容

重新粉刷经理负责决定什么时候粉刷什么东西。所以你现在看到的是两个艺术家在同一块画布上争斗,想要同时在上面作画,这简直是一团糟

再加上Swing的绘画过程不是线程安全的,你最终会陷入一片混乱

如果你一定要控制,那么你需要从等式中删除Swing的绘画引擎

首先看一看


ps-使用
缓冲策略也有硬件加速的好处

要更快地获得更好的帮助,请发布一个。
wholePane.setSize(getSize())布局管理器更有可能遵循参考的大小,而不是大小,但我们也不应该设置。请参阅(是的)。@AndrewThompson尺寸不是问题,所以我现在不太关心这个问题。@AndrewThompson实际上我已经阅读了多个教程,所有的教程都告诉我,当只涉及绘图代码时,要使用渲染方法并确保不使用paintComponent以避免不必要的绘制调用。@user3144349您只需“禁用”渲染引擎,Swing不是这样设计的。它是这样工作的。你不妨试着在冰箱里烤一块……对不起,这是事实。我可以想象,任何告诉您避免使用
paintComponent
的教程也应该告诉您使用
BufferStrategy
。这是控制喷漆过程的唯一方法。这里的问题是,Swing组件被设计为使用被动渲染引擎…catch 22…这是我之前看过的教程+1对于“两位艺术家”的描述,我不知道为什么,但这确实有助于澄清对我来说发生了什么。非常感谢。所以,如果我要完全转换为活动渲染,我还可以使用JButtons、JTextAreas等吗?如果是这样的话,我该怎么做呢?是和否。没有一种连接方式可以连接到组件中,使它们变得有用。由于混合重型和轻型组件存在问题,并且由于您现在基本上担任重绘管理器,因此您将负责确保使用
缓冲策略对其进行绘制。我个人并没有尝试过,但我没有看到很多成功的例子,这并不意味着它不可能很适合你。这是否意味着我正在使用的图形对象已附加到ev