I'm having a serious performance issue using a JLayer to do special drawing, but only under the AquaLookAndFeel on Macintosh. Using any other look and feel, the performance is fine.
Here's the scoop:
I have a test case that blurs the main window when a child dialog pops up above it. On most L&Fs it works fine. On Aqua, it takes five seconds to draw, and the screen is frozen the whole time. I can press OK to dismiss the dialog, but it doesn't respond until it's done drawing. And the reason it takes so long to draw is because Aqua is firing multiple paint events. For every component that might change its visual state, it fires a paint event. So it redraws the entire window, using the blur effect, once for each of the twelve JButtons or Checkboxes in the window. The blur effect takes about one third of a second to draw, but it takes about 5 seconds with all the repaints.
Under any other look and feel, only two paint events are fired, so the performance is acceptable.
To see this in action, run the test case at https://github.com/SwingGuy1024/Bugs/blob/main/AquaPaintBug.java
It lets you try it under different looks-and-feels. It runs fine on all but Aqua.
Has anyone else seen this? Does anyone know of a workaround? Is this a bug in Aqua, or am I missing something? If I can't use JLayer to enhance the drawing of a component, the JLayer is useless for drawing.
Note: I think this is partly caused by a PropertyChangeListener that gets set by the AquaRootPaneUI class, on a property called AquaFocusHandler.FRAME_ACTIVE_PROPERTY, which is defined as "Frame.active". This seems to get activated when the window's active state changes, which is what happens when a dialog opens up. This explains why it repaints all the JCheckBoxes, but doesn't explain why they each get a separate paint event.
Related
How do I get the mouse position. I have tried:
int mouseX = MouseInfo.getPointerInfo().getLocation().x;
int mouseY = MouseInfo.getPointerInfo().getLocation().y;
But that does it for the whole screen. Anyway to do it relative to the JPanel/JFrame
If I'm only using Graphics JFrame and JPanel that is being repainted every millisecond, should I have buffers? Or will it be fine?
How do I add a mouseAcionEvent only to the frame so it gets X() and Y() of mouse but only in frame?
Use a MouseListener instead of MouseInfo. MouseListener will trigger events which are contextual to the component which raised them, which means you won't need to translate the events into the component space as the event will already be converted to within the component context.
See How to write a mouse listener for more details
How should I update my game rePaint() every millisecond or another way?
Use a javax.swing.Timer...
See How to use Swing Timers for more details...
Should I use buffers?
That will depend. Swing components are already double buffered, but if you use a more complex timing mechanism (AKA game loop), you might find it useful, even to roll your own.
I, personally, would start simple
How can I improve the way I thought out my code in the first place? Is it right having 10 loops or only all in 1 to reduce lag ect.
There are probably lots of things, but start with broader idea...
Breakdown entities to their own responsibilities, for example, the player should know where it is and how it should be painted. It could even know how it's suppose to move based on the current state of the game. This way you could create any number of entities, all with there own set of rules which are isolated and easily updated.
Devise a controller mechanism which is responsible for taking in keyboard and mouse events and simply updating the current state of the game model. That is, rather than going "the user pressed the 'left' key, move player to the left", it would simply raise a flag in the game model that the "left" state has been triggered (or untriggered) and the engine would, on the next update loop, ensure that each entity knew about the change
Don't use magic or hard coded numbers, instead provide some kind of ability to scale the scene. For example, you could decide what is shown on the screen based on the size of the window...
I am trying to develop an application in Java (Swing) that lets me overlay a grid on the screen, and be able to click things behind the grid -- say, an icon the desktop for example.
Would I approach this problem with a Transparent JFrame or a Transparent JWindow?
Whatever I use, the transparent window/frame needs to
always be on top.
occupy the entire screen.
register every click with a mouse listener.
record the coordinates of the clicks on the screen.
allow me to use the Graphics class to draw a grid on the screen, and other elements, like numbers or images, that should also be click through.
Any direction would be appreciated.
Apologize if I haven't been specific enough, but I haven't found a demo window or frame that can do all these things. There's an example here and another here -- but I don't know how to use WindowUtils in Eclipse. This is my first time in GUI development and I've never used external libraries aside from the base Java classes.
on top: Frame.setAlwaysOnTop() should work for you
full screen: Setting the window size to the display size will make it occupy the entire screen
events and overlay painting: The actual behavior may vary by platform, but typically if you're using an alpha component to draw into your window, and your window is nominally transparent, those areas not painted (or sometimes those painted below a certain alpha threshold) will pass events through to whatever applications, windows, or components are underneath.
If you capture events, you then have to re-introduce them to whatever window is below yours, which is non-trivial. If you don't capture events, you need to install an OS-specific event handler to capture events of interest.
JNA's WindowUtils.setWindowTransparent() should provide the paint/event behavior required, or you can use the AWTUtils equivalent provided in more recent JVM releases.
I am currently programming a gui with JavaFX 2.0, which is resizable. When the user resizes the window, a big rectangle resizes with it. Now I need to push the new boundaries of this rectangle on to an image which floats inside the rectangle and may not cross its borders.
I thought of updating the boundaries via a ChangeListener, but I don't want it to update the boundaries that often. The perfect solution would be a "ChangeIsOverListener" which updates the boundaries once at the end of a change.
Can anybody help me out?
Thanks in advance! :)
You may be able to trap mouse-down and mouse-up events on either side of the window resizing - but whether you see those events will depend on the AWT system and may depend on the O/S too.
Otherwise you will have to use a timer within the window sizing event to trip a separate event some number of ms after the last window sizing event, such that you consider the size to be "done" if it hasn't be changed in the last, say, 1/2 a second. The amount of time will be a compromise between the user's perceived lag and the number of resizes you want to process.
Maybe you could compare the size of the window every x milliseconds, and when it doesn't change in this time interval, you know that the change is over.
This program will have an infinite canvas (ie as long as the user scrolls, it becomes bigger) with a tiled background image, and you can drag and drop blocks and draw arrows between blocks. Obviously I won't use a layout manager for placing blocks and lines, since they will be absolutely positioned (any link on this, possibily with a snapping feature?). The problem arises with blocks and lines. Basically I'll have two options:
Using a simple layout for each building block. This is the simplest and clearest approach, but does it scale well when you have hundreds of objects? This may not be uncommon, just imagine a database with 50 tables and dozens of relationships
Drawing everything with primitives (rectangles, bitmaps, etc). This seems too complicated (especially things like text padding and alignment) but may be more scalable if you have a large number of objects. Also there won't be any event handler
Please give me some hints based on your experience. I have never drawn with Java before - well I did something rather basic with PHP and on Android. Here is a simple preview
DISCLAIMER
You are not forced to answer this. I am looking for someone who did something like this before, what's the use of writing I can check an open source project? Do you know how difficult it is to understand someone else's code? I'm talking about implementations details here... Moreover, there is no guarantee that he's right. This project is just for study and will be funny, I don't want to sell it or anything and I don't need your authorization to start it.
Measuring and drawing text isn't such a pain, since java has built in classes for doing that. you may want to take a look at the 2D Text Tutorial for more information. In fact, I did some text drawing computations with a different graphics engine which is much more primitive, and in the end it was rather easy (at least for the single-line drawing, for going multiline see the previous link).
For the infinite canvas problem, that's also something I always wanted to be able to do. A quick search here at stackoverflow gives this which sounds nice, althought I'm not sure I like it. What you can do, is use the way GIMP has a scroll area that can extend as you move - catch the click of the middle mouse button for marking the initial intention to move the viewport. Then, when the mouse is dragged (while the button is clicked) move the viewport of the jscrollpane by the offset between the initial click and the current position. If we moved outside the bounds of the canvas, then you should simply enlarge the canvas.
In case you are still afraid of some of the manual drawing, you can actually have a JPanel as your canvas, with a fixed layout. Then you can override it's paint method for drawing the connectors, while having child components (such as buttongs and text areas) for other interaction (and each component may override it's own paint method in case it wants to have a custom-painted rect).
In my last drawing test in java, I made an application for drawing bezier curves (which are basically curves made of several control points). It was a JPanel with overidden paint method that drew the curve itself, and buttons with custom painting placed on the location of the control points. Clicking on the control point actually was clicking on a button, so it was easy to detect the matching control point (since each button had one control point associated with it). This is bad in terms of efficiency (manual hit detection may be faster) but it was easy in terms of programming.
Anyway, This idea can be extended by having one child JPanel for each class rectangle - this will provide easy click detection and custom painting, while the parent will draw the connectors.
So in short - go for nested JPanels with custom drawing, so that you can also place "on-canvas" widgets (and use real swing widgets such as text labels to do some ready drawing) while also having custom drawing (by overriding the paint method of the panels). Note that the con of this method is that some swing look-and-feel's may interfere with your drawing, so may need to mess a bit with that (as far as I remember, the metal and nimbus look-and-feel's were ok, and they are both cross-platform).
How should I run animation in a Swing applet?
I have an animation thread performing active rendering and it initially animates fine. Sometimes (anywhere from 1 minute to 2 hours later) it begins to fail to update the screen and only the sounds occur. I believe this is due to the fact that the paint is not performed from the EDT causing some kind of concurrency problem.
So, should the active rendering (ie getGraphics() and painting) be called only from the EDT? A problem with this is the Swing timer lacks precision.
Or has anyone had success with active rendering without using the EDT, and completely disabling any EDT updates to the page (maybe using Canvas / or ignore repaint on a JPanel)?
You can paint graphics into your own off-screen image in another thread and copy to the screen in the EDT. But for single threaded stuff, I would hope your frame rate is high enough to be able to do it in the EDT.
A few things to look at would be to make sure you are only repainting what needs to be repainted and not the whole graphics context each time unless necessary. Also there is a timing framework that you can use to handle some animations. I don't think it is actively being developed but last time I looked at it it had some nice api's to use for animation.
Without knowing your specific use case this is all I could come up w/ off the top of my head.