【发布时间】:2018-11-29 12:33:11
【问题描述】:
我正在做一个小小的个人项目来提高我的 Java 技能。
我在那里做的是创建 3 个 JPanel(一个全局的,2 个全局的)。
在其中一个(右侧)中,我想绘制积木。这些块具有随机的高度、宽度和唯一的 ID。
在我的一个 java 类中,我创建了随机数量的块。然后,我正在做一个绘制这些块的函数,这就是问题所在。 首先,paintComponent 函数执行了两次,我只希望它执行一次。
其次,我的积木……画得不是很好……这是一张 20 块积木画到我的面板中的图片(为了调试,我放了固定数量的积木)。我的窗户是 900x700。
这是我的paintComponent函数,我试图看看我在哪里做错了,但是 我把头发扯掉了。。
【问题讨论】:
-
“我的积木……画得不是很好”——预期的结果是什么?您能否提供您期望的示例图像以及由您的代码生成的相应图像,其中块是可区分的(例如通过不同的颜色)?
-
"paintComponent 函数执行了两次,我只希望它执行一次" - 组件更新/重绘的频率由 ui 框架决定,因此您不应仅依赖于这种情况一次。而是以一种与调用一次或 100 次无关的方式编写代码 - 这意味着将模型(可能包含
listeBlocPlacePanelBloc等)分开并从绘图代码中更新它(使用模型)。 -
UI 会在它认为有必要时重新绘制组件。当您调整窗口大小、移动它、以编程方式使其无效等时,可能会发生这种情况 - 主要教训是:不要依赖重绘的次数!这必然会导致问题,而且无论如何都是不好的风格。具有副作用的绘制方法(即,它们会做除绘制之外的其他事情(例如您将元素添加到非本地列表)会导致比它们解决的问题更多的问题。
-
您需要将处理列表添加等与绘画分开。也就是说,为您的面板提供一些模型(可以像面板内的列表一样简单)并在一些不直接参与绘画的代码中添加块。然后在您的绘画方法中,您只需遍历该列表,但您不会更改它。 - 在您的代码中,似乎
listeBlocPasEncorePlacePanel可能是该列表,尽管名称会产生误导。您不会从该列表中删除块,而是每次都对其进行迭代(并且您不再需要listeBlocPlacePanelBloc)。 -
在绘画时,您不应在该列表中添加或删除任何内容。如果列表发生更改,则使面板无效以使 UI 重新绘制它 - 但这应该发生在绘制代码之外(包括
paintXxx方法和其他方法)。这意味着您的绘画代码仅从列表中读取 - 并且为了防止在绘画时列表更改时可能发生的视觉伪影或ConcurrentModificationExceptions,您可能希望使用 2 个列表:您从中读取的一个一个已更改且更改完成后两者都被交换(也称为“双缓冲”)。