编辑两个
为了防止刻薄的评论和单行答案遗漏重点:IFF 就像调用 setDoubleBuffered(true) 一样简单,那么我如何访问当前离线缓冲区,以便我可以开始弄乱 BufferedImage 的底层像素数据缓冲区?
我花时间写了一段运行的代码(看起来也很有趣)所以我真的很感激答案实际回答(真是令人震惊;)我的问题并解释这是什么/如何工作而不是一个 -类轮和尖刻的评论;)
这是一段可以在 JFrame 上弹跳正方形的有效代码。我想知道可用于转换这段代码以使其使用双缓冲的各种方法。
请注意,我清除屏幕并重新绘制正方形的方式并不是最有效的,但这实际上不是这个问题的目的(在某种程度上,为了这个例子,它有点慢更好) .
基本上,我需要不断修改 BufferedImage 中的大量像素(以具有某种动画),并且我不想看到由于屏幕上的单缓冲而导致的视觉伪影。
我有一个 JLabel,它的图标是一个 ImageIcon 包裹着一个 BufferedImage。我想修改那个 BufferedImage。
必须做什么才能使其成为双缓冲?
我知道当我在“image 2”上绘图时,会以某种方式显示“image 1”。但是,一旦我在“图像 2” 上绘制完毕,我如何“快速”将 “图像 1” 替换为 “图像 2”?
这是我应该手动执行的操作吗,比如,我自己交换 JLabel 的 ImageIcon?
我是否应该始终在同一个 BufferedImage 中绘图,然后在 JLabel 的 ImageIcon 的 BufferedImage 中快速“blit”该 BufferedImage 的像素? (我想不,我不明白我怎么能把它与显示器的“垂直空白行”“同步”[或等同于平面屏幕:我的意思是,在不干扰显示器本身刷新它的那一刻的情况下“同步”像素,以防止剪切])。
“重绘”命令怎么样?我应该自己触发这些吗?我究竟应该在哪个/什么时候调用 repaint() 或其他方法?
最重要的要求是我应该直接在图像的像素数据缓冲区中修改像素。
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class DemosDoubleBuffering extends JFrame {
private static final int WIDTH = 600;
private static final int HEIGHT = 400;
int xs = 3;
int ys = xs;
int x = 0;
int y = 0;
final int r = 80;
final BufferedImage bi1;
public static void main( final String[] args ) {
final DemosDoubleBuffering frame = new DemosDoubleBuffering();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing( WindowEvent e) {
System.exit(0);
}
});
frame.setSize( WIDTH, HEIGHT );
frame.pack();
frame.setVisible( true );
}
public DemosDoubleBuffering() {
super( "Trying to do double buffering" );
final JLabel jl = new JLabel();
bi1 = new BufferedImage( WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB );
final Thread t = new Thread( new Runnable() {
public void run() {
while ( true ) {
move();
drawSquare( bi1 );
jl.repaint();
try {Thread.sleep(10);} catch (InterruptedException e) {}
}
}
});
t.start();
jl.setIcon( new ImageIcon( bi1 ) );
getContentPane().add( jl );
}
private void drawSquare( final BufferedImage bi ) {
final int[] buf = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
for (int i = 0; i < buf.length; i++) {
buf[i] = 0xFFFFFFFF; // clearing all white
}
for (int xx = 0; xx < r; xx++) {
for (int yy = 0; yy < r; yy++) {
buf[WIDTH*(yy+y)+xx+x] = 0xFF000000;
}
}
}
private void move() {
if ( !(x + xs >= 0 && x + xs + r < bi1.getWidth()) ) {
xs = -xs;
}
if ( !(y + ys >= 0 && y + ys + r < bi1.getHeight()) ) {
ys = -ys;
}
x += xs;
y += ys;
}
}
编辑
这不是全屏 Java 应用程序,而是常规 Java 应用程序,在其自己的(有点小)窗口中运行。
最佳答案
---- 编辑以解决每个像素设置----
项目 blow 解决了双缓冲,但还有一个关于如何将像素放入 BufferedImage 的问题。
如果你打电话
WriteableRaster raster = bi.getRaster()
在 BufferedImage 上,它将返回一个 WriteableRaster。从那里你可以使用
int[] pixels = new int[WIDTH*HEIGHT];
// code to set array elements here
raster.setPixel(0, 0, pixels);
请注意,您可能希望优化代码,而不是为每个渲染实际创建一个新数组。此外,您可能希望优化数组清除代码以不使用 for 循环。
Arrays.fill(pixels, 0xFFFFFFFF);
可能会胜过将背景设置为白色的循环。
---- 回复后编辑----
关键在于 JFrame 的原始设置和运行渲染循环内。
首先,您需要告诉 SWING 随时停止光栅化;因为,当您完成绘制到要完全换出的缓冲图像时,您会告诉它。使用 JFrame 的
setIgnoreRepaint(true);
然后您需要创建一个缓冲策略。基本上它指定了您要使用多少个缓冲区
createBufferStrategy(2);
现在您已尝试创建缓冲区策略,您需要获取 BufferStrategy 对象,因为稍后您将需要它来切换缓冲区。
final BufferStrategy bufferStrategy = getBufferStrategy();
在您的 Thread 中修改 run() 循环以包含:
...
move();
drawSqure(bi1);
Graphics g = bufferStrategy.getDrawGraphics();
g.drawImage(bi1, 0, 0, null);
g.dispose();
bufferStrategy.show();
...
从 bufferStrategy 抓取的图形将是离屏 Graphics 对象,当创建三重缓冲时,它将是“下一个”离屏 Graphics 对象循环方式。
图像和 Graphics 上下文在包含场景中不相关,并且您告诉 Swing 您会自己绘制,因此您必须手动绘制图像。这并不总是坏事,因为您可以在图像完全绘制时(而不是之前)指定缓冲区翻转。
处理图形对象是个好主意,因为它有助于垃圾回收。显示 bufferStrategy 将翻转缓冲区。
虽然上述代码中的某处可能存在失误,但这应该让您完成了 90% 的工作。祝你好运!
---- 原帖如下----
将这样的问题提交给 javase 教程似乎很愚蠢,但您是否查看过 BufferStrategy and BufferCapatbilites ?
我认为您遇到的主要问题是您被图像的名称所愚弄。 BufferedImage 与双缓冲无关,它与“在内存中缓冲数据(通常来自磁盘)”有关。因此,如果您希望拥有“双缓冲图像”,则需要两个 BufferedImages;因为更改正在显示的图像中的像素是不明智的(它可能会导致重新绘制问题)。
在您的渲染代码中,您获取图形对象。如果您按照上面的教程设置双缓冲,这意味着您将(默认情况下)抓取屏幕外的 Graphics 对象,并且所有绘图都将在屏幕外。然后你将你的图像(当然是正确的)绘制到屏幕外的对象上。最后,您告诉策略show() 缓冲区,它会为您替换 Graphics 上下文。
关于Java:如何在 Swing 中进行双缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4430356/
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式rubyshell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R