java Swing using JFrame.pack() repeatedly - how efficient is it? - java

In short I was wondering, if I call JFrame.pack() on a frame that is already sized, will it take a long time to analyse this or will it simply return immediately? I ask for efficiency reasons. There is a picture in my frame that is being updated many times a second within a loop. Now JFrame.pack() has to be called after at least the first picture is drawn to insure that the frame is the right size.
To handle this what I have (in pseudo code) is:
boolean flag = false
while (condition) {
getNextPicture();
updateFrameWithPicture()
if (!flag) {
frame.pack()
flag = true;
}
}
Now I was wondering if there would be a problem if I just left out the check for the flag and always called frame.pack(). Could the program decide fast enough if the frame is already the correct size?

Tricky to estimate differences in performance as I am displaying images received on an RTP socket.
You are micro optimizing your code. Getting external data through a socket will always be slower than repainting a frame.
I am actually using a swing timer
You should NOT use the Timer to do the actual reading of the image on the socket. The GUI will block while the image is being read. You should be using a separate Thread to read the image. It will probably be better for you to use a SwingWorker and then publish() the images as they become available. Read the section from the Swing tutorial on Concurrency for more information.
just thought it would be easier to describe my question in terms of a while loop.
No, it is better to give the actual code as you can see your current code is incorrect. Don't make use guess what you are doing.

Related

Java Splitting Up Work Between Frames

First I'll explain what I want to do and afterwords I'll provide a proposed solution.
Problem
I'm running a game where I want to do a certain amount of work every frame. For example, I have N objects that are in a queue waiting to be initialized (imagine initialization is a fairly expensive operation and N is large) and after adding them all, I want to create their collision boxes, and after that, I want to merge them together to limit render calls. I can't do these operations on a different thread because all this stuff is heavily coupled with the game world. But I want to split up all these operations into bite-size chunks to run each frame so that there is minimal lag (framerate dips). How would I go about doing this?
Proposed Solution
It would be nice to have a function that can stop after one call and continue where it left off after calling it again:
For example,
boolean loadEverything() {
for (int i = 0; i < objectsToAdd.length; i++) {
world.add(objectsToAdd[i]);
if (i % 10 == 0) {
return stop();
}
}
makeCollision();
return stop();
mergeObjects();
return true;
}
Calling loadEverything() the first objectsToAdd/10 times adds 10 objects to the game world at a time. Then calling it after should run makeCollision() and then stop. Calling it again runs mergeObjects() and then the function returns true. In the caller function I would run loadEverything() until it returns true.
I'm aware of yeild-return, yield-break implementations like those described here exist, but I'm wondering if there's a more general implementation of them, or that maybe a better solution exists that doesn't require any extra dependencies.
Do you look at Coroutine yet? There's native implementation in Kotlin but in Java there're options here and here.
By all means we need to make sure those OpenGL or Box2D operations that required to be in main thread should be in main thread, as I believe coroutine will be created under a new thread. So there might not be gain to split works for those kind of operations.
Another option
You say you need to split works in creating objects in run time. Can you predict or estimate the number of objects you would want before hand? and so if you don't really need to dynamically create object like that, I suggest to look at Object Pool in libgdx (see more here). That link has working example to use Pool in your game.
Such Pool already have initialized objects ready to be grabbed and used on-demand, also can grow if need in run time, so initially if you can provide a good estimation of number of objects you intend to use, it's all good.
Why don't you add one static variable which would keep it's value between function calls? Then you can loop from current value to current value + 10, increase current value (that static variable) by 10 and exit.

Codenameone: "Warning paint queue size exceeded, please watch the amount of repaint calls"

I am getting continuous warning while using below code.
TextArea txtLabel = new TextArea(labeltext);
txtLabel.setUIID("login_title");
txtLabel.setEditable(false);
txtLabel.setRows(2);
txtLabel.setGrowLimit(2);
txtLabel.setScrollVisible(false);
txtLabel.setGrowByContent(false);
Warnings get rids while using below code.
SpanLabel txtLabel = new SpanLabel(labeltext);
txtLabel.setUIID("login_title");
txtLabel.setScrollVisible(false);
I don't understand why TextArea cause Warning "paint queue size exceeded, please watch the amount of repaint calls"
I have used TextArea because i want multi line label with two rows.
Those warnings happen when there are too many repaint() calls in the queue. The major difference between these two calls is the default value for the columns property but I don't think that's the reason for the warning. It's just the thing that finally causes it to tip over the threshold.
You probably have an overly elaborate theme that takes too long to paint (gradients?) and a lot of components within a very elaborate hierarchy that makes it harder to eliminate paint calls. I suggest you review your design within the performance monitor tool and see what can be improved and what is really happening in terms of paint. See this developer guide section:
https://www.codenameone.com/manual/performance-debugging.html

Displaying information from multiple threads in a single JFrame

