Skip to main content

What is the secret to drawing zoomed Swing components?

6 replies [Last post]
robross
Offline
Joined: 2003-06-13

Cross posted here: http://forums.java.net/jive/thread.jspa?threadID=45585

please direct any responses to the above thread.

---------------------------------------------------------------------

I have read this thread:

http://forums.java.net/jive/thread.jspa?threadID=45350&tstart=0

and it's very close to the subject matter I am currently researching. But I wanted to ask a higher level question.

I thought all Swing components had a UI delegate that drew the component using Java2D calls. I have traced the paint() code in Component and JComponent, and they look like they are passing around the same Graphics object on which paint() was originally called. The only modification seems to be if Debug Graphics are being used, it substitutes one of those for the Graphics object.

So why is it if I override paint() in my container subclass (say a JPanel subclass), and then scale the Graphics object, then call super.paint(), why is it that Swing doesn't seem to work the way I would expect it to? I.e., when drawing, it's not really "doing the right thing" with the scaled Graphics instance it is passed.

As the other thread pointed out, if I add JComponents to my JPanel subclass, when they first appear they are indeed drawn at the scaled size. But then, moving the mouse over the JPanel, or triggering a repaint, causes the Swing component to be drawn again in its original, non-scaled size, while I also still have pixels on screen that represent the scaled JComponents but are just a drawing - I cannot interact with them via the mouse or keyboard.

What is Swing doing that makes this simple scaling call not work? And what is the secret ingredient that makes something like JXTransformer work correctly? (Nearly correctly anyway, I'm still seeing an issue on Mac OS X with the TextJXTransFormer demo (from the above link) where the border of the focused JButton isn't drawn completely around the button, the right-side of the border is not being painted.)

Rob

Cross posted here: http://forums.java.net/jive/thread.jspa?threadID=45585

please direct any responses to the above thread.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
swv
Offline
Joined: 2007-05-28

because the visual part of the JComponent has been changed (through modifying the paint method) but the actual size of the component hasn't i.e. (getSize())...

If you directly override paint, things probably get funk-a-delic in one-off ways and the causes of all that funk are probably not worth running down (definitely not worth it).

robross
Offline
Joined: 2003-06-13

Ah, well that is a good reason that explains the lack of input handling. It does not explain why the JComponents are drawn twice, once in the zoomed state, and then again in normal size.

Also, as I mentioned, I am only overriding paint() so that I can set a transform on the Graphics in order to scale it. I do want the component, and its children, drawn to the same scale, so this is the only way I can think of to accomplish this. I only override paint to set the scale factor, then call super.paint().

swv
Offline
Joined: 2007-05-28

there's OS code out there that does this. I have something that does this, but I am drawing primitives directly to the screen.

Drawing twice is just a (regular ) problem with your code, I'll bet.

A lot of the painting in LAF incorporates ImageIcons , and whatever you do, those II are not going to scale.. they get sucked up and created in BufferedImages .. to see the problem, just think about scaling a face, where you'd see things looking funny because you're especially sensitive to facial details. Images don't really scale (except SVG images).

But there are open source scaling things out there if you want to sneak a peak.

glenlamb
Offline
Joined: 2008-08-19

OK, so I could be totally wrong, and since no one else has picked up on this I guess I am, BUT, don't you also have to override the paintComponent() method, at least that's the one I always use when creating custom JComponents.

pietblok
Offline
Joined: 2003-07-17

Hi Rob,

I guess the problem is that a repaint request invoked on a component is carried out only on that component (and its children). Its parent container is unaware of it. Think of a JButton, it changes its appearance when a mouse moves over it.

Only when the repaint request is invoked on the container, then that container has the option to scale the graphics object.

In the thread that you mentioned this is, as I remember correctly, discussed with different wording.

So, for example, if you would use JXLayer for this effect, you would have to override the [code]eventDispatched(AWTEvent e, JXLayer l)[/code] method and, of course after invoking the super implementation, invoke [code]setDirty(true)[/code].

The problem of user interaction with the scaled down components remains. Events that are directed to them are based on the unscaled component coordinates.

For a moment I thought that I could solve it by trying to make a LayerUI that combines the effect of scaling down with that of a LockableUI. I hoped to be able to redirect all mouse events to the correct components. I succeeded in finding the correct component (by scaling up the coordinates), but failed to have those events processed on those components. Redispatching events seem to be very tricky.

Piet

glenlamb
Offline
Joined: 2008-08-19

AGH, of course, internall calls to paint() won't go through the superclass.

If you are overiding the eventDispached method couln't you solve the size clickable issue by simply double the size of the component after it's been drawn.

so in the Paint() method that has been overidden reduce the size of the component call super.paint() then resize it again, but have your event handler set up so that it wont then repaint at the new size?