Search |
||
hansmuller's BlogIntroducing the SceneGraph ProjectPosted by hansmuller on January 8, 2008 at 6:50 PM PST
Introducing SceneGraphI haven't written a blog entry since January when I advertised the fledgling Swing Application Framework (JSR-296) project with an uncharacteristically brief item. Work on that kept me busy until summer, when the Java FX juggernaut got underway here at Sun. Since then I've devoted much of my time to leading a project we've called "Scenario" that provides the graphical runtime for Java FX Script. We're now a public project on java.net called scenegraph.dev.java.net . You'll find downloads of the the 0.4.1 version of the Scenario source and binaries and (very) sketchy javadoc on the site. The 0.x version number is intended to convey the fact that the API hasn't stabilized yet. It's sufficient for experimentation and the implementation was robust enough to support a port of the Java FX Script interpreter, which we've showcased with a Scenario version of the FXPad Demo . Obviously, we don't recommend putting anything based on Scenario into production. Not yet. The code is being made available under the GPLv2 license. Passion about open source licenses is not something I possess so I'll leave the shouting about the implications of this choice to others. Suffice it to say that, per my limited understanding of these matters, you're free to share the code, and in the process of developing it further. We're moving our discussions of the API to the newly minted Scene Graph java.net forum . If you're interested in the project's evolution, that would be a good place to start looking. There are quite a few engineers working on Scenario, most of whom have made bigger contributions to the new software than I have, and you'll be hearing from them in their own blogs before too long. For now, what I'd like to do is to provide an introduction to the new Java APIs and just one demo. The team has written a whole raft of demos and we'll be opening up a subproject before too long, that contains the entire demo catalog. DemoAll of the examples that follow are part of a demo, each one occupies a tab. If you press "control-T" after clicking on a demo, you'll get a nice interactive tree view of the scene graph's structure, thanks to Amy Fowler for that! So press the orange button to launch the demo.
Note also: the demo scales the selected example scene to fit.
This is done with a small extension to Basics, Hello World
A scene graph, really a tree for now, is a data structure you
create from leaf nodes that represent visual elements
like 2D graphics and Swing components, filter nodes that
represent visual state, like 2D transforms and composition, and
group nodes that manage a list of children. All nodes
are subclasses of
SGText text = new SGText();
text.setText("Hello World");
JSGPanel panel = new JSGPanel();
panel.setScene(text);
panel.setPreferredSize(new Dimension(640, 480));
// create a JFrame, add the panel to it, etc..
One unusual line from the previous example, from a Swing
programmer's perspective, is that we've explicitly set the
preferred size of the
SGText text = new SGText();
text.setText("Hello World");
text.setFont(new Font("SansSerif", Font.PLAIN, 36));
text.setAntialiasingHint(RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
text.setFillPaint(Color.WHITE);
JSGPanel panel = new JSGPanel();
panel.setBackground(Color.BLACK);
panel.setScene(text);
panel.setPreferredSize(new Dimension(640, 480));
More Hello World: Groups and Shapes
Most of the Scenario classes are simple Java Beans. They provide null (no parameters) constructors and mutable properties. The API is intended to be "minimal" in the sense that it exposes the capabilities of the underlying Java 2D and Swing classes but does attempt to substantially simplify or abstract them. Scenario is intended to serve as the basis for higher level abstractions that require a scene graph, notably Java FX Script. For that reason, you may find programming against the Scenario API directly to be a bit tedious. Creating your own abstractions that simplify creating scene graphs is definitely the order of the day.
To add a border to the simple Hello World scene, we'll write a
method that takes any scene graph node and puts a garish rounded
rectangle border behind it. This example demonstrates using the
SGNode createBorder(SGNode node) {
Rectangle2D nodeR = node.getBounds();
double borderWidth = 10;
double x = nodeR.getX() - borderWidth;
double y = nodeR.getY() - borderWidth;
double w = nodeR.getWidth() + (2 * borderWidth);
double h = nodeR.getHeight() + (2 * borderWidth);
double a = 1.5 * borderWidth;
SGShape border = new SGShape();
border.setShape(new RoundRectangle2D.Double(x, y, w, h, a, a));
border.setFillPaint(new Color(0x660000));
border.setDrawPaint(new Color(0xFFFF33));
border.setDrawStroke(new BasicStroke(borderWidth / 2.0));
border.setMode(SGShape.Mode.STROKE_FILL);
border.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON);
SGGroup borderedNode = new SGGroup();
borderedNode.add(border);
borderedNode.add(node);
return borderedNode;
}
Adding a the border doesn't change the code that creates the scene graph very much:
SGText text = new SGText();
text.setText("Hello World");
// same as before ...
panel.setScene(createBorder(text));
Rotating Hello World: Transforms
As you can see in the previous example, the
To rotate a scene graph node around a point, you have to
assemble a chain of three transforms that: translate the node so
that the rotation point is at the origin, rotate the desired
amount, translate the node back to its original location.
Transforms are created with
SGTransform createRotation(SGNode node) {
Rectangle2D nodeR = node.getBounds();
double cx = nodeR.getCenterX();
double cy = nodeR.getCenterY();
SGTransform toOriginT = SGTransform.createTranslation(-cx, -cy, node);
SGTransform.Rotate rotateT = SGTransform.createRotation(0.0, toOriginT);
return SGTransform.createTranslation(cx, cy, rotateT);
}
To use the
SGTransform scene = createRotation(node);
SGTransform.Rotate rotateT = (SGTransform.Rotate)scene.getChild();
rotateT.setRotation(...);
Images and More Layout
Images can be incorporated in a scene graph with the
SGNode createRow(SGNode... nodes) {
double rowHeight = 0.0;
for(SGNode node : nodes) {
rowHeight = Math.max(rowHeight, node.getBounds().getHeight());
}
SGGroup row = new SGGroup();
double x = 0.0;
double gap = 8.0;
for(SGNode node : nodes) {
Rectangle2D nodeR = node.getBounds();
double y = (rowHeight - nodeR.getHeight()) / 2.0;
double dx = x - nodeR.getX();
double dy = y - nodeR.getY();
SGTransform xlate = SGTransform.createTranslation(dx, dy, node);
row.add(xlate);
x += nodeR.getWidth() + gap;
}
return row;
}
The code to create the SGImage node and the overall scene looks like this:
SGNode createEarth() {
BufferedImage image = null;
// ... code to load the image file
SGImage sgImage = new SGImage();
sgImage.setImage(image);
return sgImage;
}
// ...
SGNode row = createRow(createHelloWorldText(), createEarth());
SGNode scene = createBorder(row);
JSGPanel panel = new JSGPanel();
panel.setScene(scene);
Handling Input
All nodes can handle mouse and keyboard events and the support for
doing so is very similar to what AWT/Swing provides. For
example to make a node handle mouse events you add an
In this example, we've added a mouse listener to the
earth node in the scene from the previous example and restored
the support for rotating the scene. Dragging the earth with the
mouse rotates the scene. Here's the code that sets up the scene
and its
SGNode earth = createEarth();
SGNode row = createRow(createHelloWorldText(), earth);
SGTransform scene = createRotation(createBorder(row));
final SGTransform.Rotate rotateT = (SGTransform.Rotate)scene.getChild();
SGMouseListener changeRotation = new SGMouseAdapter() {
@Override public void mouseDragged(MouseEvent e, SGNode node) {
Rectangle2D r = e.getComponent().getBounds();
double x = e.getX() - r.getCenterX();
double y = e.getY() - r.getCenterY();
rotateT.setRotation(Math.atan2(y, x));
}
};
earth.addMouseListener(changeRotation);
JSGPanel panel = new JSGPanel();
panel.setScene(scene);
Although there's a great deal more to say by way of introducing Scenario, this blog entry has grown long enough that I'd better just take the same tack that Chet did , and declare this "Part 1". The code for the examples can be found here: http://weblogs.java.net/blog/hansmuller/archive/Intro.java A easy to build version will appear along with the other Scenario demos, later this month. »
Comments
Comments are listed in date ascending order (oldest first)
Submitted by throwable on Tue, 2008-01-29 10:02.
It is rather difficult to build and manipulate with scene graph using AffineTransform nodes. I think it may be simplified for example by integrating of SGNode with SGTransform allowing user to use simple bean methods like setX(), setY(), rotate(), scale(), etc... The main reason is that every "visual" node must be positioned inside scene and thus will always have corresponding translation node.
Submitted by hansmuller on Wed, 2008-01-09 11:18.
I've removed the alarming stack trace print that occurs when
MasterTimer can't read it's System properties. It was harmless
and unneccessary. I wish we had a better way to test sandboxed
applications.
Submitted by mikeazzi on Wed, 2008-01-09 12:26.
When I resize the frame I notice some lines flashing around the edges, giving it a not so smooth resizing feel. Otherwise it looks great. I am using Windows XP with Update N b08.
Submitted by diverson on Wed, 2008-01-09 14:37.
Thanks for the intro, Hans.
Regarding the rotation example: if the rotation were static (or will be rendered many more times than it will be changed) then optimally you would want to concatenate the three transforms into one transform. Will the scene graph be able to detect this and optimize automatically similar to the way Java2D handles images for you? Or, perhaps more realistically, will there be a method we can call to perform such optimizations? Some scene graphs (Java3D, for example) have this ability to "compile" scene graphs.
Submitted by paksegu on Wed, 2008-01-09 21:10.
Nice, Definately Nice...Sun is definately stepping is its game with this JavaFx thing...No frills just JAVA
Submitted by swv on Thu, 2008-04-10 12:05.
Datapoint-
Ctrl-T worked fine.
mouse didn't respond to mouse at all.
XP64 / 6N / run as webstart
Submitted by mattnathan on Wed, 2008-01-09 08:24.
I get the same exception under linux
Java Web Start 1.6.0_03
Using JRE version 1.6.0_03 Java HotSpot(TM) Server VM and ctrl+t doesn't work for me either. Also the spacing between the characters in rotated text seems to be affected by rounding errors of some kind, this is most noticeable under the mouse tab where the characters seem to 'wobble' when rotated by small values. Other than that I'm looking forward to what comes out of this project.
Submitted by pdoubleya on Wed, 2008-01-09 03:16.
Hi Hans--nice overview, thanks.
I have the same problems with the demo--Ctrl T doesn't work for me. But the panels display correctly.
Also, in the demo code, the first method, createFill(), sets anti-aliasing on but only fills a shape with a black color--what does AA mean in the context of a black fill?
The AA method call makes me think there's room for (maybe the community to offer) some cover methods like "enableAA()" as an alternative to "setAntialiasingHint(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)". The number of method calls involved makes me think an "extension" API designed with fluent interfaces might make this more fun to program with--JMock has been a real inspiration for me as regards fluent interfaces. Those are minor, and something a community member could take on to simplify use of the API.
Looking forward to looking into the framework further, keep up the good writing.
Thanks, Patrick
Submitted by twilightworkshop on Wed, 2008-01-09 08:37.
CTRL T does not work on OSX either.
And I have the same exception
Submitted by quintesse on Wed, 2008-01-09 01:39.
Control-T doesn't seem to do anything? (at least on my system: Windows XP, Java 6 (1.6.0_03))
Submitted by tball on Wed, 2008-01-09 10:10.
If you check the MasterTimer.java source (Joe-Bob says check it out!), you'll find that the exception is a harmless diagnostic. I've asked that it be removed, since everyone (including myself) assume it is a fatal error.
Submitted by hansmuller on Wed, 2008-01-09 10:40.
OK: control-T doesn't work for me either! It does work when I launch
the application locally, but not with the web started version. Will
figure what's wrong, sorry about that.
Submitted by kirillcool on Wed, 2008-01-09 01:38.
java.security.AccessControlException: access denied (java.util.PropertyPermission com.sun.scenario.animationTimeline.nogaps read)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPropertyAccess(Unknown Source)
at java.lang.System.getProperty(Unknown Source)
at java.lang.Boolean.getBoolean(Unknown Source)
at com.sun.scenario.animation.MasterTimer.(MasterTimer.java:54)
at com.sun.scenario.animation.Timeline.addFrameJob(Timeline.java:52)
at com.sun.scenario.scenegraph.JSGPanelRepainter.(JSGPanelRepainter.java:53)
at com.sun.scenario.scenegraph.JSGPanelRepainter.(JSGPanelRepainter.java:45)
at com.sun.scenario.scenegraph.JSGPanel.markDirty(JSGPanel.java:525)
at com.sun.scenario.scenegraph.JSGPanel.setScene(JSGPanel.java:102)
at demo.intro.Intro$ScalingSGPanel.setScene(Intro.java:366)
at demo.intro.Intro.createMainPanel(Intro.java:336)
at demo.intro.Intro.startup(Intro.java:347)
Submitted by hansmuller on Mon, 2008-01-14 11:48.
The problem with control-T appeared to have been that the demo never
requested focus. That was easily fixed however when I tried the
(supposedly) updated app, no soap. I was somewhat busy with another
project at the time and asked
Igor Kushnirskiy
to take a look at the problem. He pointed out that I hadn't been
updating the right .jar file. He might have also pointed out that I'm
a knucklehead, but tactful man that he is, he let the facts speak for
themselves.
So the good news is that Amy's scene graph viewer now appears on control-T,
if you've clicked on the demo first.
Submitted by hansmuller on Mon, 2008-01-14 11:58.
Posted by: pdoubleya on January 09, 2008 at 02:16 AM
Also, in the demo code, the first method, createFill(), sets
anti-aliasing on but only fills a shape with a black color--what does
AA mean in the context of a black fill?
For the black filled arcs that appear in the "smiley" demo I didn't
describe, the AA flag will cause the value of pixels that only
partially overlap the curve to have an interpolated value that's
relative to the color already there. You can see it if you use a
screen magnifier.
About enabling AA in general: I agree that doing so per node is clunky,
albeit flexible. It would be useful to be able to
enableAA(),
as you say, for a subtree.
Submitted by hansmuller on Mon, 2008-01-14 12:02.
Posted by: diverson on January 09, 2008 at 01:37 PM
Regarding the rotation example: if the rotation were static (or will
be rendered many more times than it will be changed) then optimally
you would want to concatenate the three transforms into one
transform. Will the scene graph be able to detect this and optimize
automatically similar to the way Java2D handles images for you? Or,
perhaps more realistically, will there be a method we can call to
perform such optimizations? Some scene graphs (Java3D, for example)
have this ability to "compile" scene graphs.
I agree: caching the relatively static parts of the scene graph in a
form that's much closer to what's needed for rendering is definitely
the path to better performance. We're working on that.
Introducing the SceneGraph ProjectPosted by hansmuller on January 8, 2008 at 6:50 PM PST
Introducing SceneGraphI haven't written a blog entry since January when I advertised the fledgling Swing Application Framework (JSR-296) project with an uncharacteristically brief item. Work on that kept me busy until summer, when the Java FX juggernaut got underway here at Sun. Since then I've devoted much of my time to leading a project we've called "Scenario" that provides the graphical runtime for Java FX Script. We're now a public project on java.net called scenegraph.dev.java.net . You'll find downloads of the the 0.4.1 version of the Scenario source and binaries and (very) sketchy javadoc on the site. The 0.x version number is intended to convey the fact that the API hasn't stabilized yet. It's sufficient for experimentation and the implementation was robust enough to support a port of the Java FX Script interpreter, which we've showcased with a Scenario version of the FXPad Demo . Obviously, we don't recommend putting anything based on Scenario into production. Not yet. The code is being made available under the GPLv2 license. Passion about open source licenses is not something I possess so I'll leave the shouting about the implications of this choice to others. Suffice it to say that, per my limited understanding of these matters, you're free to share the code, and in the process of developing it further. We're moving our discussions of the API to the newly minted Scene Graph java.net forum . If you're interested in the project's evolution, that would be a good place to start looking. There are quite a few engineers working on Scenario, most of whom have made bigger contributions to the new software than I have, and you'll be hearing from them in their own blogs before too long. For now, what I'd like to do is to provide an introduction to the new Java APIs and just one demo. The team has written a whole raft of demos and we'll be opening up a subproject before too long, that contains the entire demo catalog. DemoAll of the examples that follow are part of a demo, each one occupies a tab. If you press "control-T" after clicking on a demo, you'll get a nice interactive tree view of the scene graph's structure, thanks to Amy Fowler for that! So press the orange button to launch the demo.
Note also: the demo scales the selected example scene to fit.
This is done with a small extension to Basics, Hello World
A scene graph, really a tree for now, is a data structure you
create from leaf nodes that represent visual elements
like 2D graphics and Swing components, filter nodes that
represent visual state, like 2D transforms and composition, and
group nodes that manage a list of children. All nodes
are subclasses of
SGText text = new SGText();
text.setText("Hello World");
JSGPanel panel = new JSGPanel();
panel.setScene(text);
panel.setPreferredSize(new Dimension(640, 480));
// create a JFrame, add the panel to it, etc..
One unusual line from the previous example, from a Swing
programmer's perspective, is that we've explicitly set the
preferred size of the
SGText text = new SGText();
text.setText("Hello World");
text.setFont(new Font("SansSerif", Font.PLAIN, 36));
text.setAntialiasingHint(RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
text.setFillPaint(Color.WHITE);
JSGPanel panel = new JSGPanel();
panel.setBackground(Color.BLACK);
panel.setScene(text);
panel.setPreferredSize(new Dimension(640, 480));
More Hello World: Groups and Shapes
Most of the Scenario classes are simple Java Beans. They provide null (no parameters) constructors and mutable properties. The API is intended to be "minimal" in the sense that it exposes the capabilities of the underlying Java 2D and Swing classes but does attempt to substantially simplify or abstract them. Scenario is intended to serve as the basis for higher level abstractions that require a scene graph, notably Java FX Script. For that reason, you may find programming against the Scenario API directly to be a bit tedious. Creating your own abstractions that simplify creating scene graphs is definitely the order of the day.
To add a border to the simple Hello World scene, we'll write a
method that takes any scene graph node and puts a garish rounded
rectangle border behind it. This example demonstrates using the
SGNode createBorder(SGNode node) {
Rectangle2D nodeR = node.getBounds();
double borderWidth = 10;
double x = nodeR.getX() - borderWidth;
double y = nodeR.getY() - borderWidth;
double w = nodeR.getWidth() + (2 * borderWidth);
double h = nodeR.getHeight() + (2 * borderWidth);
double a = 1.5 * borderWidth;
SGShape border = new SGShape();
border.setShape(new RoundRectangle2D.Double(x, y, w, h, a, a));
border.setFillPaint(new Color(0x660000));
border.setDrawPaint(new Color(0xFFFF33));
border.setDrawStroke(new BasicStroke(borderWidth / 2.0));
border.setMode(SGShape.Mode.STROKE_FILL);
border.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON);
SGGroup borderedNode = new SGGroup();
borderedNode.add(border);
borderedNode.add(node);
return borderedNode;
}
Adding a the border doesn't change the code that creates the scene graph very much:
SGText text = new SGText();
text.setText("Hello World");
// same as before ...
panel.setScene(createBorder(text));
Rotating Hello World: Transforms
As you can see in the previous example, the
To rotate a scene graph node around a point, you have to
assemble a chain of three transforms that: translate the node so
that the rotation point is at the origin, rotate the desired
amount, translate the node back to its original location.
Transforms are created with
SGTransform createRotation(SGNode node) {
Rectangle2D nodeR = node.getBounds();
double cx = nodeR.getCenterX();
double cy = nodeR.getCenterY();
SGTransform toOriginT = SGTransform.createTranslation(-cx, -cy, node);
SGTransform.Rotate rotateT = SGTransform.createRotation(0.0, toOriginT);
return SGTransform.createTranslation(cx, cy, rotateT);
}
To use the
SGTransform scene = createRotation(node);
SGTransform.Rotate rotateT = (SGTransform.Rotate)scene.getChild();
rotateT.setRotation(...);
Images and More Layout
Images can be incorporated in a scene graph with the
SGNode createRow(SGNode... nodes) {
double rowHeight = 0.0;
for(SGNode node : nodes) {
rowHeight = Math.max(rowHeight, node.getBounds().getHeight());
}
SGGroup row = new SGGroup();
double x = 0.0;
double gap = 8.0;
for(SGNode node : nodes) {
Rectangle2D nodeR = node.getBounds();
double y = (rowHeight - nodeR.getHeight()) / 2.0;
double dx = x - nodeR.getX();
double dy = y - nodeR.getY();
SGTransform xlate = SGTransform.createTranslation(dx, dy, node);
row.add(xlate);
x += nodeR.getWidth() + gap;
}
return row;
}
The code to create the SGImage node and the overall scene looks like this:
SGNode createEarth() {
BufferedImage image = null;
// ... code to load the image file
SGImage sgImage = new SGImage();
sgImage.setImage(image);
return sgImage;
}
// ...
SGNode row = createRow(createHelloWorldText(), createEarth());
SGNode scene = createBorder(row);
JSGPanel panel = new JSGPanel();
panel.setScene(scene);
Handling Input
All nodes can handle mouse and keyboard events and the support for
doing so is very similar to what AWT/Swing provides. For
example to make a node handle mouse events you add an
In this example, we've added a mouse listener to the
earth node in the scene from the previous example and restored
the support for rotating the scene. Dragging the earth with the
mouse rotates the scene. Here's the code that sets up the scene
and its
SGNode earth = createEarth();
SGNode row = createRow(createHelloWorldText(), earth);
SGTransform scene = createRotation(createBorder(row));
final SGTransform.Rotate rotateT = (SGTransform.Rotate)scene.getChild();
SGMouseListener changeRotation = new SGMouseAdapter() {
@Override public void mouseDragged(MouseEvent e, SGNode node) {
Rectangle2D r = e.getComponent().getBounds();
double x = e.getX() - r.getCenterX();
double y = e.getY() - r.getCenterY();
rotateT.setRotation(Math.atan2(y, x));
}
};
earth.addMouseListener(changeRotation);
JSGPanel panel = new JSGPanel();
panel.setScene(scene);
Although there's a great deal more to say by way of introducing Scenario, this blog entry has grown long enough that I'd better just take the same tack that Chet did , and declare this "Part 1". The code for the examples can be found here: http://weblogs.java.net/blog/hansmuller/archive/Intro.java A easy to build version will appear along with the other Scenario demos, later this month. »
Comments
Comments are listed in date ascending order (oldest first)
Submitted by throwable on Tue, 2008-01-29 10:02.
It is rather difficult to build and manipulate with scene graph using AffineTransform nodes. I think it may be simplified for example by integrating of SGNode with SGTransform allowing user to use simple bean methods like setX(), setY(), rotate(), scale(), etc... The main reason is that every "visual" node must be positioned inside scene and thus will always have corresponding translation node.
Submitted by hansmuller on Wed, 2008-01-09 11:18.
I've removed the alarming stack trace print that occurs when
MasterTimer can't read it's System properties. It was harmless
and unneccessary. I wish we had a better way to test sandboxed
applications.
Submitted by mikeazzi on Wed, 2008-01-09 12:26.
When I resize the frame I notice some lines flashing around the edges, giving it a not so smooth resizing feel. Otherwise it looks great. I am using Windows XP with Update N b08.
Submitted by diverson on Wed, 2008-01-09 14:37.
Thanks for the intro, Hans.
Regarding the rotation example: if the rotation were static (or will be rendered many more times than it will be changed) then optimally you would want to concatenate the three transforms into one transform. Will the scene graph be able to detect this and optimize automatically similar to the way Java2D handles images for you? Or, perhaps more realistically, will there be a method we can call to perform such optimizations? Some scene graphs (Java3D, for example) have this ability to "compile" scene graphs.
Submitted by paksegu on Wed, 2008-01-09 21:10.
Nice, Definately Nice...Sun is definately stepping is its game with this JavaFx thing...No frills just JAVA
Submitted by swv on Thu, 2008-04-10 12:05.
Datapoint-
Ctrl-T worked fine.
mouse didn't respond to mouse at all.
XP64 / 6N / run as webstart
Submitted by mattnathan on Wed, 2008-01-09 08:24.
I get the same exception under linux
Java Web Start 1.6.0_03
Using JRE version 1.6.0_03 Java HotSpot(TM) Server VM and ctrl+t doesn't work for me either. Also the spacing between the characters in rotated text seems to be affected by rounding errors of some kind, this is most noticeable under the mouse tab where the characters seem to 'wobble' when rotated by small values. Other than that I'm looking forward to what comes out of this project.
Submitted by pdoubleya on Wed, 2008-01-09 03:16.
Hi Hans--nice overview, thanks.
I have the same problems with the demo--Ctrl T doesn't work for me. But the panels display correctly.
Also, in the demo code, the first method, createFill(), sets anti-aliasing on but only fills a shape with a black color--what does AA mean in the context of a black fill?
The AA method call makes me think there's room for (maybe the community to offer) some cover methods like "enableAA()" as an alternative to "setAntialiasingHint(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)". The number of method calls involved makes me think an "extension" API designed with fluent interfaces might make this more fun to program with--JMock has been a real inspiration for me as regards fluent interfaces. Those are minor, and something a community member could take on to simplify use of the API.
Looking forward to looking into the framework further, keep up the good writing.
Thanks, Patrick
Submitted by twilightworkshop on Wed, 2008-01-09 08:37.
CTRL T does not work on OSX either.
And I have the same exception
Submitted by quintesse on Wed, 2008-01-09 01:39.
Control-T doesn't seem to do anything? (at least on my system: Windows XP, Java 6 (1.6.0_03))
Submitted by tball on Wed, 2008-01-09 10:10.
If you check the MasterTimer.java source (Joe-Bob says check it out!), you'll find that the exception is a harmless diagnostic. I've asked that it be removed, since everyone (including myself) assume it is a fatal error.
Submitted by hansmuller on Wed, 2008-01-09 10:40.
OK: control-T doesn't work for me either! It does work when I launch
the application locally, but not with the web started version. Will
figure what's wrong, sorry about that.
Submitted by kirillcool on Wed, 2008-01-09 01:38.
java.security.AccessControlException: access denied (java.util.PropertyPermission com.sun.scenario.animationTimeline.nogaps read)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPropertyAccess(Unknown Source)
at java.lang.System.getProperty(Unknown Source)
at java.lang.Boolean.getBoolean(Unknown Source)
at com.sun.scenario.animation.MasterTimer.(MasterTimer.java:54)
at com.sun.scenario.animation.Timeline.addFrameJob(Timeline.java:52)
at com.sun.scenario.scenegraph.JSGPanelRepainter.(JSGPanelRepainter.java:53)
at com.sun.scenario.scenegraph.JSGPanelRepainter.(JSGPanelRepainter.java:45)
at com.sun.scenario.scenegraph.JSGPanel.markDirty(JSGPanel.java:525)
at com.sun.scenario.scenegraph.JSGPanel.setScene(JSGPanel.java:102)
at demo.intro.Intro$ScalingSGPanel.setScene(Intro.java:366)
at demo.intro.Intro.createMainPanel(Intro.java:336)
at demo.intro.Intro.startup(Intro.java:347)
Submitted by hansmuller on Mon, 2008-01-14 11:48.
The problem with control-T appeared to have been that the demo never
requested focus. That was easily fixed however when I tried the
(supposedly) updated app, no soap. I was somewhat busy with another
project at the time and asked
Igor Kushnirskiy
to take a look at the problem. He pointed out that I hadn't been
updating the right .jar file. He might have also pointed out that I'm
a knucklehead, but tactful man that he is, he let the facts speak for
themselves.
So the good news is that Amy's scene graph viewer now appears on control-T,
if you've clicked on the demo first.
Submitted by hansmuller on Mon, 2008-01-14 11:58.
Posted by: pdoubleya on January 09, 2008 at 02:16 AM
Also, in the demo code, the first method, createFill(), sets
anti-aliasing on but only fills a shape with a black color--what does
AA mean in the context of a black fill?
For the black filled arcs that appear in the "smiley" demo I didn't
describe, the AA flag will cause the value of pixels that only
partially overlap the curve to have an interpolated value that's
relative to the color already there. You can see it if you use a
screen magnifier.
About enabling AA in general: I agree that doing so per node is clunky,
albeit flexible. It would be useful to be able to
enableAA(),
as you say, for a subtree.
Submitted by hansmuller on Mon, 2008-01-14 12:02.
Posted by: diverson on January 09, 2008 at 01:37 PM
Regarding the rotation example: if the rotation were static (or will
be rendered many more times than it will be changed) then optimally
you would want to concatenate the three transforms into one
transform. Will the scene graph be able to detect this and optimize
automatically similar to the way Java2D handles images for you? Or,
perhaps more realistically, will there be a method we can call to
perform such optimizations? Some scene graphs (Java3D, for example)
have this ability to "compile" scene graphs.
I agree: caching the relatively static parts of the scene graph in a
form that's much closer to what's needed for rendering is definitely
the path to better performance. We're working on that.
Application Framework Prototype BowsPosted by hansmuller on January 30, 2007 at 8:03 AM PST
I've made a prototype of the fledgling JSR-296 API available, it's https://appframework.dev.java.net/. There's a quick overview doc and downloads of the source code, the javadoc, and the AppFramework.jar file. If you're interested in this API, please take a look at the overview, and download the code and then take a look at some of the examples and the javadoc. You can post feedback here or, if you want to participate in the long-term discussion, subscribe to the appframework.dev.java.net "users" mailing list: https://appframework.dev.java.net/servlets/ProjectMailingListList . The users alias is the last one listed. That's all I really wanted to say. I don't want to make too much of a commotion about this version of the design because there's still quite a bit that remains to be done. I was hoping that this would be a sort-of stealth release: not terribly noticeable, unless you know where to look. On the other hand, I know there are Swing developers who aren't members of the JSR-296 expert group, who'd like to take stock of where this project is going. And I know there are experienced Swing developers out there, some of whom have built their own application frameworks, that would like see how this one measures up. I'd welcome feedback from anyone who's interested and I'll promise to respond promptly, unless you bring up a really difficult issue or a really large number of them. That might take longer. Note also: the JCP defines a milestone called "Early Draft Review" that means the expert group thinks the spec is complete enough to begin fine tuning. We have not reached that milestone yet. »
Comments
Comments are listed in date ascending order (oldest first)
Application Framework Prototype BowsPosted by hansmuller on January 30, 2007 at 8:03 AM PST
I've made a prototype of the fledgling JSR-296 API available, it's https://appframework.dev.java.net/. There's a quick overview doc and downloads of the source code, the javadoc, and the AppFramework.jar file. If you're interested in this API, please take a look at the overview, and download the code and then take a look at some of the examples and the javadoc. You can post feedback here or, if you want to participate in the long-term discussion, subscribe to the appframework.dev.java.net "users" mailing list: https://appframework.dev.java.net/servlets/ProjectMailingListList . The users alias is the last one listed. That's all I really wanted to say. I don't want to make too much of a commotion about this version of the design because there's still quite a bit that remains to be done. I was hoping that this would be a sort-of stealth release: not terribly noticeable, unless you know where to look. On the other hand, I know there are Swing developers who aren't members of the JSR-296 expert group, who'd like to take stock of where this project is going. And I know there are experienced Swing developers out there, some of whom have built their own application frameworks, that would like see how this one measures up. I'd welcome feedback from anyone who's interested and I'll promise to respond promptly, unless you bring up a really difficult issue or a really large number of them. That might take longer. Note also: the JCP defines a milestone called "Early Draft Review" that means the expert group thinks the spec is complete enough to begin fine tuning. We have not reached that milestone yet. »
Comments
Comments are listed in date ascending order (oldest first)
Property Syntax for Java? A Constructive AlternativePosted by hansmuller on January 10, 2007 at 5:57 AM PST
Having written, by conservative estimates, about a jillion Java Beans classes over the years, I have to say that I'm amazed that we'd seriously consider changing the Java language to trivialize this kind of Java Bean property. It certainly is a property per the spec, a read/write property at that, but - as a Swing developer - it's the kind of property I almost never write. And if repetitive boilerplate is what we're hunting with this language change, then we're shooting at rabbits while a herd of buffalo thunders by. The mighty buffalo of the Java Beans boilerplate animal kingdom are bound properties. They're the kind of properties we write so that our beans can be automatically and dynamically synchronized with a GUI or with each other. As a desktop developer, I almost always write bound properties. To write a bound property properly you've got to ensure that your class defines or inherits support for a PropertyChangeListener. That's about 20 lines of code just to get started:
class FooBean {
private final java.beans.PropertyChangeSupport pcs;
public FooBean () {
pcs = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
public PropertyChangeListener[] getPropertyChangeListeners() {
return pcs.getPropertyChangeListeners();
}
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
pcs.firePropertyChange(propertyName, oldValue, newValue);
}
}
And then there's the definition of each read/write property which should: check the validity of new values in its set method as well as calling firePropertyChange to notify PropertyChangeListeners, and defensively copy the return value (if necessary) in its get method. I suppose one could concoct syntax that would simplify all of this, at least a little, as well as allowing for read-only/write-only variants. But that's not the proposal I wanted to make here. If you consider the property keyword proposal in light of Java's origins in the C language, then it's pretty clear what the proposal's proponents are really after: structs. It's not about defining properties, it's about simplifying defining a Java class that's comparable to a struct in the C language. So perhaps the proposal should really focus on allowing one to write classes, not properties. Where this:
struct FooBean { Foo foo; }
Would by equivalant to this (as before):
class FooBean {
private Foo foo;
public Foo getFoo() { return foo; }
public void setFoo(Foo foo) { this.foo = foo; }
}
If you admit that the focus of the property proposal is really adding support for defining structs in Java, then using "->" to refer to struct properties feels like coming home again.
struct Point { int x, y; }
Point p = new Point();
p->x = p->y = 0; // oh joy
I'm not a language design expert however I would think that I would be among the target developers for Java language feature designed to support properties. In my humble (ha) opinion, the current proposal serves the needs of Java Beans developers poorly by targeting a special case that doesn't warrant language support. Although I would welcome a proposal that also simplified defining bound properties, I would guess that it would be hard to invent syntax that would handle the general case without being obscure. If there is a consituency for the current proposal, I say: give them structs instead. »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
Properties access with pointers p->x
Submitted by bemowski on Tue, 2009-10-20 13:53.
I am wondering if an extension to java.util.Properties that I've published over on Google Code meets this need?
http://code.google.com/p/eproperties/
EProperties supports nested properties objects, and allows deep access using the 'pointer' syntax.
Property Syntax for Java? A Constructive AlternativePosted by hansmuller on January 10, 2007 at 5:57 AM PST
Having written, by conservative estimates, about a jillion Java Beans classes over the years, I have to say that I'm amazed that we'd seriously consider changing the Java language to trivialize this kind of Java Bean property. It certainly is a property per the spec, a read/write property at that, but - as a Swing developer - it's the kind of property I almost never write. And if repetitive boilerplate is what we're hunting with this language change, then we're shooting at rabbits while a herd of buffalo thunders by. The mighty buffalo of the Java Beans boilerplate animal kingdom are bound properties. They're the kind of properties we write so that our beans can be automatically and dynamically synchronized with a GUI or with each other. As a desktop developer, I almost always write bound properties. To write a bound property properly you've got to ensure that your class defines or inherits support for a PropertyChangeListener. That's about 20 lines of code just to get started:
class FooBean {
private final java.beans.PropertyChangeSupport pcs;
public FooBean () {
pcs = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
public PropertyChangeListener[] getPropertyChangeListeners() {
return pcs.getPropertyChangeListeners();
}
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
pcs.firePropertyChange(propertyName, oldValue, newValue);
}
}
And then there's the definition of each read/write property which should: check the validity of new values in its set method as well as calling firePropertyChange to notify PropertyChangeListeners, and defensively copy the return value (if necessary) in its get method. I suppose one could concoct syntax that would simplify all of this, at least a little, as well as allowing for read-only/write-only variants. But that's not the proposal I wanted to make here. If you consider the property keyword proposal in light of Java's origins in the C language, then it's pretty clear what the proposal's proponents are really after: structs. It's not about defining properties, it's about simplifying defining a Java class that's comparable to a struct in the C language. So perhaps the proposal should really focus on allowing one to write classes, not properties. Where this:
struct FooBean { Foo foo; }
Would by equivalant to this (as before):
class FooBean {
private Foo foo;
public Foo getFoo() { return foo; }
public void setFoo(Foo foo) { this.foo = foo; }
}
If you admit that the focus of the property proposal is really adding support for defining structs in Java, then using "->" to refer to struct properties feels like coming home again.
struct Point { int x, y; }
Point p = new Point();
p->x = p->y = 0; // oh joy
I'm not a language design expert however I would think that I would be among the target developers for Java language feature designed to support properties. In my humble (ha) opinion, the current proposal serves the needs of Java Beans developers poorly by targeting a special case that doesn't warrant language support. Although I would welcome a proposal that also simplified defining bound properties, I would guess that it would be hard to invent syntax that would handle the general case without being obscure. If there is a consituency for the current proposal, I say: give them structs instead. »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
Properties access with pointers p->x
Submitted by bemowski on Tue, 2009-10-20 13:53.
I am wondering if an extension to java.util.Properties that I've published over on Google Code meets this need?
http://code.google.com/p/eproperties/
EProperties supports nested properties objects, and allows deep access using the 'pointer' syntax.
Javapolis Session Interrupted by Marriage ProposalPosted by hansmuller on December 17, 2006 at 4:34 PM PST
Javapolis 2006I spent most of last week at the Javapolis conference in Antwerp Belgium. With nearly 3000 attendees, it's the second biggest Java conference after JavaOne, and it's held in a movie cineplex complex called "Metropolis". The venue delivers large halls, comfortable seats (with beverage caddies!), and dramatic lighting. Half of each enormous movie screen is devoted to a live image of the presenter and the camerawork is quite good, pausing for a dramatic closeup now and then. My laptop wasn't working correctly so I had to turn around periodically, to visually sync up with my slides. That meant that the audience was treated to six linear feet of my balding hemisphere glowing in the klieg lights. I was thankful that everyone put up with that, and also with my raspy voice. I'd managed to pick up a cold the day before leaving, and only hours before I was scheduled to speak, I could do little more than croak and wheeze. Things were somewhat better by the showtime, however from the sound of my voice you might think I'd spent the day smoking heavily and shrieking. My presentation topic was JSR-296 "Swing Application Framework". If you're interested, there's a copy here. Within a few months you'll find a nicely edited slides-and-video version of the presentation on parleys.com, thanks to Stephan Janssen, the tireless Javapolis organizer. And when it appears, do not miss the finale. As Richard Bair and I finished up a demo of a prototype of the Application Framework in NetBeans, Stephan appeared and asked to interrupt the proceedings for a special announcment. He picked up the microphone and asked a woman who's name I didn't catch to come forward. Sure enough, a tall young blonde woman came to the front, looking nonplussed. After a brief pause, a young man wearing a suit came loping down the aisle and in a moment he was facing the woman and making a declaration of some kind in Dutch. She looked pretty nervous and, not knowing where this was all going, we started feeling a bit anxious too. Until he dropped to one knee and assumed the international marriage proposal position. Then we really started to worry, because here was a situation that could only end really well, or really badly. The woman was crying (uh oh) and smiling (whew!), and then nodding her head, and to everyone's relief, we had a happy betrothal. The couple bounded up the steps to a nice round of applause, and Richard and I tried to remember what it was we'd been talking about. The Javapolis conference was memorable as always. One evening the organizers arranged for enough french fries and mayonaise to serve 3000 (that's a lot), they showed the new James Bond movie, Mark Fleury performed his keynote dressed up like Flavor Flav, Sun raffled away a Nintendo Wii, the technical sessions were solid, and, mine was interrupted by a proposal of marriage. With a happy ending. Merry Christmas!
Update: Stephan Janssen has published the video, you'll find it here: »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
Javapolis Session Interrupted by Marriage ProposalPosted by hansmuller on December 17, 2006 at 4:34 PM PST
Javapolis 2006I spent most of last week at the Javapolis conference in Antwerp Belgium. With nearly 3000 attendees, it's the second biggest Java conference after JavaOne, and it's held in a movie cineplex complex called "Metropolis". The venue delivers large halls, comfortable seats (with beverage caddies!), and dramatic lighting. Half of each enormous movie screen is devoted to a live image of the presenter and the camerawork is quite good, pausing for a dramatic closeup now and then. My laptop wasn't working correctly so I had to turn around periodically, to visually sync up with my slides. That meant that the audience was treated to six linear feet of my balding hemisphere glowing in the klieg lights. I was thankful that everyone put up with that, and also with my raspy voice. I'd managed to pick up a cold the day before leaving, and only hours before I was scheduled to speak, I could do little more than croak and wheeze. Things were somewhat better by the showtime, however from the sound of my voice you might think I'd spent the day smoking heavily and shrieking. My presentation topic was JSR-296 "Swing Application Framework". If you're interested, there's a copy here. Within a few months you'll find a nicely edited slides-and-video version of the presentation on parleys.com, thanks to Stephan Janssen, the tireless Javapolis organizer. And when it appears, do not miss the finale. As Richard Bair and I finished up a demo of a prototype of the Application Framework in NetBeans, Stephan appeared and asked to interrupt the proceedings for a special announcment. He picked up the microphone and asked a woman who's name I didn't catch to come forward. Sure enough, a tall young blonde woman came to the front, looking nonplussed. After a brief pause, a young man wearing a suit came loping down the aisle and in a moment he was facing the woman and making a declaration of some kind in Dutch. She looked pretty nervous and, not knowing where this was all going, we started feeling a bit anxious too. Until he dropped to one knee and assumed the international marriage proposal position. Then we really started to worry, because here was a situation that could only end really well, or really badly. The woman was crying (uh oh) and smiling (whew!), and then nodding her head, and to everyone's relief, we had a happy betrothal. The couple bounded up the steps to a nice round of applause, and Richard and I tried to remember what it was we'd been talking about. The Javapolis conference was memorable as always. One evening the organizers arranged for enough french fries and mayonaise to serve 3000 (that's a lot), they showed the new James Bond movie, Mark Fleury performed his keynote dressed up like Flavor Flav, Sun raffled away a Nintendo Wii, the technical sessions were solid, and, mine was interrupted by a proposal of marriage. With a happy ending. Merry Christmas!
Update: Stephan Janssen has published the video, you'll find it here: »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
Dialog DiatribePosted by hansmuller on October 27, 2006 at 5:48 PM PDT
I've been writing the occasional small application recently and now and then I blunder into a problem with Java SE that's, uh..., well, annoying. I realize that I'm not the only one who's had this experience and I'm probably not the only one who seeks relief by writing a lengthy diatribe and then sending it to whomever might be guilty of creating the situation. Of course, in my case that's often me, and since relief usually doesn't come from berating oneself, I'm guilty of sending the occasional long crabby missive to the people who are currently responsible for maintaining things that I'm probably responsible for bollocksing up in the first place. It's not a particularly endearing habit. I sent the following to Swing's technical lead, Shannon Hickey, and he confirmed that the details, though twisted with bile, are essentially correct. So in the interest of furthering my own therapy, and also to ensure that some record of this will be stored away in Google's indices till the end of time, I thought I'd share. I would think that a fairly common idiom in a Swing application would be to popup a dialog in response to selecting a menu item. Given Matisse, we'll assume that the JDialog has been created with the IDE, rather than some JOptionPane convenience method, and given rudimentary aesthetics, assume the dialog should be centered over the menu item's frame. Accomplishing this seems to be much too difficult:
public void showMyDialog(ActionEvent e) {
// How to find the Dialog's Frame owner?
Window dialogOwner = null;
JDialog dialog = new MyDialog(dialogOwner, true); // true => modal Dialog
dialog.pack();
// How to center the Dialog?
dailog.setVisible(true);
}
The first problem to deal with is mapping from the menu item's ActionEvent to the frame that contains the menu item. The frame will be the dialog's owner as well as the component we're going to center the dialog relative to. There seems to be an overabundance of SwingUtilities methods that address this trivial problem:
To find the Frame that owns a JMenuItem, we have to follow the JPopupMenu's "invoker" property, which gets us back into the component hierarchy. So to find the frame that corresponds to an ActionEvent one must write (!):
Frame frameForActionEvent(ActionEvent e) {
if (e.getSource() instanceof Component) {
Component c = (Component)e.getSource();
while(c != null) {
if (c instanceof Frame) {
return (Frame)c;
}
c = (c instanceof JPopupMenu) ? ((JPopupMenu)c).getInvoker() : c.getParent();
}
}
return null;
}
It would more useful to have written
But we're still not done, because we must also center the dialog over the frame. Naturally there are other useful positions for the dialog. Centering a dialog over its frame happens to be what started me on this quest. I have it on good authority that Windows.setLocationRelativeTo() is the handy method for this job. The javadoc for this method isn't promising:
OK so far. Except it sounds like I'm going to have to compute the relative origin of my dialog and deal with edge (of the screen) conditions. Yech.
Huh? What does "the component" refer to in this sentence? I
assume they're not referring to this Window and I have to
wonder what "showing" means in this context. Is is the same
thing as
This, no doubt, means that the method will endeavor to find a location for my dialog that respects the relative location I've specified, without making part of the dialog appear off-screen. Good, I think. So I still appear to be stuck with computing an origin for my dialog that centers it relative to its owner. Before I code that, I try leaving the origin of the new dialog at 0,0, which is the default:
public void showMyDialog(ActionEvent e) {
Window dialogOwner = frameForActionEvent(e);
JDialog dialog = new MyDialog(dialogOwner, true);
dialog.pack();
aboutBox.setLocationRelativeTo(dialogOwner);
dialog.setVisible(true);
}
Miraculously, this works. The dialog appears centered over the dialogOwner unless that would cause the dialog to appear off-screen. I have no idea why it works, since according to the "spec" (and the name of the method) I should have had to compute an appropriate relative origin for the dialog. But I guess I don't. Frankly, I think this whole mess is a mini-travesty. If I'm going to show a dialog, I should be able to do so without writing code that digs around the component hierarchy and without experimentally determining what something as simple (and not terribly useful) as Window.setLocationRelativeTo() does. There, that feels a little better. A seven year old bug that covers the menu item to frame lookup problem is still open. Given the fact that it's accumulated exactly 0 votes in that time, perhaps no one has ever cared about the problem quite as much as I do at this moment. I would think that a cleaner way to handle this case would be some static methods that handled the entire idiom, for example:
public void showMyDialog(AWTEvent event) {
Window dialogOwner = Window.eventToWindow(event);
JDialog dialog = new MyDialog(dialogOwner, true);
Window.showModalDialog(dialog); // Center dialog relative to its owner
}
And Shannon suggested that the method name might be rationalized
as implying that the Window is be moved to a location that makes
its relationship to the component parameter obvious.
Typically that means centering the Window relative to the
component. In return for that tortured explanation, I had to
agree to file an RFE about the
Thanks for listening. »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
Dialog DiatribePosted by hansmuller on October 27, 2006 at 5:48 PM PDT
I've been writing the occasional small application recently and now and then I blunder into a problem with Java SE that's, uh..., well, annoying. I realize that I'm not the only one who's had this experience and I'm probably not the only one who seeks relief by writing a lengthy diatribe and then sending it to whomever might be guilty of creating the situation. Of course, in my case that's often me, and since relief usually doesn't come from berating oneself, I'm guilty of sending the occasional long crabby missive to the people who are currently responsible for maintaining things that I'm probably responsible for bollocksing up in the first place. It's not a particularly endearing habit. I sent the following to Swing's technical lead, Shannon Hickey, and he confirmed that the details, though twisted with bile, are essentially correct. So in the interest of furthering my own therapy, and also to ensure that some record of this will be stored away in Google's indices till the end of time, I thought I'd share. I would think that a fairly common idiom in a Swing application would be to popup a dialog in response to selecting a menu item. Given Matisse, we'll assume that the JDialog has been created with the IDE, rather than some JOptionPane convenience method, and given rudimentary aesthetics, assume the dialog should be centered over the menu item's frame. Accomplishing this seems to be much too difficult:
public void showMyDialog(ActionEvent e) {
// How to find the Dialog's Frame owner?
Window dialogOwner = null;
JDialog dialog = new MyDialog(dialogOwner, true); // true => modal Dialog
dialog.pack();
// How to center the Dialog?
dailog.setVisible(true);
}
The first problem to deal with is mapping from the menu item's ActionEvent to the frame that contains the menu item. The frame will be the dialog's owner as well as the component we're going to center the dialog relative to. There seems to be an overabundance of SwingUtilities methods that address this trivial problem:
To find the Frame that owns a JMenuItem, we have to follow the JPopupMenu's "invoker" property, which gets us back into the component hierarchy. So to find the frame that corresponds to an ActionEvent one must write (!):
Frame frameForActionEvent(ActionEvent e) {
if (e.getSource() instanceof Component) {
Component c = (Component)e.getSource();
while(c != null) {
if (c instanceof Frame) {
return (Frame)c;
}
c = (c instanceof JPopupMenu) ? ((JPopupMenu)c).getInvoker() : c.getParent();
}
}
return null;
}
It would more useful to have written
But we're still not done, because we must also center the dialog over the frame. Naturally there are other useful positions for the dialog. Centering a dialog over its frame happens to be what started me on this quest. I have it on good authority that Windows.setLocationRelativeTo() is the handy method for this job. The javadoc for this method isn't promising:
OK so far. Except it sounds like I'm going to have to compute the relative origin of my dialog and deal with edge (of the screen) conditions. Yech.
Huh? What does "the component" refer to in this sentence? I
assume they're not referring to this Window and I have to
wonder what "showing" means in this context. Is is the same
thing as
This, no doubt, means that the method will endeavor to find a location for my dialog that respects the relative location I've specified, without making part of the dialog appear off-screen. Good, I think. So I still appear to be stuck with computing an origin for my dialog that centers it relative to its owner. Before I code that, I try leaving the origin of the new dialog at 0,0, which is the default:
public void showMyDialog(ActionEvent e) {
Window dialogOwner = frameForActionEvent(e);
JDialog dialog = new MyDialog(dialogOwner, true);
dialog.pack();
aboutBox.setLocationRelativeTo(dialogOwner);
dialog.setVisible(true);
}
Miraculously, this works. The dialog appears centered over the dialogOwner unless that would cause the dialog to appear off-screen. I have no idea why it works, since according to the "spec" (and the name of the method) I should have had to compute an appropriate relative origin for the dialog. But I guess I don't. Frankly, I think this whole mess is a mini-travesty. If I'm going to show a dialog, I should be able to do so without writing code that digs around the component hierarchy and without experimentally determining what something as simple (and not terribly useful) as Window.setLocationRelativeTo() does. There, that feels a little better. A seven year old bug that covers the menu item to frame lookup problem is still open. Given the fact that it's accumulated exactly 0 votes in that time, perhaps no one has ever cared about the problem quite as much as I do at this moment. I would think that a cleaner way to handle this case would be some static methods that handled the entire idiom, for example:
public void showMyDialog(AWTEvent event) {
Window dialogOwner = Window.eventToWindow(event);
JDialog dialog = new MyDialog(dialogOwner, true);
Window.showModalDialog(dialog); // Center dialog relative to its owner
}
And Shannon suggested that the method name might be rationalized
as implying that the Window is be moved to a location that makes
its relationship to the component parameter obvious.
Typically that means centering the Window relative to the
component. In return for that tortured explanation, I had to
agree to file an RFE about the
Thanks for listening. »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
|
||
|