I start several(threads) instances of a java class that receives an "input" and based on that generates an "output" on out it out on the standard output(screen). I would like to add an option that would enable me to send this output to a single JFrame (text area). What is the best way of doing this? Up to this point my program was totally GUIless but I would like to make it a bit more GUI friendly and add this option.
The challenge is that at any given point I could have several threads running. Any design or code snippets would be greatly appreciated.
As MadProgrammer points out, a nice, encapsulated way of doing this is SwingWorker.
That said, here is the general theory:
All updates to Swing components must be done on the Swing event dispatch thread (there are some exceptions, but not relevant here). This is achieved by SwingUtilities.invokeLater() (and occasionally invokeAndWait() ).
The Swing runtime will then queue up the changes you want to make and call them one at a time. This makes the entire problem of updating your text area pretty trivial: just create a Runnable with the text you want to append, pass that to invokeLater(), and have your Runnable grab the document model of the text area and append your desired text to it.
SwingWorker can encapsulate some of the complexities of background thread management, but I encourage you to do it the 'hard way' a time or two (and your use-case is actually easier to do the 'hard way'). That way you can appreciate what SwingWorker does for you when you do need it.
You need not to convert your existing threads to SwingWorkers. Just let them from time to time send messages to JFrame in a way like this:
EventQueue.invokeLater(new Runnable(){
// update GUI
});
To avoid boilerplate code, it is good to wrap programming interface to the screen with a java.lang.reflect.Proxy. An example of such wrapping is at SwingProxyActorTest.java.

Updating scenes in advance while still rendering previous frame

I'm currently working on a multi-threading safe rendering system and I would like to know your thoughts on how to correctly update the next step in the game world while the previous scene is currently rendering. Currently I am using LWJGL Opengl Bindings with Java. Here is pseudocode for my game loop as it is currently set up (which is probably just a basic loop that most people are familiar with):
//DrawingLayers are wrappers for in game entities and has an update
//and render method
game-loop:
addInputEventsToInputStack()
removeCompletedDrawingLayers()
foreach layer in DrawingLayerQueue :
layer.update(deltaTime) //update position/color/size for entity
layer.render() //performs OpenGL calls
if(layer.isCompleted):
addToCompletedDrawingLayersList()
swapBuffers() //blocks until scene is fully rendered
goto game-loop
My problem lies in the swapBuffers() method as it blocks until the scene is rendered which means I cannot perform any updates while that is going on. My thought on how to get around this is to:
Have a copy of all DrawingLayers that I use for updating the state of the entities and have the other copy as a reference for the rendering thread. And while a frame is rendering, kick off a thread just before swapBuffers() to update the copy that is not in use.
I'm wary of this approach as I believe creating the copies before every frame would slow the system down more than I would like.
Does my approach make sense, and if not, do you guys have any recommendations for how to do this? I'm open to a complete restructuring.
Updated: Based on datenwolf's suggestion I've changed my gameloop to the following:
//DrawingLayers are wrappers for in game entities and has an update
//and render method
//A future for the pre-processing task
Future preProcess = null
game-loop:
//Update: checks if we have a preprocessed update to wait for
//and waits for it to complete
if(preProcess != null):
preProcess.get()
preProcess = null
addInputEventsToInputStack()
removeCompletedDrawingLayers()
foreach layer in DrawingLayerQueue :
layer.render() //performs OpenGL calls
if(layer.isCompleted):
addToCompletedDrawingLayersList()
//UPDATE: the following just calls all the update methods for the layers
// in a new thread
preProcess = executorService.submit(new UpdateRunnable())
swapBuffers() //blocks until scene is fully rendered
goto game-loop
So far with this I've got a significant improvement in performance. There may be some race condition issues that I cant see, but overall Im happy with this improvement.
in the swapBuffers() method as it blocks until the scene is rendered
The blocking of the buffer swap is only partial by finishing the rendering. It usually also blocks due to wait for the retrace. However OpenGL guarantees you, that after any drawing command returns, the buffers accessed by it can be safely modified without any pending rendering operations being impaired. The implementation is required to make copies or copy-on-write mappings to all data.
Or in short terms: Just modify the data in the buffers. As soon as drawing calls (glDrawArrays, glDrawElements) return it's safe to do so.

Design question about Swing GUI updates via PropertyChangeSupport

In the past I have used PCS to update Swing elements that displayed certain fields and everything worked as expected. However, I am now facing a relatively complex (in other words, terribly designed) UI that displays a lot of fields. Data updates come in bunches (a network packet containing new values for about 1,000 fields), and I was wondering what the proper way to handle something like this is.
My main concern is that whenever a data packet comes, 1,000 PropertyChangeEvents are triggered, causing 1,000 .repaint()'s (or .revalidate()'s or whatever). The more prudent way seemed to do something like "gui.stopRepainting(); fireAllThePropertyEvents(); gui.restartPainting();". Is there a way to do that, or is there maybe a better way to handle this ?
A repaint request is passed to the RepaintManager which in turn combines multiple requests into a single repaint.
I find it strange that you have 1000, fields of a single form. Assuming this in fact true then I doubt all 1000 will be visible at the same time. I believe the RepaintManager will only paint those that are visible so the overhead may not be as bad as you think.
I don't know of any way to stop the repaint, but maybe you could make the pane invisble, do the updates and then make it visible again.
Or maybe you can create a custom RepaintManager the does nothing. You instal it, do your updates and then reinstal the default manager.

Categories