views:

582

answers:

6

Hi, I have a simple object which extends JPanel, when the update() method is called on this object it it meant to add some labels to the panel and then repaint. However the labels do not show up after the update method is called, below is the code for update:

public void update(){
        GridBagConstraints constraints = new GridBagConstraints();

        if(cardsHidden){
            for(int i = 0; i < 2; i++){
                constraints.gridx = i;
                constraints.gridy = 0;
                JLabel card = new JLabel(PlayingCards.cardImages[PlayingCards.CARD_BACK_INDEX]);
                add(card, constraints);
            }
        }
        else{
            Card[] holeCards = player.getHoleCards();
            for(int i = 0; i < holeCards.length; i++){
                constraints.gridx = i;
                constraints.gridy = 0;
                JLabel card = new JLabel(holeCards[i].getImageIcon());
                add(card, constraints); 
            }
        }

        validate();
        repaint();
    }

any ideas?

Thanks

EDIT solved:

It turns out that the HoleCardsPanel wansn't adding to its parent frame properly, once that was fixed the adding of new JLabels works fine. I added call to the update() method to the event dispatch thread using SwingUtillities.invokeLater I additionaly had to call validate() from the uppermost component (in this case the JFrame)strong text

A: 

Have you tried SetVisible() on the labels ?

Have you tried to add the objets at initialisation without any update ? If they don't show up there, they will never show up.

Silence
yes I've tried this but no luck :( (but i did not downvote)
Aly
Ok. Personnally, I disagree with the downvote. People usually forget simple things like this and this may solve someone else problem.
Silence
I agree, so I will upvote to cancel it out
Aly
Are java components not visible by default on creation?
Chris Kannon
Yes. But I don't know the rest of the code. When someone mentions a component not showing up, setvisible comes to my mind. It might not be the solution to the problem for 95 % of people looking for an answer to their own similar problem but for the other 5 % people that will come to this site, to this very question, it will solve it. If I would have said "Did you make sure your screen is turn on ?" I would have agree with a downvote ;)
Silence
Not saying the downvote was worthy, just that he clearly adds the controls in the code above, since he just created them, they MUST be setVisible(true).
Chris Kannon
+1  A: 

Try calling revalidate(); repaint is not what you want.

As per:

API Docs

Note: If a component has been added to a container that has been displayed, validate must be called on that container to display the new component. If multiple components are being added, you can improve efficiency by calling validate only once, after all the components have been added.

revalidate() is basically a invalidate() followed by a validate().

See this question.....

Chris Kannon
I just tried removing the repaint() statement and changed validate() to revalidate() but no luck :(
Aly
are you calling update from another thread, or the event dispatch thread?
Chris Kannon
I am calling update directly from another object running on a standard thread
Aly
Oh, further... call the revalidate on the owning JFrame not the JPanel! Just thought of that.
Chris Kannon
JFrame doesnt have a method 'revalidate()'
Aly
for JFrame validate is correct. If that doesn't work try invalidate first.
Chris Kannon
+2  A: 

The call to validate() should work, although revalidate() may be sufficient; repaint() should not be required. You might compare what you're doing to this example that does dynamic GridBagLayout.

trashgod
+1  A: 

You could try calling updateUI() method.

tou
+5  A: 

It depends on what you want to happen and what layout managers are in use, but the basic rules are:

  1. Make sure update is called on the EDT. If it's not (SwingUtilities.isEventDispatchThread()returns false) you will need to use SwingUtilities.invokeLater to schedule the update on the EDT. For example:

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            update();
        }});
    
  2. Call invalidate(). Most things that change a component will do this for you. So you only need to call this if the following does not work on its own.

  3. Call validate() on the highest affected component. This is probably the muddiest bit of Java's rendering cycle. The call to invalidate marks the component and all of its ancestors as needing layout. The call to validate performs the layout of the component and all of its descendants. One works "up" and the other works "down". You need to call validate on the highest component in the tree that will be affected by your change.

    Also, calling validate on a top-level component (JWindow, JDialog, JFrame) will not necessarily resize that component. To make that happen, you'll need to call pack() or setSize().

  4. If your changes alter the size or position of containers, The resized containers will repaint, but they will not erase the space the used to occupy. Calling repaint() on the parent of the container will cause it to repaint the background, correcting the damage.

Devon_C_Miller
@Devon, where can I find a good resource that discusses all these rules? The Javadoc isn't explicit about everything you wrote above. Surely there is a better resource...?
Gili
Painting (note: this covers both AWT and Swing) http://java.sun.com/products/jfc/tsc/articles/painting/
Devon_C_Miller
Painting and threading: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
Devon_C_Miller
A: 

It turns out that the HoleCardsPanel wansn't adding to its parent frame properly, once that was fixed the adding of new JLabels works fine. I added call to the update() method to the event dispatch thread using SwingUtillities.invokeLater I additionaly had to call validate() from the uppermost component (in this case the JFrame)

Aly
Consider adding these results to your question for future reference.
trashgod