java - Java:图像、图形和面板
问题描述
我正在尝试通过 Java 制作动画,但无法理解 DoubleBufferImage 和 DoubleBufferGraphics。我了解 update()、render() 和 paint() 序列。但是,在每个方法中,我无法理解它是如何绘制的。这是代码。
gameUpdate() // 我将跳过更新部分,因为我首先需要了解背景。
游戏渲染()
private void gameRender() { if (DoubleBufferImage == null) { System.out.println("The Image is null: Error occurence"); DoubleBufferImage = createImage(P_WIDTH - 15, P_HEIGHT - 15); } DoubleBufferGraphic = DoubleBufferImage.getGraphics(); DoubleBufferGraphic.setColor(Color.LIGHT_GRAY); DoubleBufferGraphic.fillRect(0, 0, P_WIDTH, P_HEIGHT); DoubleBufferGraphic.setColor(Color.BLUE); DoubleBufferGraphic.setFont(font); DoubleBufferGraphic.drawString("Average FPS/UPS: " + df.format(averageFPS) + df.format(averageUPS), 10, 10); }
画()
public void paintScreen() { Graphics g; try { g = this.getGraphics(); if ((g != null) && (DoubleBufferImage != null)) { g.drawImage(DoubleBufferImage, 0, 0, null); } Toolkit.getDefaultToolkit().sync(); } catch (Exception e) { System.out.println("Graphics context error: " + e); } }
还有从 Jpanel 覆盖的 paintComponent 方法。
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (DoubleBufferImage != null) {
g.drawImage(DoubleBufferImage, 0, 0, null);
}
}
这是我的问题。运行是更新->渲染->和绘画但是从渲染中可以看出,他们使用图形来绘制。但这都是在 DoubleBufferImage 中绘制的吗?Image 实例是否类似于面板实例?我的意思是,它只是可添加到框架中吗?由于这是双缓冲系统,所以我想知道哪些方法是直接绘制的,哪些是预先绘制的方法。最后在运行中,没有任何代码表明我们制作的图像或图形将被添加到面板中。我只想知道绘制 BufferedImage 的时间。请帮忙!我无法上传整个代码,所以我不确定你们是否能理解:(
解决方案
好的,所以你似乎在反对一些错误信息和误解。也许您应该首先在画笔类型的 GUI 中查看诸如 paintComponent() 与 paint() 以及 JPanel 与 Canvas 之类的东西
在 AWT/Swing 中,至少有两种执行自定义绘画的方式,每种方式各有利弊。
您可以使用paintComponent
,它是 Swing 使用的绘画系统的“钩子”。Swing 使用“被动”渲染系统。这意味着您无法控制何时绘制某些东西,绘制系统会做出这些决定,然后(间接)调用paintComponent
组件的,以便您可以执行更新。
另一种机制 ( BufferStrategy
) 使用“主动”渲染系统,它可以让您完全控制绘画发生的时间。
作为一般规则,你不能混合它们。Swing 有自己的绘画系统,不能很好地与BufferStrategy
.
但这不会回答你的问题,或者不会直接回答
让我们尝试分解它
gameRender
private void gameRender() {
if (DoubleBufferImage == null) {
System.out.println("The Image is null: Error occurence");
DoubleBufferImage = createImage(P_WIDTH - 15, P_HEIGHT - 15);
}
DoubleBufferGraphic = DoubleBufferImage.getGraphics();
DoubleBufferGraphic.setColor(Color.LIGHT_GRAY);
DoubleBufferGraphic.fillRect(0, 0, P_WIDTH, P_HEIGHT);
DoubleBufferGraphic.setColor(Color.BLUE);
DoubleBufferGraphic.setFont(font);
DoubleBufferGraphic.drawString("Average FPS/UPS: " +
df.format(averageFPS) + df.format(averageUPS), 10, 10);
}
此时,DoubleBufferImage
似乎是 a BufferedImage
,所以当gameRender
被调用时,它会检查缓冲区是否存在并根据需要创建它。DoubleBufferImage
然后它获取s上下文的引用Graphics
并准备渲染,清除之前绘制的内容。
快速概览Graphics
Graphics
是底层渲染管道顶部的抽象层,通常使用 OpenGL 或 DirectX 来实现,具体取决于系统。它提供了一个公共层,可以在该层上以独立于系统的方式执行图形操作
paintScreen
public void paintScreen() {
Graphics g;
try {
g = this.getGraphics();
if ((g != null) && (DoubleBufferImage != null)) {
g.drawImage(DoubleBufferImage, 0, 0, null);
}
Toolkit.getDefaultToolkit().sync();
} catch (Exception e) {
System.out.println("Graphics context error: " + e);
}
}
这让我很担心,因为我没有上下文,但this.getGraphics()
似乎正在参考组件的Graphics
上下文并绘制DoubleBufferImage
它。
这是危险的,也是不明智的。getGraphics
返回组件上次绘制时的快照,可以在再次绘制组件时随时绘制。
您应该尽早摆脱这种方法。
paintComponent
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (DoubleBufferImage != null) {
g.drawImage(DoubleBufferImage, 0, 0, null);
}
}
如上所述,paintComponent
这是挂钩到 Swing 油漆系统的首选方法。所有这一切都是描绘DoubleBufferImage
它,尽管它实际上应该阅读g.drawImage(DoubleBufferImage, 0, 0, this);
那么,这一切在做什么呢?
基本上,在 Swing 中执行双缓冲是不明智的尝试……默认情况下它已经是双缓冲的。
但是,正如您从渲染中看到的那样,他们使用图形进行绘制。但这都是在 DoubleBufferImage 中绘制的吗?Image 实例是否类似于面板实例?
不,组件是一个对象,它具有许多属性。它的工作之一是绘制它的状态,这是通过各种绘制方法完成的,它传递一个Graphics
附加到本机对等点的上下文,最终将呈现到屏幕(或打印机)。
ABufferedImage
就是这样,一个图像。Graphics
上下文只是一种简单的方法,您可以通过它来绘制它。然后可以将其保存到文件中,或者像这里的情况一样,将其绘制到组件(通过它的Graphics
)上下文中。
正如我上面所说,Graphics
只是一个抽象层,它允许您对多个不同的目的地、屏幕、打印机、图像等执行绘画操作......
我的意思是,它只是可添加到框架中吗?
不,它不是基于组件的类
由于这是双缓冲系统,所以我想知道哪些方法是直接绘制的,哪些是预先绘制的方法。
paintComponent
并且(不明智的)paintScreen
将图像直接绘制到组件上,最终将由绘制子系统渲染到屏幕上。
进一步阅读...
推荐阅读
- javascript - Redux 状态无法从调度程序更新
- java - JAVA_HOME 未指向 JDK
- python - 如何使用 python 3.8 将多个值作为 JSON 返回?
- sql - 如何在 WHERE 子句的 LIKE 运算符中使用撇号?示例 - WHERE WORD like '%That's why%'
- rsync - rsync 将文件列表从一台服务器同步到另一台服务器
- flutter - 如何将图像转换为base64颤振?
- qt - 如何在 Qt 上实时移动我的地图标记?
- javascript - app.js:6 Uncaught TypeError: Cannot read property 'addEventListener' of null
- python - Django ValueError:字段“id”需要一个数字但得到“S”
- spartacus-storefront - Spartacus Angular 搜索框建议不适用于 iPad 设备