SSCCE,尽可能小,保持所有逻辑的顺序相同:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Test {
public static void main(String[] args) {
new Test();
}
BufferedImage img = null; // <-- needs this scope
JFrame mainWindow = new JFrame();
JLabel mainImage = new JLabel();
public Test() {
mainWindow.add(mainImage);
mainWindow.setVisible(true);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// step 5
mainImage.addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {
dostuff();
}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mousePressed(MouseEvent e) {}
@Override public void mouseReleased(MouseEvent e) {}
});
dostuff();
}
private void dostuff() {
// step 1
try {
JFileChooser fc = new JFileChooser();
fc.showOpenDialog(null);
File file = fc.getSelectedFile();
img = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
//step 2
mainImage.setIcon(new ImageIcon(img));
mainWindow.pack();
mainWindow.setLocationRelativeTo(null);
Graphics2D g = img.createGraphics();
g.setColor(new Color(0xFFFF0000));
g.drawOval(10, 10, 10, 10);
try{Thread.sleep(2000);}catch(Exception e){}
// step 3
BufferedImage img2 = new BufferedImage(400,300,BufferedImage.TYPE_INT_RGB);
for (int i = 10 ; i < 20 ; i++) {
for (int j = 10 ; j < 20 ; j++) {
img2.setRGB(i,j,0xFF0000FF);
}
}
// step 4
mainImage.setIcon(new ImageIcon(img2));
mainWindow.pack();
mainWindow.setLocationRelativeTo(null);
}
}
我应该明白我正在尝试做什么,并且编译将表明它没有这样做。但我希望这篇文章有一个问号所以这里是问题描述和问题:
我想要发生什么:
加载程序,系统会提示用户选择文件(图像)。
选择图像后,该图像将显示在JFrame中,并且会在其上显示一些Graphics2D图形。 (我包括sleep(),因为这些图纸在实际程序中需要一段时间)
完成绘图后,会创建一个新图像并将其绘制出来。
新图片会替换JFrame中的旧图片
当用户点击图片时,系统会提示他们选择新图片,我们会从第1步开始重复。
发生了什么:
第一步到第四步工作正常。在第五步,选择图像后,JFrame将填入一个用户选择图像大小的黑色矩形,第三步的图像覆盖在左上角,第二步不会发生,第三步到第五步似乎工作得很好。
更重要的是,在我的实际程序中,我可以看出新的用户选择图像通过第三步产生的输出正常工作。
所以问题是,如何修复第2步的后续重复,以便在JFrame中显示适当的图像?
编辑:这张imgur专辑逐步显示了我得到的结果。 http://imgur.com/a/xW051
EDIT2:在没有Thread.sleep()
的情况下更新import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Test {
public static void main(String[] args) {
new Test();
}
BufferedImage img = null; // <-- needs this scope
JFrame mainWindow = new JFrame();
JLabel mainImage = new JLabel();
public Test() {
mainWindow.add(mainImage);
mainWindow.setVisible(true);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// step 5
mainImage.addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {
dostuff();
}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mousePressed(MouseEvent e) {}
@Override public void mouseReleased(MouseEvent e) {}
});
dostuff();
}
private void dostuff() {
// step 1
try {
JFileChooser fc = new JFileChooser();
fc.showOpenDialog(null);
File file = fc.getSelectedFile();
img = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
//step 2
mainImage.setIcon(new ImageIcon(img));
mainWindow.pack();
mainWindow.setLocationRelativeTo(null);
Graphics2D g = img.createGraphics();
g.setColor(new Color(0xFFFF0000));
for (int h = 0 ; h < 0xFF ; h++) {
for (int i = 0 ; i < img.getWidth() ; i++) {
for (int j = 0 ; j < img.getHeight()/2 ; j++) {
img.setRGB(i,j,0x88FF0000 + h);
}
}
mainImage.repaint();
}
// step 3
BufferedImage img2 = new BufferedImage(400,300,BufferedImage.TYPE_INT_RGB);
for (int i = 10 ; i < 20 ; i++) {
for (int j = 10 ; j < 20 ; j++) {
img2.setRGB(i,j,0xFF0000FF);
}
}
// step 4
mainImage.setIcon(new ImageIcon(img2));
mainWindow.pack();
mainWindow.setLocationRelativeTo(null);
}
}
答案 0 :(得分:2)
编辑:
如果我然后加载1000x1000图像,我会看到一个1000x1000黑色方块......
我猜黑色图像是因为你导致事件调度线程(EDT)进入睡眠状态。因此,虽然框架使用pack()语句调整大小,但新加载的图像未被绘制。
不要在EDT上执行的代码中使用Thread.sleep()。从侦听器执行的所有代码都在EDT上执行。相反,您应该使用Swing Timer来安排事件来更新标签的图像。
编辑2:
阅读Concurrency上的Swing教程中的部分。通常,所有事件代码都在EDT上执行。当EDT被阻止时,Swing组件不能重新绘制。
mainImage.setIcon(new ImageIcon(img));
上述语句将导致在&#34; mainImage&#34;上调用repaint()。标签。 repaint()请求被传递给RepaintManager,并且绘画请求被添加到EDT的末尾。
因此标签将在&#34; doStuff()&#34;中的所有代码之后绘制。方法已经完成执行。
但是你也可以调用
mainImage.setIcon(new ImageIcon(img2));
在方法结束时。因此,当图像实际被绘制时,它的Icon已经被第二次更改,因此只绘制了第二个Icon。
在这两个语句之间,在读取图像后,在调用pack()方法时调整帧的大小。我相信这是因为帧的打包导致OS级绘制,因为帧是OS小部件而不是Swing组件。换句话说,即使帧上的组件没有重新绘制,也可以调整帧的大小。
如果您想要一个响应式GUI,那么您就无法在EDT上执行长时间运行的代码。在第二个SSCCE的情况下,&#34; for循环&#34;你补充说需要很长时间 运行,这有效地阻止了EDT并阻止了新读取的图标。
因此,长时间运行的任务应该在单独的Thread
上执行。并发教程将解释如何使用SwingWorker
进行长时间运行的任务。