我目前正在为学校开展一个小项目,而且我还处于起步阶段。我刚刚开始阅读JFrame和所有这些内容,所以不要错过为什么我可能不会那么熟悉你将给我看的一切。
现在的目标是拥有一个程序,该程序可以显示图像并能够手动更改该图像的每个像素。因此,我写了以下代码:
public class JavaGraphicsTest {
private static Pixel pixel;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
pixel = new Pixel(1600, 900);
frame.getContentPane().add(pixel);
//pixel.testChange();
}
}
和
public class Pixel extends Component {
private BufferedImage img;
private int width;
private int height;
private Graphics graphics;
public Pixel(int w, int h) {
width = w;
height = h;
}
public void create() {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//Set any color for now
for(int wc = 0; wc < width; wc++) {
for(int hc = 0; hc < height; hc++) {
img.setRGB(wc, hc, new Color(0xAAFFBB).getRGB());
}
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
graphics = g;
create();
update();
}
public void update() {
graphics.drawImage(img, 0, 0, null);
}
public void testChange() {
for(int i = 50; i < 80; i++) {
for(int j = 80; j < 120; j++) {
img.setRGB(i, j, new Color(0xFF8876).getRGB());
}
for(int j = 460; j < 493; j++) {
img.setRGB(i, j, new Color(0xFF8876).getRGB());
}
}
}
}
嗯,代码工作到目前为止(经过几个小时的讨厌错误发现xD),但我现在想要做的似乎是没有工作到目前为止:我想调用方法&#34; pixel.testChange() &#34;在主要方法(它目前评论)。但据我所知,JFrame是如何工作的,一旦我将它添加到JFrame中,我就无法对对象做任何事情。但那谁应该工作呢?如何修改任何活动对象而不删除并重新添加它?
PS:如果您不了解testChange方法应该做什么:它应该将图像的两个块更改为另一种颜色,它基本上是一个测试,看看我是否成功更改了图像
如果您需要有关该项目的更多信息,请问我:)
提前致谢, 儒略
答案 0 :(得分:4)
不要存储Graphics
对象。如初。
public class Pixel extends Component {
private Graphics graphics; // <<-- DO NOT DO THIS
@Override
public void paint(Graphics g) {
// ...
graphics = g; // <<-- DO NOT DO THIS
// ...
}
}
每次调用#paint(Graphics g)
时都可以重新创建图形对象,并在#paint(Graphics g)
退出时失效,销毁或损坏。
同上,请勿在{{1}}来电期间创建图片。只有在创建#paint(Graphics g)
时才能执行此操作。
Pixel
但您可以安全地将public class Pixel extends Component {
@Override
public void paint(Graphics g) {
// ...
create(); // <<-- DO NOT DO THIS, EITHER.
// ...
}
}
对象传递给从Graphics
调用的其他方法。
paint(Graphics g)
确定。对于手头的业务 - 您的public class Pixel extends Component {
// ...
public Pixel(int w, int h) {
width = w;
height = h;
create();
}
@Override
public void paint(Graphics g) {
super.paint(g);
update(g);
}
private void update(Graphics g) {
graphics.drawImage(img, 0, 0, null);
}
}
方法。更改图像后,您只需让Swing使用#testChange()
调用再次绘制您的组件。
#repaint()
最后一点说明:除了事件调度线程(EDT)之外,你真的不应该更改Swing对象。创建第一个窗口时,但在设置可见之前,通常允许例外。
public class Pixel extends Component {
public void testChange() {
int rgb = new Color(0xFF8876).getRGB()); // Cached, for efficiency.
for(int i = 50; i < 80; i++) {
for(int j = 80; j < 120; j++) {
img.setRGB(i, j, rgb);
}
for(int j = 460; j < 493; j++) {
img.setRGB(i, j, rgb);
}
}
repaint(); // <<-- Ask Swing to repaint the component.
}
}
相反,您可以像这样重构代码:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true); // <<-- Window becomes visible here
pixel = new Pixel(1600, 900);
frame.getContentPane().add(pixel); // <<-- DANGEROUS!!
}
更好的是,使用public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
pixel = new Pixel(1600, 900);
frame.getContentPane().add(pixel); // <<-- Safe - window not visible yet.
frame.setVisible(true); // <<-- Window becomes visible here
}
实际切换到EDT:
SwingUtilities.invokeLater(...)
哦,使用Java8,您可以摆脱大部分public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true); // <<-- Window becomes visible here
pixel = new Pixel(1600, 900);
frame.getContentPane().add(pixel); // <<-- Safe - running on EDT.
pixel.testChange(); // <<-- Also safe - running on EDT
}
});
}
样板代码:
Runnable
答案 1 :(得分:0)
在testChange
方法结束时(或在调用它之后),您应该在invalidate
对象上调用Pixel
,这是一个通知组件重绘的信号,因为它已被改变。
同时检查this SO question。