内部内容在 JScrollPane 中显示然后消失

Inner content showing then disappearing in JScrollPane

我的问题与带有内部 JPanelJScrollPane 有关。我尝试在 JPanel 上画画,但它出现的时间非常短暂,然后消失,直到我手动移动 HorizontalScrollBar,然后再次出现并保持稳定。为了避免手动干预(或在实际代码中难以管理的 HorizontalScrollBar.setValue),我在 JPanelViewport 上尝试了 validate/revalidate(以及更多),但没有成功。 JScrollPaneJFrame.

下面的(非常)简化的代码重现了这个问题。可能很明显,但我看不到。

public class Main {

private JFrame mainPane;

private RenderZone renderZone = new RenderZone();
private JScrollPane renderScrollPane = new JScrollPane(renderZone,
        JScrollPane.VERTICAL_SCROLLBAR_NEVER, 
        JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);



public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Main window = new Main();
                window.mainPane.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public Main() {
    initialize();
}

private void initialize() {
    mainPane = new JFrame();
    mainPane.setPreferredSize(new Dimension(1024, 768));
    mainPane.setSize(new Dimension(1024, 768));
    mainPane.setLocation(new Point(200, 200));
    mainPane.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    SpringLayout springLayout = new SpringLayout();
    springLayout.putConstraint(SpringLayout.NORTH, renderScrollPane, 0, SpringLayout.NORTH, mainPane.getContentPane());
    springLayout.putConstraint(SpringLayout.WEST, renderScrollPane, 0, SpringLayout.WEST, mainPane.getContentPane());
    springLayout.putConstraint(SpringLayout.SOUTH, renderScrollPane, 0, SpringLayout.SOUTH, mainPane.getContentPane());
    springLayout.putConstraint(SpringLayout.EAST, renderScrollPane, 0, SpringLayout.EAST, mainPane.getContentPane());
    mainPane.getContentPane().setLayout(springLayout);
    mainPane.getContentPane().add(renderScrollPane);

}

public class RenderZone extends JPanel {

    private static final long serialVersionUID = -8240875812801921009L;

    private BufferedImage image = null;
    private BufferedImage sub = null;

    public RenderZone() {
        this.setBackground(Color.WHITE);
        this.setPreferredSize(new Dimension(1124, 768));// added 100 for test purpose
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);// pour repeindre la panel à chaque fois
        Graphics2D g2 = (Graphics2D)this.getGraphics();
        if(image==null) {

            try {
                image = ImageIO.read(RenderZone.class.getResourceAsStream("TestImage0.png"));
                sub = image.getSubimage(0, 0, 1024, 768);
            } catch (IOException e) {}
        }

        if( sub!=null)g2.drawImage(sub, 0, 0, null); 
        g2.dispose();
    }
}
}

代码有几处错误,这是修复后的代码。解释见代码下方的要点

public class RenderZone extends JPanel {

    private static final long serialVersionUID = -8240875812801921009L;

    private BufferedImage image = null;
    private BufferedImage sub = null;

    public RenderZone() {
        this.setBackground(Color.WHITE);
        this.setPreferredSize(new Dimension(1124, 768));// added 100 for test purpose
        image = new BufferedImage(2000, 1000, BufferedImage.TYPE_INT_RGB);
        sub = image.getSubimage(0, 0, 1024, 768);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);// pour repeindre la panel à chaque fois
        if (sub != null) {
            g.drawImage(sub, 0, 0, this);
        }
    }
}

好的..

  1. Graphics2D g2 = (Graphics2D)this.getGraphics(); 当您已经有了一个有效的 Graphics 实例时,很难确定为什么您认为这是个好主意。但基本上,使用提供的 Graphics 实例。
  2. ImageIO.read(..); 读取图像 不是 应该在任何绘画方法中完成的事情。它应该在 class 的构造函数中加载一次。
  3. sub = image.getSubimage(0, 0, 1024, 768); 同样,并不是每次调用 paint 时你都想做的事情,事实上,在照片编辑软件中以合适的尺寸创建图像会更优化,而且只是加载 裁剪后的 图像。
  4. } catch (IOException e) {} 不要忽略异常!他们告诉我们究竟出了什么问题。除非实现日志记录,否则至少调用 Throwable.printStackTrace()
  5. if( sub!=null)g2.drawImage(sub, 0, 0, null);因为每个JComponent都是一个ImageObserver,所以应该是
    if( sub!=null)g2.drawImage(sub, 0, 0, this);

还有一些可疑但不属于当前问题的部分,因此它们没有改变:

  1. // pour repeindre la panel à chaque fois .. 法语的代码注释(仅供人类使用)有什么意义?请用英文放置代码注释(针对此站点)。否则它们就是噪音。
  2. this.setPreferredSize(new Dimension(1124, 768)); 可能最好覆盖 getPreferredSize() 和 return 一个基于 sub 图像大小(如直接从中获取的数字)的值。
  3. mainPane.setPreferredSize(new Dimension(1024, 768)); 这比 mainPane.pack(); 更好。后者不是猜测,将考虑子组件的首选大小。