Difference Between Validate(), Revalidate() and Invalidate() in Swing Gui

Difference between validate(), revalidate() and invalidate() in Swing GUI

invalidate() marks the container as invalid. Means the content is somehow wrong and must be re-laid out. But it's just a kind of mark/flag. It's possible that multiple invalid containers must be refreshed later.

validate() performs relayout. It means invalid content is asked for all the sizes and all the subcomponents' sizes are set to proper values by LayoutManager.

revalidate() is just sum of both. It marks the container as invalid and performs layout of the container.

UPDATE:

Some code from Component.java

public void revalidate() {
revalidateSynchronously();
}

/**
* Revalidates the component synchronously.
*/
final void revalidateSynchronously() {
synchronized (getTreeLock()) {
invalidate();

Container root = getContainer();
if (root == null) {
// There's no parents. Just validate itself.
validate();
} else {
while (!root.isValidateRoot()) {
if (root.getContainer() == null) {
// If there's no validate roots, we'll validate the
// topmost container
break;
}

root = root.getContainer();
}

root.validate();
}
}
}

When are validate(), invalidate() and the combination of both mandatory?

My simple way of looking at this is that revalidate() is used when a property of a Swing component is changed that will possibly affect the size of the component. Since the size of the component may change the layout of components on the panel may be effected. So the revalidate() is basically used to make sure the layout manager is invoked.

Swing components are smart enough to invoke revalidate() and repaint() when needed. Note AWT components did not invoke invalidate() and validate() automatically so it was more of an issue when using AWT.

That is when you invoke any "setter" method on a Swing component it does the revalidate() and repaint() for you.

That is why in your simple example above you don't need to invoke revalidate().

One case where you need to invoke revalidate() manually is when you add components to a panel on a visible GUI. After you add all the components to the panel you would invoke revalidate() to invoke the layout manager of the panel.

Java Swing revalidate() vs repaint()

You need to call repaint() and revalidate(). The former tells Swing that an area of the window is dirty (which is necessary to erase the image of the old children removed by removeAll()); the latter tells the layout manager to recalculate the layout (which is necessary when adding components). This should cause children of the panel to repaint, but may not cause the panel itself to do so (see this for the list of repaint triggers).

On a more general note: rather than reusing the original panel, I'd recommend building a new panel and swapping them at the parent.

Remove Swing Component Using Validate or Revalidate

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

Look at Sun's Java source code.

You want to call revalidate().

Java Swing: repaint() vs invalidate

Q1: which should I use when my
interface has changed: repaint or
invalidate?

If the layout is not up to date because of resizing , font change etc then you should call invalidate. Invalidating a component, invalidates the component and all parents above it are marked as needing to be laid out. Prior to painting, in the validation step if no change is found then the paint step is left out.

If there is some part of component which is being updated (defined by the graphic's clip rectangle, called "damaged" region) then you should consider calling repaint. One of the reason a damaged regions may occur is from the overlapping of a part of your component because of some other component or application.
As per my experience the repaint() is more effective if you call it on the innermost enclosing component (i.e. using public void repaint(int x, int y, int width, int height) rather than using public void repaint()).

Q2: when should they be called?

Invalidate(): marks a component as not valid -- that means, it's layout is or may not be "up to date" anymore: i.e. the component is resized, a border is added, it's font changes, etc. you should never need to call invalidate() by hand, as swing does that for you on pretty much for every property change.

When more than one region within the control needs repainting, Invalidate will cause the entire window to be repainted in a single pass, avoiding flicker caused by redundant repaints. There is no performance penalty for calling Invalidate multiple times before the control is actually repainted.

Repaint() : If the component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.

Also have look at Update method.

NOTE: Swing processes "repaint" requests in a slightly different way from the AWT, although the final result for the application programmer is essentially the same -- paint() is invoked.

Refer to the link below for an excellent link on how painting is done in AWT and Swing:

http://www.oracle.com/technetwork/java/painting-140037.html

Hope this will help.

Validate or repaint for this case?

You create a new JPanel in the ActionListener's actionPerformed method but add it to nothing, in particular you add it to no container whose container hierarchy leads to a top-level window (here your JFrame), so changes to it will not be reflected in the GUI.

I suspect that you are under the fallacy that if you have a variable refer to a new object and change the new object's state, here panConf, that you will somehow change the state of the original object that the variable previously referred to, but that's not how Java works. The original JPanel that panConf refered to at the program start still exists and still sits in the GUI unchanged. The key to this is that you must understand the difference between a reference variable and an object (or reference). This is a key Java concept that might take some effort to fully get, but is worth the effort.

Instead simply remove the components held by the original panConf JPanel:

  btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do not create a new JPanel here
panConf.removeAll();
panConf.revalidate();
panConf.repaint();
}
});

