为什么仅在我在 Swing 中调整 window 的大小后才显示 JFrame 的背景图像?
Why is a Background Image of a JFrame only showing after i resize the window in Swing?
我注意到将图像设置为 JFrames 的背景时出现了一些奇怪的行为。我希望在创建两个框架时都显示背景图像。
当我在我的主要方法中创建 Window1 时,它只在我手动调整 window 的大小后显示背景。当我单击 Window1 中的按钮并在 Window1 中创建 window2 时,Window2 会正确显示背景图像。当我在我的主要方法中创建 Window2 时,背景图像也无法正确显示。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestStart {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Window1();
}
});
}
}
public class Window1 extends JFrame {
Image img = Toolkit.getDefaultToolkit().getImage("C:\Users\Tim\Desktop\water.jpg");
public Window1() {
super("gridtest");
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
new Window2();
}
});
pack();
setVisible(true);
}
}
public class Window2 extends JFrame {
Image img = Toolkit.getDefaultToolkit().getImage("C:\Users\Tim\Desktop\water.jpg");
public Window2() {
super("gridsecond");
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
pack();
setVisible(true);
}
}
我尝试在我的代码中的不同点添加 revalidate()/repaint() 调用并调用 paint 方法,但除了我上面描述的奇怪行为外,我无法在不调整我的大小的情况下显示背景图像window.
免责声明:我知道为每个 window 创建一个新的 JFrame 不是好的做法,但我无法更改整个项目结构,所以我坚持这样做。
那么,一系列问题可能会导致您的问题...
首先,使用Toolkit.getDefaultToolkit().getImage
Image img = Toolkit.getDefaultToolkit().getImage("C:\Users\Tim\Desktop\water.jpg");
问题在于,图像加载是在一个单独的线程上进行的。这意味着当 getImage
returns 图像可能已实际加载也可能未加载
其次,当调用 drawImage
时,您将 null
作为 ImageConsumer
传递,因此组件不会收到图像 "loaded" 状态和将无法相应地安排组件更新...
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
三,这更多是副作用,但是,您已经使用 JPanel
手动设置了 contentPane
,默认情况下使用 FlowLayout
,因此使用 BorderLayout
约束实际上有点毫无意义。
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
//...
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);
此外,BorderLayout
是基于 window 的组件使用的默认布局管理器 ;)
那么,您将如何解决这个问题?那么,您可以立即将 this
作为 ImageConsumer
...
g.drawImage(img,0,0,getWidth(),getHeight(),this);
这将允许组件监视图像的加载状态并根据需要触发重绘。
一个长期的解决方案是停止使用 Toolkit.getDefaultToolkit().getImage
(并推而广之,ImageIcon
),因为它们可能很烦人,并开始使用 ImageIO
。
除了支持更广泛的图像格式外,API 不会 return 直到图像完全加载或发生错误(尝试诊断其他加载问题 APIs )
有关详细信息,请参阅 Reading/Loading images
我注意到将图像设置为 JFrames 的背景时出现了一些奇怪的行为。我希望在创建两个框架时都显示背景图像。 当我在我的主要方法中创建 Window1 时,它只在我手动调整 window 的大小后显示背景。当我单击 Window1 中的按钮并在 Window1 中创建 window2 时,Window2 会正确显示背景图像。当我在我的主要方法中创建 Window2 时,背景图像也无法正确显示。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestStart {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Window1();
}
});
}
}
public class Window1 extends JFrame {
Image img = Toolkit.getDefaultToolkit().getImage("C:\Users\Tim\Desktop\water.jpg");
public Window1() {
super("gridtest");
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
new Window2();
}
});
pack();
setVisible(true);
}
}
public class Window2 extends JFrame {
Image img = Toolkit.getDefaultToolkit().getImage("C:\Users\Tim\Desktop\water.jpg");
public Window2() {
super("gridsecond");
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
pack();
setVisible(true);
}
}
我尝试在我的代码中的不同点添加 revalidate()/repaint() 调用并调用 paint 方法,但除了我上面描述的奇怪行为外,我无法在不调整我的大小的情况下显示背景图像window.
免责声明:我知道为每个 window 创建一个新的 JFrame 不是好的做法,但我无法更改整个项目结构,所以我坚持这样做。
那么,一系列问题可能会导致您的问题...
首先,使用Toolkit.getDefaultToolkit().getImage
Image img = Toolkit.getDefaultToolkit().getImage("C:\Users\Tim\Desktop\water.jpg");
问题在于,图像加载是在一个单独的线程上进行的。这意味着当 getImage
returns 图像可能已实际加载也可能未加载
其次,当调用 drawImage
时,您将 null
作为 ImageConsumer
传递,因此组件不会收到图像 "loaded" 状态和将无法相应地安排组件更新...
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
三,这更多是副作用,但是,您已经使用 JPanel
手动设置了 contentPane
,默认情况下使用 FlowLayout
,因此使用 BorderLayout
约束实际上有点毫无意义。
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
//...
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);
此外,BorderLayout
是基于 window 的组件使用的默认布局管理器 ;)
那么,您将如何解决这个问题?那么,您可以立即将 this
作为 ImageConsumer
...
g.drawImage(img,0,0,getWidth(),getHeight(),this);
这将允许组件监视图像的加载状态并根据需要触发重绘。
一个长期的解决方案是停止使用 Toolkit.getDefaultToolkit().getImage
(并推而广之,ImageIcon
),因为它们可能很烦人,并开始使用 ImageIO
。
除了支持更广泛的图像格式外,API 不会 return 直到图像完全加载或发生错误(尝试诊断其他加载问题 APIs )
有关详细信息,请参阅 Reading/Loading images