Note that there are some explanatory texts on larger screens.

plurals
  1. PODrawing a Component to BufferedImage causes display corruption
    text
    copied!<p>I am using the <code>JScrollNavigator</code> component described <a href="http://www.javalobby.org/java/forums/t21355.html" rel="nofollow noreferrer">here</a>, in order to provide a navigation window onto a large "canvas-like" CAD component I have embedded within a <code>JScrollPane</code>.</p> <p>I have tried to adapt the <code>JScrollNavigator</code> to draw a thumbnail image of the canvas to provide some additional context to the user. However, the action of doing this causes the rendering of my application's main frame to become corrupted. Specifically, it is the action of calling <code>paint(Graphics)</code> on the viewport component (i.e. my main canvas), passing in the <code>Graphics</code> object created by the <code>BufferedImage</code> that causes subsequent display corruption; if I comment this line out everything works fine.</p> <p>Below is the <code>JScrollNavigator</code>'s overridden <code>paintComponent</code> method:</p> <pre><code>@Override protected void paintComponent(Graphics g) { Component view = jScrollPane.getViewport().getView(); BufferedImage img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); // Paint JScrollPane view to off-screen image and then scale. // It is this action that causes the display corruption! view.paint(g2d); g2d.drawImage(img, 0, 0, null); Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0); super.paintComponent(g); g.drawImage(scaled, 0, 0, null); } </code></pre> <p>Does anyone have any suggestions as to the cause of the corruption? I would have thought that painting to an offscreen image should have no effect on existing paint operations.</p> <p><strong>EDIT</strong></p> <p>To provide some additional detail: The <code>JScrollNavigator</code> forms a sub-panel on the left-hand side of a <code>JSplitPane</code>. The <code>JScrollPane</code> associated with the navigator is on the right-hand side. The "corruption" causes the splitter to no longer be rendered and the scrollbars to not be visible (they appear white). If I resize the <code>JFrame</code>, the <code>JMenu</code> section also becomes white. If I attempt to use the navigator or interact with the scrollbars, they become visible, but the splitter remains white. It's as if the opaque settings of the various components has been affected by the rendering of the viewport view to an offscreen image.</p> <p>Also, if I make the <code>JScrollNavigator</code> appear in a completely separate <code>JDialog</code>, everything works correctly.</p> <p><strong>EDIT 2</strong></p> <p>I can reproduce the problem <strong>consistently</strong> by doing the following:</p> <p>Add a <code>JMenuBar</code> to the <code>mFrame</code>:</p> <pre><code>JMenuBar bar = new JMenuBar(); bar.add(new JMenu("File")); mFrame.setJMenuBar(bar); </code></pre> <p>In the <code>main()</code> method of <code>JScrollNavigator</code> replace:</p> <pre><code>jsp.setViewportView(textArea); </code></pre> <p>... with:</p> <pre><code>jsp.setViewportView(new JPanel() { { setBackground(Color.GREEN); setBorder(BorderFactory.createLineBorder(Color.BLACK, 5)); } }); </code></pre> <p>Ensure that the <code>JScrollNavigator</code> is embedded as a panel within <code>mFrame</code>, rather than appearing as a separate <code>JDialog</code>:</p> <pre><code>mFrame.add(jsp, BorderLayout.CENTER); mFrame.add(nav, BorderLayout.NORTH); </code></pre> <p>Now when the application runs the <code>JMenuBar</code> <strong>is no longer visible</strong>; the act of painting the view (i.e. a green <code>JPanel</code> with thick black border) to the <code>Graphics2D</code> returned by <code>BufferedImage.createGraphics()</code> actually appears to be rendering it <strong>onscreen</strong>, possibly from the top-left corner of the JFrame, thus obscuring other components. This only seems to happen if a <code>JPanel</code> is used as the viewport view, and not another component such as <code>JTextArea</code>, <code>JTable</code>, etc.</p> <p><strong>EDIT 3</strong></p> <p>Looks like this person was having the same problem (no solution posted though): <a href="http://www.javaworld.com/community/node/2894/" rel="nofollow noreferrer">http://www.javaworld.com/community/node/2894/</a></p> <p><strong>EDIT 4</strong></p> <p>Here's the <code>main</code> and <code>paintComponent</code> methods that result in the reproducible error described in Edit 2:</p> <pre><code>public static void main(String[] args) { JScrollPane jsp = new JScrollPane(); jsp.setViewportView(new JPanel() { { setBackground(Color.GREEN); setBorder(BorderFactory.createLineBorder(Color.BLACK, 5)); } }); JScrollNavigator nav = new JScrollNavigator(); nav.setJScrollPane(jsp); JFrame mFrame = new JFrame(); JMenuBar bar = new JMenuBar(); bar.add(new JMenu("File")); mFrame.setJMenuBar(bar); mFrame.setTitle("JScrollNavigator Test"); mFrame.setSize(800, 600); mFrame.setLayout(new GridLayout(1, 2)); mFrame.add(jsp); mFrame.add(nav); Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize(); mFrame.setLocation((screenDim.width - mFrame.getSize().width) / 2, (screenDim.height - mFrame.getSize().height) / 2); mFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mFrame.setVisible(true); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Component view = jScrollPane.getViewport().getView(); if (img == null) { GraphicsConfiguration gfConf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB); } Graphics2D g2d = img.createGraphics(); view.paint(g2d); Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0); g.drawImage(scaled, 0, 0, null); } </code></pre> <p><strong>EDIT 5</strong></p> <p>It seems like others are having trouble recreating the exact problem. I would ask people to run the code pasted <a href="http://pastebin.com/ueuNSBjy" rel="nofollow noreferrer">here</a>. When I first run this example I see the following:</p> <p><img src="https://i.stack.imgur.com/S1vPB.png" alt="Corrupt Image 1"></p> <p>Neither the JScrollNavigator or the JMenuBar have been painted; these frame areas are transparent.</p> <p>After resizing I see the following:</p> <p><img src="https://i.stack.imgur.com/qraWO.png" alt="Corrupt Image 2"></p> <p>The <code>JMenuBar</code> has still not been painted and it appears that the <code>JPanel</code> was at some point rendered at (0,0) (where the <code>JMenuBar</code> should be). The <code>view.paint</code> call within <code>paintComponent</code> is the direct cause of this.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload