3

So this question has two parts, which I think may be related, and it's mostly abstract. Briefly, here's what I'm doing:

I have a JFrame with a JPanel and some child JPanels each with 3 JButtons on it. I also created a JComponent called glassPanel for the JFrame (i.e. myJFrame.setGlassPane(glassPanel)), that allows me to paint over the JPanels and buttons.

(1) Essentially triggered by clicking all 3 buttons on a JPanel, glassPanel is set to Visible (which appears to then call paintComponent()). This is relates to the first question.

(2) In paintComponent() I draw and paint rectangles and images, using a double buffer, onto glassPanel. This is relates to the second question.

Here's my relevant GlassPanel class code (this is not an SSCCE because it is an abstract question for now):

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;


public class GlassPanel extends JComponent {

     @Override
     protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        setDoubleBuffered(true);
        Graphics2D g2 = (Graphics2D) g;

        g2.drawRect(x,y,width,height);
        g2.fillRect(x,y,width,height);

        g2.drawImage(img, x, y, this);
    }
}

By placing a System.out.print statement inside the paintComponent() method, I could tell it was being called continuously and also asynchronously. For how I think the call is made, see (1). Also, let's say I'm absolutely certain there is no call to repaint() anywhere in the code (I've checked many, many times). This is the basis of the first question.

The first time I click 3 buttons, all goes smoothly. The rectangle and images are both drawn immediately. However, when I click the next 3 buttons (at this point, glassPanel has already been setVisible(true) and the first rectangle and image are still on the screen, painted over the first 3 buttons), the second rectangle and image only load partially. When I click away from the JFrame and onto the Eclipse window that I've run the program from, the number of calls to paintComponent() rapidly increases by the same amount each time AND the partially loaded image(s) and rectangle(s) immediately and completely show up in the background JFrame. When I click back to the JFrame, the number of calls goes up again by an exact amount). This is the basis of the second question.

UPDATE: Here's something I read:

Also, when the GUI is covered by another window and then becomes uncovered, the painting system invokes the paintComponent method with the painting area equal to the newly uncovered area.

My questions are:

(1) why might paintComponent() be called so much without a repaint()? Or, a similar question, what might be calling paintComponent()?

UPDATE: After doing a little math, I strongly believe that it's being called by every component (all buttons and panels) continuously. But still, no call to repaint()...

(2) Why are the images loaded partially until i take focus from the JFrame window?

Note that I have tried many things: (a) creating my own doubleBuffer and using no double buffer (I know it's mostly for animation), (b) overriding and not overriding paintComponent(), (c) drawing and not drawing the image (the rectangle still takes time to load), (d) making absolutely sure there was no repaint(), (e) using and not using SwingUtilities.invokeLater(new Runnable() { public void run() { //stuff});, (f) done an if statement to only setVisible(true) once.

I can try and past the SSCCE if I must, but I do think these are more abstract. Thanks!

Alex Silverman
  • 183
  • 1
  • 5
  • 18
  • 1
    Sorry, Andrew. I know it would be a lot easier to help with the code (running) in front of you. I know I'm not making it easy. But I'm hoping someone has had a similar issue and can answer it without seeing any code. – Alex Silverman Jul 11 '13 at 09:03
  • add Mouse, KeyListener to Glasspane/JComponent with System.out.print and paintComponent is called from methods implemented in APIs – mKorbel Jul 11 '13 at 09:07
  • what would I do with the listeners? – Alex Silverman Jul 11 '13 at 09:22

1 Answers1

1

Well, I think I've answered both questions. For the first, why paintComponent() was being called continuously, was that it was not actually being called continuously. It was being called by all the components when it first shows the GUI. When the Eclipse window covers it and then uncovers it, it gets called more times.

For the second, it has to do with the clipBounds of the Graphics2D object/thing. I found out how the clipBounds were changing for each paint call, so when I set the clip at the start of the paintComponent() method, the images show up immediately. (BTW, It looks GREAT!).

With a twist: after an image is displayed, each click of a button does something to the image. I haven't figured out what exactly, though. It almost looks like its repainting the same image over the old images.

So I have to figure out how to keep the old images but draw new ones when appropriate and only draw/add the new ones onto the glassPanel.

UPDATE: Calling repaint() immediately after each button is clicked helps a little. But it still causes the image to flicker somewhat, as if adding another layer, as the button is pressed, and then it returns to normal when the user lets go.

Alex Silverman
  • 183
  • 1
  • 5
  • 18
  • Consider drawing on a `JPanel` instead of over a `JComponent`, as there lies slight difference between the two as cited in [this answer](http://stackoverflow.com/a/16998657/1057230) :-) – nIcE cOw Jul 11 '13 at 11:03
  • The problem with using JPanel is that i can't do a lot of the other things I want: check if it's visible, automatic double buffer, glass pane, etc. – Alex Silverman Jul 11 '13 at 11:17
  • 1
    Are you kidding me!!, Swing uses Double Buffering by default, in many of it's components (JPanel falls in that, no doubt), have a look at what [Java Tutorials](http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html) has to say on that :-) – nIcE cOw Jul 11 '13 at 11:20
  • what about glasspane? So setDoubleBuffer(true) is useless unless I specify otherwise? Also, do you think the problem could lie in the buffered image being redrawn over itself, such that creating my own double buffer again would be useful? – Alex Silverman Jul 11 '13 at 11:22
  • I guess partially it depends on the route one takes to paint artifacts on the screen, so for that reason, I guess, one needs to see the code, for that matter. – nIcE cOw Jul 11 '13 at 11:25
  • 1
    `JPanel` is a subclass of `JComponent`. You shouldn't be changing calling `setDoubleBuffered` within `paintComponent` anyway, as it may trigger another repaint. You should also avoid playing with the clipBounds, they are set by the parent container before the child is painted, to meet the bounds requirements of the child component. Check out [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) for more details – MadProgrammer Jul 12 '13 at 05:16