Or better still, use a CardLayout to swap views.

Also, there's no need to use SwingUtilities.invokeLater and a Runnable queue this on the EDT. The code is already being called on the event thread.

JComponent's paint(Graphics g) method is being called by validate(), revalidate(), or paint()?

  1. You never load the image, so your paint method is going to throw a NullPointerException
  2. Graphics#drawImage(Image, int, int, ImageObserver) refers to the position the image should be painted, not it's size (strangely, your scale algorithm is return 0x0, but I didn't spend much time looking into it)
  3. In this context, you should be passing this to the last parameter of Graphics#drawImage
  4. It is recommended that custom painting be done within the context of the paintComponent method and not the paint method. See Performing Custom Painting for more details

nb- I also tried adding the pane to a full screen window without issues. I even introduced a small delay between the frame becoming visible and adding the pane and had it work - after I corrected for the NullPointerException.

Try removing the full screen requirement while you test it...

JPanel not updating when using invalidate, validate and repaint

So, based on your example, lookReply creates a NEW JPanel, but you don't do anything with it. So the component is never added to the screen, so all attempts to make it refresh will have no effect...

Revalidate and repaint - Java 6

As a workaround you could do

invalidate();
validate();

This approximates to what is occurring in revalidate without RootPane recursion.

Another option is to invoke pack if the window size has not changed.

Although upgrading to Java 7 would be simpler

Java/AWT/Swing: about validation and sizes

I am afraid you are in a wrong track.

Use Stewart's answer and set a null layout manager. That allows you to set the position of all components by calling setBounds().

Then, add a listener on the window which is called whenever the window is resized, and recalculate the positions and call setBounds().

This all can be automated if you implement your positioning code as a layoutmanager. (After all, positioning the components at resize == layout management, so believe or not, you are developing a layout manager, it is this simple!)

public class MyLayout implements LayoutManager,LayoutManager2 {

@Override
public void addLayoutComponent(Component comp, Object constraints) {
// TODO Auto-generated method stub

}

@Override
public Dimension maximumLayoutSize(Container target) {
// TODO Auto-generated method stub
return null;
}

@Override
public float getLayoutAlignmentX(Container target) {
// TODO Auto-generated method stub
return 0;
}

@Override
public float getLayoutAlignmentY(Container target) {
// TODO Auto-generated method stub
return 0;
}

@Override
public void invalidateLayout(Container target) {
// TODO Auto-generated method stub

}

@Override
public void addLayoutComponent(String name, Component comp) {
// TODO Auto-generated method stub

}

@Override
public void removeLayoutComponent(Component comp) {
// TODO Auto-generated method stub

}

@Override
public Dimension preferredLayoutSize(Container parent) {
// TODO Auto-generated method stub
return null;
}

@Override
public Dimension minimumLayoutSize(Container parent) {
// TODO Auto-generated method stub
return null;
}

@Override
public void layoutContainer(Container parent) {
// Now call setBounds of your components here
}

}

In the layoutContainer method, you can call the setBounds of all the components. This method is called when the window is laid out initially, as well as every time when there is a resize.

Then, when you e.g. put things to a window or to a JPanel, simply setLayoutManager(new MyLayoutManager()) and you're golden.

However, a very crude question still remains. Your layout manager is a separate class, but still it has to access to the components you're created elsewhere in your window code. The brute-force solution is to simply get a reference to all components in the constructor, e.g.:

class MyWindow extends JFrame {
public MyWindow() {
JLabel label=new JLabel("Hello");
JButton button=new JButton("Ok");

setLayoutManager(new MyLayoutManager(label,button)); // PASS THEM
add(label);
add(button);
pack();
setVisible(true);
}
}

Of course, it is a naive approach, but could work. The proper way for handling this is to implement the addLayoutComponent in your layout manager, which is getting called whenever you add anything to a JFrame (such as when calling add(label)). This way the layout manager is aware of the components in the layout.



Related Topics



Leave a reply



Submit