Listeners and validation/repainting - java

So I have this problem. I have a program that creates and load files.
When I load a file into my program, I rely on a component listener that tells me when is the specific component "full", and then moves all of the components according to that.
I add each component on the top, and then listener register when parent component is "filled" and moves the bottom compoennt to a new parent it also creates. Think of it as adding a new line of text to the begining of a houndred page MSWord document.
That listener also relys on the GUI setup - if everything in memory is not painted to the screen, it grabs wrong component heights (usually being 0) and uses them in it's calculations which then come out wrong, and everything gets messed up.
Here is a flow chart of that part of my program:
(everytning happens on a JPanel in a JFrame)
trigger opening method:
{
repeat this x (lets say e.g. 100) times:
{
trigger addComponent method
{
add component
{
adding component triggers the component listner 8if there is no more room in parent)
{
move all of the components one place down, move the ones out of bounds to next "page"
repaint and revalidate whole JFrame (inside listener)
}
}
repaint and revalidate whole JFrame (part of addComponent method)
}
repaint and revalidate whole JFrame(part of opening methid, after component addition)
}
repaint and revalidate whole JFrame (as a part of opening method, final repaint/validate)
}
The reason for this may repaint/validate is that addComponent method, as well as the listener has other functions and is called in other places where that is the only (optimal) place for repainting/validating.
The problem is that JFrame doesn't get repainted until the very last(final) validate/repaint call in opeoning method. I tried adding Thread.sleep(1000) to several places in the code (after validate/repaint) to proved this.
Also, as far a I know, when a component listener is triggered, it stops at the line which triggerd it, then executes itself, and then continues from that line, right?
How do I fix this? How do I force my program to repaint/validate after each new component was added ant then again after the listener did it's job?
Reply to the first two comments:
Firstly, Thread.sleep(1000) was just to diagnose the problem. Right before Thread.sleep(1000) method was repaint/validate method, so I thought if I pause the program right after reapint() was called, after every pause, GUI would be repainted ad I would see new element added, which was not the case.
Secondly, regarding to the lengthy calculations, those calculations aren't that long (executing this with 20 components gets momentary results, though not ones that are desired). Also, that calculations require removing and adding components to the GUI quite often (every 10-20 lines), so Incorporating SwingWorker in that is close to impossible, and not needed.
Thirdly, I think you missed the whole point. Length of execution is not the real problem here, nor the freezing of the GUI (whic doesn't really occurr, not long enough to be noticable, anyway). The problem is that repaint/validate was called in the loop for total of 3-4 times for every component (cca. 60-80 times if I open a file with 20 components), and the only time I saw it being executed is when the last time it was called, after the loop...
I even put System.out.println("something") method right before and right after the repaint/validate. It printed out "something" twice, but repaint/validate never happened.

I can see any issue with add / remove / modify JComponents in the container (JFrame --> JPanel e.i.)
depends if container (JPanel e.i.) is placed in JScrollPane
depends if you need to call pack() after add / remove / modify JComponents in the container, and then to change size of JFrame (for example) on the screen

Related

Refreshing a JFrame

I have done some digging around on this, however, I still can't seem to figure it out. Please excuse me, I haven't been programming for long.
Background: When I click on my run button it should create a second JFrame and update the background colours of JPanels on the second frame, periodically, once per iteration, throughout the run that the JButton starts.
Problem: The second frame is created, but stays blank until the loop, started by the JButton is finished, and it only displays the final state.
I have tried: invalidate(), validate(), repaint(), setVisible(true).
I have tried to run it in a separate thread.
I have even tried sleep(), in case it doesn't have enough time to update. Is there something else that I can try?
I think I would have overwritten the void paint(Graphics g) method which is called by the OS when redrawing is needed and add your drawing routine there. Don't forget the super.paint(g) call. You can then manually trigger redrawing (from inside your loop) by a call to void update (Graphics g); (calling void repaint() should work too)
The second frame is created, but stays blank until the loop, started by the JButton is finished, and it only displays the final state
If your ActionListener attached to the JButton (or the Action) is implemented like
public void actionPerformed( ActionEvent e ){
updateColor();
...
updateColor();
...
updateColor();
}
then the behavior you are seeing is exactly as expected.
Swing is a single threaded framework. When your ActionListener updates the background color, a repaint will be scheduled (emphasis on schedule, which is something different from performed). Since your loop in the ActionListener is still occupying the single thread (the EDT), the repaint cannot be executed.
As such, the first time the repaint can be executed is after you have released the EDT by finishing your loop. At that moment, the background color has already changed to its final color, and that is all what you will be seeing.
A possible solution to be able to see the background change is to use a javax.swing.Timer (and not the java.util version). A click on the JButton can start the timer, and each time the timer is triggered you change the background color to the next color. The moment the final color is reached, you stop the timer.

What's the difference between setVisible(true), repaint() and validate()?

I create a little program that load a frame in which I added some panels.
When I click on some button it should show some panels and hide other.
I'm experiencing some difficult to do it, even because I don't really figure out the diference between setVisible(true), repaint() and validate() (that some friends of mine suggested to me).
I hope you can make me to understand!
Thank you.
Carefully read the API for JComponent. The usages are:
setVisible - it will hide or show your component altogether. If you set it as false, you won't see it at all.
repaint() - is called when the actual pixels need to be redrawn, this is done automatically. It's used, for example, when you move a window on top of your GUI and then move it away. The part that was covered needs to be redrawn.
validate() - you should call this when the layout of your GUI has changed and you need the manager to replace and redraw your GUI.
It's a bit more complicated than that, so again, carefully read the API.
setVisible(true): sets the component so that it's visible.
repaint(): calls the paint method on the component.
revalidate(): updates the component based on the root component

Implications of setVisible() method in Swing

I'm writing a program that uses a few components in a GUI. However, I don't need all of them showing at the same time. In addition, depending on the user's input, there may be times once a component is not in use anymore, that it may or may not be needed again.
So far I have simply just invoked setVisible(false) for each component that I do want to show on the screen. If they are needed again, i simply make them visible.
My question is this. Does setting a component's visibility to false have major implications on performance of a program (generally speaking)? Does the paintComponent method paint a component that is not visible and then just does not show it, or does it ignore it all together?
Also, is it better to just to remove the component from a container instead?
If it is not visible it not being drawn. Lets say I made a button and then made it so it prints "Hello" when I press it. If the button setVisible() is false I won't be able to click on it, its not their.

When exactly are components realized in Swing

I'm developing an application, in which all UI components are defined via an XML file. I read the xml and depeding on it the UI is composed. After the user made some changes a new XML is provided and the UI is refreshed accordingly. Now I get some really annoying rendering issues, especially with several scroll areas, where either parts of the UI are cut of (and only get visible, when I resize the window) or the scrollbar is alread scrolled to some point, but it should just show the top of the content.
I assume this is an Event Dispatch Thread issue and found some really useful info about it here: http://www.javapractices.com/topic/TopicAction.do?Id=153
You can read there:"This thread (the EDT) becomes active after a component becomes realized : either pack, show, or setVisible(true) has been called"
Parsing the XML is not done in the EDT and also instantiating the components and adding them to their parent panels. Only after all components are created they are finally added to the MainPane via the EDT.
However is seems in some cases creating components and adding them to panels, already starts the EDT. So things get messed up.
Does someone have detailed knowledge which methods call pack, show, or setVisible(true) and therefore start the EDT?
Thanks a lot
I had the same issues with scroll panes, try setting the following property on them:
scrollpane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
As in the comments, all Swing components must be created on the EDT or your going to get weird stuff happening.

Get notified when the user finishes resizing a JFrame

I have a fractal generation component (a subclass of JPanel) inside a JFrame. When the user resizes the window, it takes quite a while to update the fractal to the new size.
I currently have a ComponentListener on the JPanel, but its componentResized event is called every time the user moves the mouse while dragging the window border. This means that the fractal is told to resize many times, and slowly (over the course of a few minutes) grows to the new size.
Is there a way to be notified when the user releases the mouse button, so that I can only change the fractal size when the user has finished resizing?
Others have reported this happening when the listener is attached to the JFrame instead, but this doesn't work for me (and others), for some reason.
Instead of starting the calculation each time you receive a receive-event, you can only start the calculation after you received the last event by using a timer, e.g. in pseudo-code (or at least code which I typed here directly and not in my IDE)
private Timer recalculateTimer = new Timer( 20, myRecalculateActionListener );
constructor(){
recalculateTimer.setRepeats( false );
}
#Override
public void componentResized(ComponentEvent e){
if ( recalculateTimer.isRunning() ){
recalculateTimer.restart();
} else {
recalculateTimer.start();
}
}
And you can still combine this with Andrews suggestion to use an image which you stretch until the calculation has actually finished.
you have look at HierarchyListener, where you can listening for HierarchyEvent with interface to HierarchyBoundsListener
basically nothing wrong with ComponentListener, but you have to wrapping expected events to the Swing Timer, in the case that events repeated, only to call Timer#restart(), output from Swing Timer should be Swing Action
It's a bit late, but it looks like no one found the correct answer. I found that when you call child.updateUI() inside a ComponentListener (componentResized block) of a window, this child resizes it self and updates its content. Using timers is unsafe.

Categories