DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

The Latest Popular Topics

article thumbnail
Ant Build File Changes for Java Web Projects in NetBeans IDE 6.1
While working with a Java Web Application in NetBeans, I noticed some slight changes in the Ant build file for my project between NetBeans 6.0 and 6.1. This article explores some of the problems these changes caused to help out anyone with similar issues. I started with a Java Web Application that was created in NetBeans 6.0.1. After adding some JSP files and several Java source files, I committed everything in the project to my CVS repository. For some of my projects, I utilize the Hudson continuous integration build server. Using a standard deployment of Hudson, I configured the project to poll the SCM every 60 minutes, check out the code from CVS (if changes had been committed), and trigger the NetBeans project’s Ant build file (calling several specific targets like compile, dist, and so on. My builds have been functioning correctly for several weeks using this standard setup. I recently opened one of those projects in NetBeans 6.1 Beta and have been thoroughly enjoying the new features (faster startup, better JSP parsing in the Source Editor). After adding some JAR files as libraries and making several configuration changes, I committed the entire project (particularly the build-related files in the nbproject directory). Suddenly, my build for that project started failing. The console output reported by Hudson was : -init-check: BUILD FAILED D:/projects/hudson-server/data/jobs/MyWebProjectl/workspace/nbproject/build-impl.xml:149: The Java EE server classpath is not correctly set up. Your active server type is Tomcat55. Either open the project in the IDE and assign the server or setup the server classpath manually. For example like this: ant -Duser.properties.file= (where you put the property “j2ee.platform.classpath” in a .properties file) or ant -Dj2ee.platform.classpath= (where no properties file is used) Total time: 2 seconds finished: FAILURE I undid the configuration changes one by one, but the build failed regardless of what I reset. Apparently the property j2ee.platform.classpath is now required. I did a DIFF on the nbproject/build-impl.xml file and discovered several changes. The -init-check target includes property checks including this new one : The Java EE server classpath is not correctly set up. Your active server type is ${j2ee.server.type}.Either open the project in the IDE and assign the server or setup the server classpath manually.For example like this: ant -Duser.properties.file= (where you put the property “j2ee.platform.classpath” in a .properties file) or ant -Dj2ee.platform.classpath= (where no properties file is used) I hadn’t really taken notice of this property in the build file before, but it is referenced in a number of other targets such as: -init-macrodef-javac, -init-macrodef-junit, -init-macrodef-java, -init-macrodef-nbjpda, -init-macrodef-debug, compile-jsps, -do-compile-single-jsp, connect-debugger, javadoc-build, -do-compile-test, -do-compile-test-single Not being able to find a definition of the property anywhere in the build file, I looked through the project’s project.properties file among the list of defined properties. The property j2ee.platform.classpath was not defined. Thus, I’m assuming this is passed into the build file dynamically by NetBeans? In general I wouldn’t care, but when running the build file via Ant inside Hudson, the property j2ee.platform.classpath is never passed in. Hudson DOES allow you to pass properties and values to the build file, so I suppose I can specify the value manually, but I would like to keep the number of per project customizations to a minimum to maintain a low level of maintenance. Unless this causes some problem with the project properties in the build system, I would suggest the following fix for anyone who is experiencing a similar issue. Open your project’s project.properties file. Navigate to the section that contains these properties: j2ee.platform=1.4 j2ee.server.type=Tomcat55 Add a new line that specifies a blank j2ee.platform.classpath property such as this: j2ee.platform=1.4 j2ee.platform.classpath= j2ee.server.type=Tomcat55 Now, if the project.properties file is committed to CVS, a Hudson build can be triggered, and the FAIL check in the build-impl.xml file will pass. I ran some quick tests with the project, and everything with the project inside NetBeans still seems to work fine. I would propose to the NetBeans team to have the j2ee.platform.classpath property automatically added to the project.properties file.
March 26, 2008
by Adam Myatt
· 15,519 Views
article thumbnail
Java Bean Code Generation In Eclipse
Where would we be without JavaBeans? We use them in all our basic Java applications. We have Struts Form Beans, Hibernate and Spring POJO's and the list goes on. We are all used to writing setters and getters in for our Java Bean's manually. With thanks to Eclipse and other plugins, this effort is now very very easy. This tip is for the beginners (seniors, this is my first quick tip post) to generate setters and getters in a Java Bean class. First declare all the variables you need in the class. Next, right click any where on the source file. Select Source and then Generate Getters and Setters. This can be done alternatively by pressing Alt+Shift+S. Now select the variables for which you want to generate the getters and setters and you're done. As you can see there are multiple options in the window. Finally, the source code is.. Happy Coding! Until Next Time... RD
March 20, 2008
by Ratna Dinakar Tumuluri
· 56,943 Views
article thumbnail
Applying Python To Modify Java Code
Python script intended to open each Java's project file, add the license term on the start of the file as a Java comment and writing it to the disk. 1) You'll need a Python interpreter. Check this out in http://python.org. 2) You'll need to enter the root file directory of the Java project, like python AddLicense.py ${path} where ${path} defines user project root directory. 3) See http://fcmanager.wiki.sourceforge.net 1:# Python script to add the LGPL notices to each java file of the FileContentManager project. 2:import os, glob, sys 3:License = """\ 4:/** 5:*FileContentManager is a Java based file manager desktop application, 6:*it can show, edit and manipulate the content of the files archived inside a zip. 7:* 8:*Copyright (C) 2008 9:* 10:*Created by Camila Sanchez [http://mimix.wordpress.com/], Rafael Naufal [http://rnaufal.livejournal.com] 11:and Rodrigo [[email protected]] 12:* 13:*FileContentManager is free software; you can redistribute it and/or 14:*modify it under the terms of the GNU Lesser General Public 15:*License as published by the Free Software Foundation; either 16:*version 2.1 of the License, or (at your option) any later version. 17:* 18:*This library is distributed in the hope that it will be useful, 19:*but WITHOUT ANY WARRANTY; without even the implied warranty of 20:*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21:*Lesser General Public License for more details. 22:* 23:*You should have received a copy of the GNU Lesser General Public 24:*License along with FileContentManager; if not, write to the Free Software 25:*Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ 26: 27:size = len(sys.argv) 28:if size == 1 or size > 2: 29: print "Usage: AddLicense.py $1" 30: sys.exit(1) 31:inputPath = sys.argv[1] 32:if not os.path.exists(inputPath): 33: print inputPath, "does not exist on disk" 34: sys.exit(1) 35:if not os.path.isdir(inputPath): 36: print inputPath, "isn't a dir" 37: sys.exit(1) 38:for path, dirs, files in os.walk(inputPath): 39: fileWithLicense = '' 40: for filepath in [ os.path.join(path, f) 41: for f in files if f.endswith(".java")]: 42: content = file(filepath).read() 43: f = file(filepath, "w") 44: print >>f, License + "\n" + content 45: f.close() 46: 47:
March 17, 2008
by Rafael Naufal
· 2,807 Views
article thumbnail
How to Create a Pluggable Photo Album in Java
Here you see a simple photo album I created in Java Swing. It is, by no definition of the term, a great photo album. However, the point is that none of the photos you see are provided by the application itself. Nor do they come from the web. So... where do they come from and how did they end up in my photo album? Read on to find out... Here's a clue. All that you would need to provide in order to add photos to my photo album is a Java application that is structured as follows: The images "demo1.png" and "demo2.png" are two of the four photos you see in the first screenshot, i.e., the screenshot of my photo album. The other two photos you see there come from another Java application, which is structured in exactly the same way as the above. "Ah," you might now think. "This article is all about the Java SE 6 java.util.ServiceLoader class. I guess I'll need to be using Java SE 6 and then I'll be able to construct small applications structured like the above and then I'll be able to plug into your photo album." Wrong. You don't need Java SE 6 at all. Although, you're close. Here's the definition of the VacPhotos class that you see in the illustration above: package com.example.vacphotos; import javax.swing.Icon; import javax.swing.ImageIcon; import photoalbumapp.Photo; public class VacPhotos implements Photo { ImageIcon icon1 = new ImageIcon(getClass().getResource("/com/example/vacphotos/demo1.png")); ImageIcon icon2 = new ImageIcon(getClass().getResource("/com/example/vacphotos/demo2.png")); public VacPhotos() { } @Override public Icon[] getPhoto() { Icon[] icons = new Icon[]{icon1, icon2}; return icons; } @Override public String[] getDescription() { String[] descs = new String[]{"pic 1", "pic2"}; return descs; } } In other words, you simply need to extend the photoalbumapp.Photo class, which the photo album itself makes available, meaning you need its JAR on your plugin's classpath. The photo album is an empty application shell that exposes the Photo class, with its two methods getPhoto and getDescription. You therefore need to create a Java class that implements those two methods, returning arrays of Icons and Strings for the photos you'd like to integrate into the photo album. Finally, you need to create a file in your META-INF.services folder, with the name of the class that you are implementing, which in this case is photoalbumapp.Photo. Within that file you need nothing more than one line, which is the FQN of your implementation class: com.example.vacphotos.VacPhotos And that's all. Now, when the JAR of your app is on the classpath of the photo album, your photos and descriptions will automatically be integrated with all the photos provided by all the other implementations of the same class. The cool thing is that the photo album is an implementation of JSR-296, the Swing Application Framework, so that lifecycle management and persistance, as well as other typical application services, are dealt with by the framework itself. For example, I don't need to provide any code for the user's resizings and repositionings to be saved across restarts. The most important part, in this context, of my photo album application (i.e., this is a totally separate application to the VacationPhotos application above), is the code that defines my photo service: package photoalbumapp; import java.util.Collection; import org.openide.util.Lookup; import org.openide.util.Lookup.Result; import org.openide.util.Lookup.Template; public class PhotoService { private static PhotoService service; private Lookup photoLookup; private Collection photos; private Template photoTemplate; private Result photoResults; private PhotoService() { photoLookup = Lookup.getDefault(); photoTemplate = new Template(Photo.class); photoResults = photoLookup.lookup(photoTemplate); photos = photoResults.allInstances(); } public static synchronized PhotoService getInstance() { if (service == null) { service = new PhotoService(); } return service; } public Collection getDefinitions() { return photos; } } The template lookup method returns a Result instance that contains multiple providers, if they exist. You can retrieve the entire collection of providers by calling the Result instance's allInstances method, which is exactly what is done above. Here you see that we are not dealing with the Java SE 6 ServiceLoader class (nor its earlier incarnations, which have been in the JDK since JDK 1.3). Instead, we are dealing with the NetBeans Platform's org.openide.util.Lookup class. Above, I have provided the bridge between your VacationPhotos application and my own separate application that provides the photo album. The bridge is accessed by the photo album to retrieve photos and descriptions. The bridge, in its role as a "service", will, in turn, access all the classes that implement the Photo implementers, as defined in the small Java applications that exist for no other reason than to provide photos, such as the VacPhotos application shown earlier. And how is the service used? The main JFrame constructor in the photo album is as follows, really simplistic as you can see: ... ... ... private PhotoService photo; public PhotoAlbum() { photo = PhotoService.getInstance(); initComponents(); JPanel content = new JPanel(); content.setLayout(new FlowLayout()); Collection coll = photo.getDefinitions(); Iterator it = coll.iterator(); while (it.hasNext()) { Photo photo = it.next(); Icon[] icons = photo.getPhoto(); String[] strings = photo.getDescription(); for (int i = 0; i < icons.length; i++) { JLabel imageLabel = new JLabel(); imageLabel.setBorder(BorderFactory.createLineBorder(Color.red)); Icon icon = icons[i]; String desc = strings[i]; imageLabel.setIcon(icon); imageLabel.setText(desc); content.add(imageLabel); } } setContentPane(content); } ... ... ... And that's really all. Now, what are the benefits of using the NetBeans Platform's org.openide.util.Lookup class instead of the JDK's ServiceLoader class? Lookup is available in versions for older JDKs and thus you can use it as a replacement of ServiceLoader when running on JDKs older than 1.6. Lookup is ready to work inside of the NetBeans runtime container, so makes even more sense when you're working with NetBeans modules. It knows how to discover all the modules in the system, how to effectively read its defined services, and similar activities. Lookup supports listeners. Client code can attach a listener and observe changes in lookup content. This is a necessary improvement to adapt to the dynamic environment created by the NetBeans runtime container, where modules can be enabled or disabled at runtime, which in turn can affect the set of registered service providers. Lookup is extensible and replaceable. While the ServiceLoader class in JDK 1.6 is a final class with hard-coded behavior, the NetBeans Lookup class is an extensible class that allows various implementations. This can be useful while writing unit tests. Or you can write an enhanced version of lookup that not only reads META-INF/services but, for example, finds the requested service providers around the Internet. Lookup is a general purpose abstraction. While the JDK's ServiceLoader can de-facto have just one instance per classloader, there can be thousands of independent Lookup instances, each representing a single place to query services and interfaces. In fact this is exactly the way Lookup is used in NetBeans IDE—it represents the context of each dialog, window element, node in a tree, etc. And now you know all that's needed for treating Java applications as plugins. (For further information, see John O'Conner's Creating Extensible Applications With the Java Platform.) In summary, by means of registration and discovery of classes and interfaces, loosely coupled photo albums, and similar applications, are clearly very easy to achieve.
March 16, 2008
by Geertjan Wielenga
· 47,091 Views
article thumbnail
Understanding Loose Typing in JavaScript
for many front end developers, javascript was their first taste of a scripting and/or interpretive language. to these developers, the concept and implications of loosely typed variables may be second nature. however, the explosive growth in the demand for web 2.0-ish applications has resulted in a growing number of back end developers that have had to dip their feet into pool of client side technologies. many of these developers are coming from a background in strongly typed languages, such as c# and java, and are unfamiliar with both the freedom and the potential pitfalls involved in working with loosely typed variables. since the concept of loose typing is so fundamental to scripting in javascript, an understanding of it is essential. this article is a top level discussion of loose typing in javascript. since there may be subtle differences in loose typing from language to language, let me constrain this discussion to the context of javascript. ok, let's dig in... what is loose typing? well, this seems like a good place to start. it is important to understand both what loose typing is , and what loose typing is not . loose typing means that variables are declared without a type. this is in contrast to strongly typed languages that require typed declarations. consider the following examples: /* javascript example (loose typing) */ var a = 13; // number declaration var b = "thirteen"; // string declaration /* java example (strong typing) */ int a = 13; // int declaration string b = "thirteen"; // string declaration notice that in the javascript example, both a and b are declared as type var. please note, however, that this does not mean that they do not have a type, or even that they are of type "var". variables in javascript are typed, but that type is determined internally. in the above example, var a will be type number and var b will be type string. these are two out of the three primitives in javascript, the third being boolean. javascript also has other types beyond primitives. the type diagram for javascript is as follows (as per mozilla ): ya really - null and undefined too. note, however, that this distinction between primitives and objects will be dismissed in javascript 2.0. you can read more about that here . type coercion type coercion is a topic that is closely associated with loose typing. since data types are managed internally, types are often converted internally as well. understanding the rules of type coercion is extremely important. consider the following expressions, and make sure you understand them: 7 + 7 + 7; // = 21 7 + 7 + "7"; // = 147 "7" + 7 + 7; // = 777 in the examples above, arithmetic is carried out as normal (left to right) until a string is encountered. from that point forward, all entities are converted to a string and then concatenated. type coercion also occurs when doing comparisons. you can, however, forbid type coercion by using the === operator. consider these examples: 1 == true; // = true 1 === true; // = false 7 == "7"; // = true 7 === "7"; // = false; there are methods to explicitly convert a variable's type as well, such as parseint and parsefloat (both of which convert a string to a number). double negation (!!) can also be used to cast a number or string to a boolean. consider the following example: true == !"0"; // = false true == !!"0"; // = true conclusion this obviously is not a definitive reference to loose typing in javascript (or type coercion for that matter). i do hope, however, that this will be a useful resource to those who are not familiar with these topics, and a good refresher for those who already are. i have tried to insure that the above is accurate, but if you notice anything incorrect, please let me know! and as always, thanks for reading!
March 14, 2008
by Jeremy Martin
· 15,419 Views
article thumbnail
Easy Multi Select Transfer with jQuery
I'm sure that at some point or another you've encountered a form widget like the one below, allowing options to be traded from one multi select to another. Option 1 Option 2 Option 3 Option 4 add >> << remove I recently encountered a tutorial over at Quirks Mode on creating such a widget. While not a bad script, when all was said and done it was coming up on 40 lines of JS. I suppose that's not horrible, but we're talking about some simple functionality. This struck me as a perfect example to demonstrate the simple and compact nature of jQuery coding. The widget operating above is running off of the following code: $().ready(function() { $('#add').click(function() { return !$('#select1 option:selected').remove().appendTo('#select2'); }); $('#remove').click(function() { return !$('#select2 option:selected').remove().appendTo('#select1'); }); }); That's it... 8 lines. You can also try it out for yourself with the following test page: Option 1Option 2Option 3Option 4 add >> << remove Since the purpose of this widget is usually to collect all the elements in the second multi select, you can use the following snippet to automatically select all of the options before submitting. $('form').submit(function() { $('#select2 option').each(function(i) { $(this).attr("selected", "selected"); }); }); Just make sure you include that snippet inside the $().ready() handler. Thanks for viewing and I hope you found this helpful! Feel free to use and modify without constraint.
March 7, 2008
by Jeremy Martin
· 31,716 Views
article thumbnail
Log4J the Groovy Way
While developing around, now or then one wants something printed out at the console of his/her IDE.
March 4, 2008
by Gerhard Balthasar
· 61,929 Views
article thumbnail
SVNKit: Tame Subversion with Java!
SVNKitis an Open Source pure Java Subversion library. SVNKit literally brings Subversion, popular open source version control system, to the Java world. With SVNKit you can do the following: All standard Subversion operations: For instance, the following snipped checks out project from repository: File dstPath = new File("c:/svnkit"); SVNURL url = SVNURL. parseURIEncoded("http://svn.svnkit.com/repos/svnkit/branches/1.1.x/"); SVNClientManager cm = SVNClientManager.newInstance(); SVNUpdateClient uc = cm.getUpdateClient(); uc.doCheckout(url, dstPath, SVNRevision.UNDEFINED, SVNRevision.HEAD, true); Updates it to the latest revision: uc.doUpdate(dstPath, SVNRevision.HEAD, true); And finally commits local changes in "www" subdirectory if there are any: SVNCommitClient cc = cm.getCommitClient(); cc.doCommit(new File[] {new File(dstPath, "www")}, false, "message", false, true); SVNKit supports all standard Subversion operations and compatible with the latest version of Subversion. Access Subversion repository directly: Some applications will benefit from working with repository directly, without keeping working copy locally. Example below displays list of files in "www" directory. SVNURL url = SVNURL.parseURIEncoded("http://svn.svnkit.com/repos/svnkit/branches/1.1.x/"); SVNRepository repos = SVNRepositoryFactory.create(url); long headRevision = repos.getLatestRevision(); Collection entriesList = repos.getDir("www", headRevision, null, (Collection) null); for (Iterator entries = entriesList.iterator(); entries.hasNext();) { SVNDirEntry entry = (SVNDirEntry) entries.next(); System.out.println("entry: " + entry.getName()); System.out.println("last modified at revision: " + entry.getDate() + " by " + entry.getAuthor()); } Direct repository access API allows to perform operations like update, commit, diff and many other. Additionaly to the performance benefits of the direct access to repository, this API makes it possible to version arbitrary objects or object models within Subevrsion repository, not only files from the file system. Replace JNI Subversion bindings with SVNKit: Native Subversion provides Java interface that works with Subversion binaries through JNI. In case you already using it or would like to use as an option, you may also use SVNKit through exactly the same interface. This way you'll let your application dynamically switch between JNI and SVNKit implementation of the same API or let your application work on the platforms where there are no native Subversion binaries. For example: // pure Java implementation of the standard Subversion Java interface SVNClientInterface jniAPI = SVNClientImpl.newInstance(); byte[] contents = jniAPI.fileContent("http://svn.svnkit.com/repos/svnkit/branches/1.1.x/changelog.txt", Revision.HEAD); SVNKit is widely used in different applications, including IntelliJ IDEA, Eclipse Subversion integrations, SmartSVN, JDeveloper, bug tracking server side applications (e.g. Atlassian JIRA) and repository management and tracking tools (e.g. Atlassian FishEye) and many others. Where to get more information: Recently we've released SVNKit version 1.1.6 which is bugfix release. At http://svnkit.com/ you will find more information on that new version and, of course, downloads, documentation, source code example and articles explaining how to use SVNKit. In case of any questions you're welcome at our mailing list, or just contact us at [email protected] SVNKit is widely used in different applications, including IntelliJ IDEA, Eclipse Subversion integrations, SmartSVN, JDeveloper, bug tracking server side applications (e.g. Atlassian JIRA) and repository management and tracking tools (e.g. Atlassian FishEye) and many others. With best regards, TMate Software, http://svnkit.com/ - Java [Sub]Versioning Library!
February 26, 2008
by Alexander Kitaev
· 11,277 Views · 2 Likes
article thumbnail
Let's Create a Tetris Game in Compiled JavaFX Script
i thought it would be fun to spend a few posts creating a tetris game in compiled javafx script together. today i made a rough start on it, and if you promise not to laugh, i'll show you the humble beginnings. here's a screenshot of its current status: in tetris, there are several types of tetrominoes , each having a letter that it resembles. the four buttons on the left represent four of these shapes. when you press one of these buttons, the corresponding tetromino appears at the top and begins moving down the screen. when you click the rotate button, the tetromino rotates to the right, and the left / right buttons move the tetromino left and right, respectively. the code is contained in four fx program files, and needs some refactoring already. :-) before showing you the code in its current state, i'd like to point out a couple of helpful things: as explained in the spinning wheel post, the key frame animation syntax that you see here will become much less verbose as the javafx script compiler team continues to address animation. javafx script programs should always be designed with the ui binding to a model. in this program, the model is represented in one class named tetrismodel , located in the fx file of the same name. you may find it helpful to take a look the creating a compiled javafx script program with multiple fx source files post to see a hello world style program that has more than one fx file. please notice the package statments in this tetris program, as that influences where you need to put the source files and how you build them. you can obtain the javafx compiler by following the instructions in the obtaining the openjfx script compiler post. the source code (so far) here's the main program, named tetrismain.fx , that declaratively expresses the ui, and starts things up: /* * tetrismain.fx - the main program for a compiled javafx script tetris game * * developed 2008 by james l. weaver (jim.weaver at lat-inc.com) * to serve as a compiled javafx script example. */ package tetris_ui; import javafx.ui.*; import javafx.ui.canvas.*; import java.lang.system; import tetris_model.*; frame { var model = tetrismodel { } var canvas:canvas width: 480 height: 500 title: "tetrisjfx" background: color.white content: borderpanel { center: canvas = canvas {} bottom: flowpanel { content: [ button { text: "i" action: function() { canvas.content = []; insert tetrisshape { model: model shapetype: tetrisshapetype.i } into canvas.content; model.t.start(); } }, button { text: "t" action: function() { canvas.content = []; insert tetrisshape { model: model shapetype: tetrisshapetype.t } into canvas.content; model.t.start(); } }, button { text: "l" action: function() { canvas.content = []; insert tetrisshape { model: model shapetype: tetrisshapetype.l } into canvas.content; model.t.start(); } }, button { text: "s" action: function() { canvas.content = []; insert tetrisshape { model: model shapetype: tetrisshapetype.s } into canvas.content; model.t.start(); } }, button { text: "rotate" action: function() { model.rotate90(); } }, button { text: "left" action: function() { model.moveleft(); } }, button { text: "right" action: function() { model.moveright(); } } ] } } visible: true onclose: function():void { system.exit(0); } } i made the tetrisshape class a custom graphical component. therefore, it is a subclass of the compositenode class, and overrides the composenode function. note: there is a typo in line 62 of the tetrisshape.fx listing. "returnreturn" should read "return". it will be corrected asap. /* * tetrisshape.fx - a tetris piece, configurable to the * different shape types. they are: * i, j, l, o, s, t, and z * * developed 2008 by james l. weaver (jim.weaver at lat-inc.com) * to serve as a compiled javafx script example. * */ package tetris_ui; import javafx.ui.*; import javafx.ui.canvas.*; import java.awt.point; import java.lang.system; import tetris_model.*; class tetrisshape extends compositenode { private static attribute squareoutlinecolor = color.black; private static attribute squareoutlinewidth = 2; private attribute squarecolor; public attribute model:tetrismodel; public attribute shapetype:tetrisshapetype on replace { if (shapetype == tetrisshapetype.i) { squarelocs = []; insert new point(0, model.square_size * 1) into squarelocs; insert new point(0, 0) into squarelocs; insert new point(0, model.square_size * 2) into squarelocs; insert new point(0, model.square_size * 3) into squarelocs; squarecolor = color.red; } else if (shapetype == tetrisshapetype.t) { squarelocs = []; insert new point(model.square_size * 1, 0) into squarelocs; insert new point(0, 0) into squarelocs; insert new point(model.square_size * 2, 0) into squarelocs; insert new point(model.square_size * 1, model.square_size * 1) into squarelocs; squarecolor = color.green; } else if (shapetype == tetrisshapetype.l) { squarelocs = []; insert new point(0, model.square_size * 1) into squarelocs; insert new point(0, 0) into squarelocs; insert new point(0, model.square_size * 2) into squarelocs; insert new point(model.square_size * 1, model.square_size * 2) into squarelocs; squarecolor = color.magenta; } else if (shapetype == tetrisshapetype.s) { squarelocs = []; insert new point(model.square_size * 1, 0) into squarelocs; insert new point(model.square_size * 2, 0) into squarelocs; insert new point(0, model.square_size * 1) into squarelocs; insert new point(model.square_size * 1, model.square_size * 1) into squarelocs; squarecolor = color.cyan; } } private attribute squarelocs:point[]; public function composenode():node { return group { transform: bind [ translate.translate(model.square_size * model.tetrominohorzpos, (model.a / model.square_size).intvalue() * model.square_size), rotate.rotate(model.tetrominoangle, squarelocs[0].x + model.square_size / 2, squarelocs[0].y + model.square_size / 2) ] content: [ for (squareloc in squarelocs) { rect { x: bind squareloc.x y: bind squareloc.y width: bind model.square_size height: bind model.square_size fill: bind squarecolor stroke: squareoutlinecolor strokewidth: squareoutlinewidth } } ] }; } } the tetrisshapetype class defines the tetromino types: /* * tetrisshapetype.fx - a tetris shape type, which are * i, j, l, o, s, t, and z * * developed 2008 by james l. weaver (jim.weaver at lat-inc.com) * to serve as a compiled javafx script example. * */ package tetris_ui; import javafx.ui.*; class tetrisshapetype { public attribute id: integer; public attribute name: string; public static attribute o = tetrisshapetype {id: 0, name: "o"}; public static attribute i = tetrisshapetype {id: 1, name: "i"}; public static attribute t = tetrisshapetype {id: 2, name: "t"}; public static attribute l = tetrisshapetype {id: 3, name: "l"}; public static attribute s = tetrisshapetype {id: 4, name: "s"}; } and finally, here's a model class, named tetrismodel: /* * tetrismodel.fx - the model behind the tetris ui * * developed 2008 by james l. weaver (jim.weaver at lat-inc.com) * to serve as a compiled javafx script example. * */ package tetris_model; import javafx.ui.animation.*; import java.lang.system; import com.sun.javafx.runtime.pointerfactory; public class tetrismodel { public static attribute square_size = 20; public attribute a:integer; private attribute pf = pointerfactory {}; private attribute bpa = bind pf.make(a); private attribute pa = bpa.unwrap(); private attribute interpolate = numbervalue.linear; public attribute t = timeline { keyframes: [ keyframe { keytime: 0s; keyvalues: numbervalue { target: pa; value: 0; interpolate: bind interpolate } }, keyframe { keytime: 20s; keyvalues: numbervalue { target: pa; value: 370 interpolate: bind interpolate } } ] }; public attribute tetrominoangle:number; public attribute tetrominohorzpos:number = 10; public function rotate90():void { (tetrominoangle += 90) % 360; } public function moveleft():void { if (tetrominohorzpos > 0) { tetrominohorzpos--; } } public function moveright():void { if (tetrominohorzpos < 20) { //todo:replace 10 with a calculated number tetrominohorzpos++; } } } compile and execute this example, and examine the code. i'll get busy making it behave a little more like a tetris game, and show you some progress in the next post. please feel free to get ahead of me, and make your own version! regards, jim weaver javafx script: dynamic java scripting for rich internet/client-side applications immediate ebook (pdf) download available at the book's apress site
February 22, 2008
by James Weaver
· 17,556 Views
article thumbnail
VisualVM: Free and Open Source Java Troubleshooter
Trying to troubleshoot Java? VisualVM is a great, free, open source tool.
February 21, 2008
by Geertjan Wielenga
· 69,406 Views
article thumbnail
Lorem Ipsum: Now Generated in Java
February 14th, the international day of sweet nothings, saw the release of Lorem Ipsum for Java, the new Java generator of space filler text. Never again will you need to put "aaaaa" in a demo field, or "xxxx", or something similar. Instead, you will be able to ooze the air of the Greeks of old, by generating text into your otherwise bare ui. And all that text will not need to have been typed, or copy/pasted, or anything similar. Instead, you will be able to use Java itself to generate the above filler text. The above 5 paragraphs of high minded mumbo jumbo came about like this: LoremIpsum ipsum = new LoremIpsum(); String words = ipsum.getParagraphs(5); And the lorem ipsum library is quite versatile: So not only can you choose to generate either words or paragraphs, but the exact number of words and paragraphs can also be specified. Here's looking forward to seeing lorem ipsumized space fillers in all the demos of the future!
February 18, 2008
by Geertjan Wielenga
· 15,463 Views
article thumbnail
Plugging into Lobo's Pure Java Web Browser
Lobo's Java Web Browser, still at a dot zero release, drew my attention today because it very recently was Java Posse's project of the week. I love the fact that this browser is pure Java! Plus, it is open source and under active development. Let's help things along by explaining how to create plugins, because this project is smart enough to expose an API for this purpose. At the end of this article, you'll be able to start up the Lobo browser and you will then see a new menu, with a new menu item, that will produce a "Hello World" greeting in a JOptionPane. It will all look thusly: Even though there is no "Hello world" document for Lobo plugin development (which I am hoping to remedy by means of this article), the Lobo Browser Plugin HOWTO provides most of the information you need. It is all quite intuitive, once you have the basics. Here they are: After you download the Lobo distro, put its lobo-pub.jar on your plugin-to-be's classpath. At a bare minimum, you need a class that extends org.lobobrowser.ua.NavigatorExtension. Here's mine, just to give you an idea. Note the overrides, of course, because these are the main hooks into the browser: public class ExtensionImpl implements NavigatorExtension { private JMenu menu; private JMenuItem item; @Override public void init(NavigatorExtensionContext ctx) {} @Override public void windowOpening(NavigatorWindow window) { menu = new JMenu("Greetings"); item = new JMenuItem("Hello"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { JOptionPane.showMessageDialog(null, "hello world"); } }); window.addMenu("Demo", menu); } @Override public void windowClosing(NavigatorWindow window) {} @Override public void destroy() {} } That's all we need for our small scenario. Since we're simply using Swing, it is easy to imagine other things that you might do when the window opens/closes, etc. Use code completion and other tools in your IDE to figure out other things you might be able to do to the Lobo browser: Now create a properties file called lobo-extension.properties, in your src structure, at the highest level, and add the following info: extension.name=Demo Lobo Extension extension.description=This is a demo extension extension.by=Geertjan Wielenga extension.version=0.1 extension.class=demoloboplugin.ExtensionImpl extension.priority=4 The extension class is the one shown in step 2, registered by its FQN. The priority is described in the API docs, it's not so important at this stage, since w're just doing a hello world scenario. Finally, you'll have a plugin that looks similar to this: Now compile the plugin, creating a JAR that you put in the distro's ext folder. Below, mine is called "DemoLoboPlugin.jar": Just restart the browser and there's your new menu. Since it is this easy to extend the browser, I'm hoping this intro has grabbed your imagination and that you'll support this super cool browser. If you love Java, you'll love this browser. Downloading the distro and setting things up was as simple as unjarring and then running java -jar from the command line. Here's hoping that the people behind this project will publish MANY small samples demonstrating the ways in which the browser can be extended. That way, they'd be giving developers handholds to making this browser all that it should be.
February 6, 2008
by Geertjan Wielenga
· 34,091 Views
article thumbnail
How to Add Resize Functionality to Visual Applications in Java?
In How to Create Visual Applications in Java?, I introduced you to the NetBeans Visual Library, specifically in the context of standard Java SE applications. Here we continue where we left off, but we add resize functionality... in very few lines of code! At the end of the previous article, it was clear that (a) the NetBeans Visual Library is a very powerful framework for creating graphical widgets (for example, to make a widget move, you simply add one line of code), (b) one doesn't need the NetBeans Platform even though one is using one of its libraries and (c) one doesn't even need NetBeans IDE, even though one could do so, of course, but only if one wanted to do so. Simply put, you just download NetBeans IDE once, remove two of its JARs and then, if that's how you feel, you can remove NetBeans IDE completely. Next, simply put those two JARs on your classpath and you're good to go. At the end of that article, we had created Chuk, one of the Sun evangelists, as a movable object with an editable label text field. We then also created Gregg, who is also a Sun evangelist, as another instance of the same object: However, there was one problem with the above scenario, at least, according to Gregg: "Hey, how come Chuk's picture is larger?" That's the message he left in my blog, where I had also discussed this scenario in detail. So, this time, we're going to help Gregg. (So, all of this is for you, Gregg!) We're going to do two things, both of which are really cool, mostly undocumented, and illustrative of a whole host of things, as you'll discover if you stick with this article until the very end. At the end, when your mouse moves over a widget, its borders will become resizable. Then, when you drag the handles on the border, the image will resize itself according to the movement of the mouse. So, you'll be able to make Chuk a whole lot smaller. And, Gregg can be made bigger (or smaller still): Let's begin by asking ourselves how to create that border with the handles, i.e., the one that, when you see it, you think: "I am now able to resize something". Probably lots of code, right? Wrong. The Visual Library extends the borders offered by the JDK's Border classes. It provides a package called org.netbeans.api.visual.border.BorderFactory and another called org.netbeans.api.visual.border.Border. (I learned about all of this from Fabrizio Giudici's Creative Uses of the Visual Library, a document which I highly recommend.) Here we begin by declaring two constants, one for a normal border and one for resizing: private static final Border RESIZE_BORDER = BorderFactory.createResizeBorder(8,Color.BLACK,true); private static final Border DEFAULT_BORDER = BorderFactory.createEmptyBorder(8); Even though our default border is empy, we set its thickness to 8, so that the area reserved for our border is the same for both. (If you experiment later, you'll see that if you don't set a thickness, strange effects result when the resize border is enabled/disabled.) Now that we have our borders, we need to specify when they should be shown. To do this, we create a class that extends IconNodeWidget, unlike the last time where we were extending GraphScene and then creating new nodes in attachNodeWidget. Creating a separate class gives us more room to maneouvre, allowing us to add a lot of behavior to an individual widget. Here we call our widget PhotoWidget, we expect to receive the scene, an image, and a name. We assign those to the widget's label and image. We then add, as before, the MoveAction, so that the widget can move. (Just one line of code and no listeners!) We also, for the first time, add the HoverAction, which will make the widget sensitive to our mouse, as it hovers over it: private static final class PhotoWidget extends IconNodeWidget { public PhotoWidget(Scene scene, Image pic, String name) { super(scene); setLabel(name); setImage(pic); setPreferredLocation(new Point(10, 20)); getActions().addAction(ActionFactory.createMoveAction()); getActions().addAction(scene.createWidgetHoverAction()); } @Override public void notifyStateChanged(ObjectState previousState, ObjectState newState) { super.notifyStateChanged(previousState, newState); getImageWidget().setBorder( newState.isSelected() ? ( newState.isHovered() ? RESIZE_BORDER : DEFAULT_BORDER) : ( newState.isHovered() ? RESIZE_BORDER : DEFAULT_BORDER)); } } Finally, notice that we have overridden IconNodeWidget.notifyStateChanged, which will determine whether our border will be shown! And that depends on our calculations in the setBorder method, which returns a border, as calculated above. If the widget is selected or hovered over, the border changes. Currently, however, even though the border changes, the image doesn't resize when we drag the border's handles. To be able to do that, we need to add four lines of additional code, just lines 7-10 below: public PhotoWidget(Scene scene, Image pic, String name) { super(scene); setLabel(name); setImage(pic); setPreferredLocation(new Point(10, 20)); //Add lines 7-10 below: setLayout(LayoutFactory.createVerticalFlowLayout(LayoutFactory.SerialAlignment.JUSTIFY, 1)); setChildConstraint(getImageWidget(), 1); setCheckClipping(true); getImageWidget().getActions().addAction(ActionFactory.createResizeAction()); getActions().addAction(ActionFactory.createMoveAction()); getActions().addAction(scene.createWidgetHoverAction()); } It is very important that the ResizeAction appear BEFORE the MoveAction, otherwise the MoveAction will consume the event, which will result in your resize gesture causing a move action instead. Also note that we don't resize the WHOLE widget, but just the image. The other three lines change the layout and grab the image, such that they can be resized. We set the clipping check to true, so that the image is clipped as it resizes, otherwise bits of it would remain as we resized. At this point, I should reveal that the above doesn't actually work, because of a known issue in the Visual Library. Guided by David Kaspar, the creator of the library, I hacked the sources of the library to make it work. You can do the same. Just attach the sources to your project, instead of the JAR. Then find ImageWidget.paintWidget and change this line: gr.drawImage(image, 0, 0, observer); ...to these lines: Rectangle bounds = getBounds(); gr.drawImage(image, bounds.x, bounds.y, bounds.width, bounds.height, 0, 0, width, height, observer); Now that your image has bounds, it can be resized. You'll have to make this change in the sources yourself too, until the issue is fixed, hopefully soon. Just to recap, starting from last time, we have a JFrame with a JScrollPane. We've added a Visual Library "scene" to the JScrollPane. Then we added a LayerWidget to which we added two IconNodeWidgets. Both can move, they're sensitive to hovering, they have names, and images. And now the IconNodeWidgets get new resize borders when hovered over. And the handles on those borders can be dragged to resize the widget, including its image. For the record, here is our constructor, together with our declarations at the top of the class: private static final Border RESIZE_BORDER = BorderFactory.createResizeBorder(8, Color.BLACK, true); private static final Border DEFAULT_BORDER = BorderFactory.createEmptyBorder(8); private LayerWidget mainLayer; private Image CHUK = Utilities.icon2Image( new ImageIcon(getClass().getResource("/demo/chuk.png"))); private Image GREGG = Utilities.icon2Image( new ImageIcon(getClass().getResource("/demo/gregg.png"))); public DemoVisualFrame() { Scene scene = new Scene(); initComponents(); jScrollPane1.setViewportView(scene.createView()); mainLayer = new LayerWidget(scene); scene.addChild(mainLayer); mainLayer.addChild(new PhotoWidget(scene, CHUK, "Chuk")); mainLayer.addChild(new PhotoWidget(scene, GREGG, "Gregg")); } Hope you're happy now Gregg!
February 5, 2008
by Geertjan Wielenga
· 44,764 Views
article thumbnail
How to Create Visual Applications in Java?
My excellent colleague Java evangelist Chuk Munn Lee wrote me an e-mail in response to my description yesterday of how to create JConsole plugins: "I did not know that the visual library can be used outside of NetBeans. Do you need a special build of the library? Do I need to build it myself or is there a standalone version that I can download?" This is a good question and the answer is illustrative of how interwoven NetBeans IDE is with the NetBeans Platform. Look in your NetBeans installation folder and you'll find a folder called "platform7", with this content: In other words, literally, the content of the folder above is the NetBeans Platform. Many of the JARs that make up the NetBeans Platform can be used outside a NetBeans Platform application. Last October I wrote about this, in a blog entry entitled NetBeans APIs Outside of the NetBeans Platform. Follow the steps in that tutorial and you'll have a standard Java application that makes use of some of the typical JARs from the NetBeans Platform. In other words, several typical scenarios developed on the NetBeans Platform can also be developed outside of it. Another similar scenario is illustrated in the article I wrote yesterday, How to Get Started with JConsole Plugins, where the Visual Library API is used to inject some graph functionality into the JConsole. And so, in response to Chuk's questions "Do you need a special build of the library? Do I need to build it myself or is there a standalone version that I can download?", the answer is: "No, you don't." Download NetBeans IDE, take the two JARs that are highlighted in the screenshot above, put them on your app's classpath, and you're ready to create visual Java applications: Let's get started for real now. To create visual applications, you need some kind of Swing container within which you need a JScrollPane. Then you create your visual "scene" within that JScrollPane. There are several interesting classes that you can extend to make your visual application. Have a look at the Javadoc or take a stroll through the tutorial, though not all of the tutorial is intended for use outside of the NetBeans Platform. Now that you have a Swing container with a JScrollPane, create a new Java class that extends GraphScene. Fill it out as follows: package demo; import java.awt.Image; import java.awt.Point; import java.util.Random; import javax.swing.ImageIcon; import org.netbeans.api.visual.graph.GraphScene; import org.netbeans.api.visual.widget.LayerWidget; import org.netbeans.api.visual.widget.Widget; import org.netbeans.api.visual.widget.general.IconNodeWidget; import org.openide.util.Utilities; public class DemoGraphScene extends GraphScene { private LayerWidget mainLayer; private Image image; private Random r = new Random(); public DemoGraphScene() { mainLayer = new LayerWidget(this); addChild(mainLayer); image = Utilities.icon2Image( new ImageIcon(getClass().getResource("/demo/chuk.png"))); addNode("Chuk"); } @Override protected Widget attachNodeWidget(Object arg0) { IconNodeWidget widget = new IconNodeWidget(this); widget.setImage(image); widget.setPreferredLocation(new Point(10, 20)); mainLayer.addChild(widget); return widget; } @Override protected Widget attachEdgeWidget(Object arg0) { return null; } @Override protected void attachEdgeSourceAnchor(Object arg0, Object arg1, Object arg2) { } @Override protected void attachEdgeTargetAnchor(Object arg0, Object arg1, Object arg2) { } } Most of the above code is self-explanatory, I believe. You have a LayerWidget which you add to the scene. Then you add an IconWidget, which you add to the layer. One interesting thing to note is how the icon is converted to an image, via a utility method from the NetBeans Utilities API, which you have already put on your classpath, together with the Visual Library API. In other words, there's a bunch of stuff that NetBeans Platform developers use that can also be used in your own smaller Java applications, as is the case here. To wrap up, we need to instantiate the GraphScene class from our JFrame and then set the JScrollPane so that its port view will contain the "scene". Here's how we do that, nice and easy via the JFrame constructor: private DemoGraphScene scene = new DemoGraphScene(); public DemoVisualFrame() { initComponents(); jScrollPane1.setViewportView(scene.createView()); } Next, I added a pic of Chuk to my app's source structure and then ran the application. And here's the result: Next, let's turn Chuk into a movable object. The user should be able to drag and drop him with their mouse. Hmmm. That will mean a lot of coding, right? Wrong. Here's all I needed to add, i.e., just line 6 below: protected Widget attachNodeWidget(Object arg0) { IconNodeWidget widget = new IconNodeWidget(this); widget.setImage(image); widget.setPreferredLocation(new Point(10, 20)); //I only needed to add this line: widget.getActions().addAction(ActionFactory.createMoveAction()); mainLayer.addChild(widget); return widget; } And now, when I run my app, I can use my mouse to drag Chuk to a different location: A MoveAction can only mean one thing, i.e., it can only mean that you want to move the widget. However, other actions could be implemented in a variety of ways, hence there is no default. You need to provide the content of the action yourself, as in the case of the LabelTextFieldEditor. Here, we begin by defining a class-level LabelTextFieldEditor: private WidgetAction editorAction = ActionFactory.createInplaceEditorAction(new LabelTextFieldEditor()); Next, we define out LabelTextFieldEditor, extending the TextFieldInplaceEditor class: private class LabelTextFieldEditor implements TextFieldInplaceEditor { public boolean isEnabled(Widget widget) { return true; } public String getText(Widget widget) { return ((LabelWidget) widget).getLabel(); } public void setText(Widget widget, String text) { ((LabelWidget) widget).setLabel(text); } } Finally, we add a label to our widget. We also assign the editor action defined above to our widget. Here we go, just line 7 and 8 below: @Override protected Widget attachNodeWidget(Object arg0) { IconNodeWidget widget = new IconNodeWidget(this); widget.setImage(image); widget.setPreferredLocation(new Point(10, 20)); //I added the following two lines: widget.setLabel("Chuk"); widget.getLabelWidget().getActions().addAction(editorAction); widget.getActions().addAction(ActionFactory.createMoveAction()); mainLayer.addChild(widget); return widget; } That's it. Let's run our app again. You now have a label which you can click and then it is editable: When you press Enter, the label is changed. But what's the point of having just Chuk in our application? Let's add another evangelist, Gregg Sporar: private Image CHUK = Utilities.icon2Image(new ImageIcon(getClass().getResource("/demo/chuk.png"))); private Image GREGG = Utilities.icon2Image(new ImageIcon(getClass().getResource("/demo/gregg.png"))); Next, we'll create a hash table, so that we can manipulate them more effectively: private final Hashtable mapping; { mapping = new Hashtable(); mapping.put("Chuk", CHUK); mapping.put("Gregg", GREGG); } Then, we'll add them both, rather than just one: public DemoGraphScene() { mainLayer = new LayerWidget(this); addChild(mainLayer); //Here we create our two evangelists: addNode("Chuk"); addNode("Gregg"); getActions().addAction(editorAction); } We'll need to rewrite our earlier method just a bit, so that it is more generic, because now it will have to handle both Chuk and Gregg: @Override protected Widget attachNodeWidget(Object node) { Image image = (Image) mapping.get(node); if (image != null) { return createNewWidget(node, image); } throw new IllegalArgumentException(node.toString()); } And we move all the code from the previous implementation of the above method to a new one: protected Widget createNewWidget(Object label, Image image) { IconNodeWidget widget = new IconNodeWidget(this); widget.setImage(image); widget.setPreferredLocation(new Point(10, 20)); widget.setLabel(label.toString()); widget.getLabelWidget().getActions().addAction(editorAction); widget.getActions().addAction(ActionFactory.createMoveAction()); mainLayer.addChild(widget); return widget; } Run the app again and now you'll have two evangelists in your "scene", instead of just one, with the same properties because they're both the same widget, as you can see from the code above: You might now think about connecting them together, which we can look at in a future article. In general, there's a lot more that can be done, of course, and the documentation on all of this goes into it all. Here's the homepage of the library. I also highly recommend Fabrizio Giudici's Creative use of the NetBeans Visual Library: the Light Table. In summary, you don't even need to like NetBeans IDE to benefit from its graph library. Just download the IDE, get the two JARs specified above, and then add them to your classpath. That's all. And then code in whatever IDE has your preference.
January 29, 2008
by Geertjan Wielenga
· 198,430 Views · 1 Like
article thumbnail
From Java to Groovy in a Few Easy Steps
Groovy and Java are really close cousins, and their syntaxes are very similar, hence why Groovy is so easy to learn for Java developers.
January 27, 2008
by Guillaume Laforge
· 121,778 Views · 3 Likes
article thumbnail
3D Model Interaction with Java 3D
This tutorial is based on a computer graphics assignment for which i was given the task of creating an application in which some articulated animal would walk using a hierarchical model. I had 4 days to complete this assignment, so i had to learn java 3d quickly, but i ended up having to read fragmented documentation, mostly focused on theory i already knew, with practical examples that were either too simple or too complex. The objective of this tutorial is to provide a guide for writing a basic java 3d application with a 3d model loaded from disk; it's less generic than the official java3d application tutorial and less focused on theory than other tutorials, but more straightforward for the experienced java developer who already knows basic cg theory and just wants to know what goes where very quickly - going deeper in the APIs is up to you. Requirements JDK version 1.5 or above (the examples use java 5 features) java 3d version 1.4 or above installed experience with jfc basic computer graphics knowledge (3d transforms, illumination types) a 3d model visualizer, like poseray a 3d model converter like 3dwin will be useful if you find some interesting 3d model in a format not supported by any java 3d loader Models You can download free 3d models on websites like turbosquid or the 3d archive . Free models may not have the quality you are looking for, so if you are on a serious/commercial project, you should probably consider purchasing a quality model. If you really want to model your objects you can try blender. Visualizing the model I will use a cockroach I downloaded from the 3d archive. You can choose another model if you will as long you know what you're doing. I will use poseray to visualize the model. Poseray cannot open every 3d format, so if the format of your model is not supported by poseray, you will have to use some other program like 3dwin to convert it to a format poseray accepts. poseray is actually intended to work with moray and povray, but it works very well for the purpose of viewing 3d models. 1. load the model 2. check the model (shot #1) 3. check the model (shot #2) 4. check how this model is branched These are the pieces that form the complete model. you will have to analyze how your model is branched to see if you can animate or interact with it as you plan. Every component of the model has a name - let it be the parts of your main subject or just other components from the scene. You can get these names on your program, but it's easier to check which part is which here. you can use the update function if the names aren't descriptive enough. You will need to know the name of every part if you plan to texturize or animate them independently. In the end, all that matters is that you save your file in a format that java loaders will recognize. preferably, save it in the wavefront .obj or lightwave . LWO format because java 3d comes with loaders for these file formats by default. Other loaders are available, but you will have to download them separately. Other java3d loaders Loading the model Wavefront .obj format import java.io.filereader; import java.io.ioexception; import com.sun.j3d.loaders.scene; // contains the object loaded from disk. import com.sun.j3d.loaders.objectfile.objectfile; // loader of .obj models public static scene loadscene(string location) throws ioexception { objectfile loader = new objectfile(objectfile.resize); return loader.load(new filereader(location)); } Lightwave .lwo format import com.sun.j3d.loaders.lw3d.lw3dloader; // loader of .lwo models public static scene loadscene(string location) throws ioexception { lw3dloader loader = new lw3dloader(); return loader.load(new filereader(location)); } Recommended reading: objectfile javadoc , lw3dloader javadoc . Basic setup Now that you know how to load the model let's see how it will look on your program before proceeding to further manipulation. the most important class of this example is the simple universe, which saves you from having to configure the view of your scene. a directional light is added to allow you to view your object (no light and you will see a plain black). You can view the source in . Roach as seen on the example program Recommended reading: simpleuniverse javadoc Getting the scene components We need to obtain a reference to every body part we need to manipulate (or just scene component, if you are not using a model of an animal). If you want to create a variable for every component and assign a meaningful name to each one, you will have to know what name maps to what component. the following piece of code demonstrates how to list the name of every named object from the scene: import javax.media.j3d.shape3d; void listscenenamedobjects(scene scene) { map namemap = scene.getnamedobjects(); for (string name : namemap.keyset()) { system.out.printf("name: %s\n", name); } } Have in mind that every shape3d is already part of the branchgroup of the scene, you have loaded. If you want to create another graph with your custom hierarchy, you will have to get a reference to one specific shape3d and then remove it from the branchgroup : import javax.media.j3d.branchgroup; /* obtains a reference to a specific component in the scene */ shape3d eyes = namemap.get("eyes"); /* the graph that still contains a reference to "eyes" */ branchgroup root = scene.getscenegroup(); /* removes "eyes" from this graph */ root.removechild(eyes); /* now you are free to use "eyes" in your custom graph */ Always remember you cannot add a component to more than one graph. If one component is already part of a graph and you try to add it to another, you will get a multipleparentexception. If you need the same component in more than one graph, you can clone them. Transformations Basic transformation steps: Add the parts you want to transform to a transformgroup ; Apply the transformgroup.allow_transform_write capability to the group if it wasn't set; Create or use some previously created instance of transform3d ; Configure this instance of transform3d as / if necessary; Apply this transform3d instance on the transformgroup instance. That implies you will have to keep references to instances of these classes in order to transform specific nodes of your graph. The following piece of code demonstrates translation, rotation on multiple axis and non-uniform scaling. It uses code created on previous sections. import javax.vecmath.vector3f; import javax.vecmath.vector3d; import javax.media.j3d.transformgroup; import javax.media.j3d.transform3d; map namemap = scene.getnamedobjects(); /* get the node you want to transform */ shape3d wing = namemap.get("wing"); /* add it to a transformgroup */ transformgroup transformgroup = new transformgroup(); transformgroup.addchild(wing); /* necessary to allow this group to be transformed */ transformgroup.setcapability(transformgroup.allow_transform_write); /* accumulates all transforms */ transform3d transforms = new transform3d(); /* creates rotation transforms for x, y and z axis */ transform3d rotx = new transform3d(); transform3d roty = new transform3d(); transform3d rotz = new transform3d(); rotx.rotx(15d); // +15 degrees on the x axis roty.roty(30d); // +30 degrees on the y axis rotz.rotz(-20d); // -20 degrees on the z axis /* combines all rotation transforms */ transforms.mul(rotx, roty); transforms.mul(transforms, rotz); /* translation: translates 2 on x, 3 on y and -10 on z */ vector3f translationvector = new vector3f(2f, 3f, -10f); transforms.settranslation(translationvector); /* non uniform scaling: scales 3x on x, 1x on y and 2x on z */ vector3d scale = new vector3d(3d, 1d, 2d); transforms.setscale(scale); /* apply all transformations */ transformgroup.settransform(transforms); Recommended reading: transform3d javadoc , transformgroup javadoc Hierarchical model Now that you have access to all components separately, you can build your custom hierarchical graph. If you have been using swing or awt, you are already familiar with the hierarchical model. for instance, you can have a jframe , which then adds a jpanel , which then adds a jlabel and so forth. Many properties applied on the root are propagated to children, like the isvisible() property. With a 3d model, all transforms and texturizations will be applied to all children (subgraphs). imagine if you had to apply the same transform over and over to many model parts just to make one movement? Java 3d has a class called group , which is basically an n-tree: every children has only one parent and an arbitrary number of children. you will use subclasses of group to create your scenes. java 3d has also the leaf class, which is used to construct objects on the tree which wouldn't make sense with children, like background, camera, behaviour, etc. hierarchical model of the scene I will use the transformgroup class as the default node for building the graph. you may use other subclasses of group if you have other needs. You may want to keep a reference of every transformgroup you create if you are going to do some interaction (like making a cockroach walk). Note that the code above suffers from the same flaws of programatic gui construction. you can define the graph in xml and create a custom parser if you need reusability. if possible, you can also edit the model graph in a model editor to avoid having to perform these steps on your program. Hierarchical construction of the graph transformgroup getcockroach(scene scene) { /* obtain the scene's branchgroup, from which components are removed */ branchgroup root = scene.getscenegroup(); map namemap = scene.getnamedobjects(); /* remove all children (you don't want a multiparentexception) */ root.removeallchildren(); /* construct the groups */ transformgroup leftlegs = new transformgroup(); transformgroup rightlegs = new transformgroup(); transformgroup body = new transformgroup(); transformgroup roach = new transformgroup(); /* build the graph --> left legs */ leftlegs.addchild(namemap.get("luplegf")); leftlegs.addchild(namemap.get("luplegm")); leftlegs.addchild(namemap.get("luplegr")); leftlegs.addchild(namemap.get("lmidlegf")); leftlegs.addchild(namemap.get("lmidlegm")); leftlegs.addchild(namemap.get("lmidlegr")); leftlegs.addchild(namemap.get("llowlegf")); leftlegs.addchild(namemap.get("llowlegm")); leftlegs.addchild(namemap.get("llowlegr")); leftlegs.addchild(namemap.get("lfootf")); leftlegs.addchild(namemap.get("lfootm")); leftlegs.addchild(namemap.get("lfootr")); /* build the graph --> right legs */ rightlegs.addchild(namemap.get("ruplegf")); rightlegs.addchild(namemap.get("ruplegm")); rightlegs.addchild(namemap.get("ruplegr")); rightlegs.addchild(namemap.get("rmidlegf")); rightlegs.addchild(namemap.get("rmidlegm")); rightlegs.addchild(namemap.get("rmidlegr")); rightlegs.addchild(namemap.get("rlowlegf")); rightlegs.addchild(namemap.get("rlowlegm")); rightlegs.addchild(namemap.get("rlowlegr")); rightlegs.addchild(namemap.get("rfootf")); rightlegs.addchild(namemap.get("rfootm")); rightlegs.addchild(namemap.get("rfootr")); /* build the graph --> remaining body */ body.addchild(namemap.get("antena")); body.addchild(namemap.get("antenar")); body.addchild(namemap.get("wing")); body.addchild(namemap.get("abdomen")); body.addchild(namemap.get("head")); body.addchild(namemap.get("prothorx")); body.addchild(namemap.get("eyes")); body.addchild(namemap.get("lpalp")); body.addchild(namemap.get("rpalp")); /* build the graph --> roach */ roach.addchild(leftlegs); roach.addchild(rightlegs); roach.addchild(body); /* enable transform capability (it is not enabled by default) */ enabletransformcapability(leftlegs, rightlegs, body, roach); return roach; } void enabletransformcapability(transformgroup... parts) { for (transformgroup part : parts) { part.setcapability(transformgroup.allow_transform_write); } } Note that i have declared the transform groups locally, but on your program you will have to declare them globally or keep a reference to them somewhere if you plan to add interaction to your model. we will configure the camera (actually a view) and add lights . I did a fairly simple hierarchy because the movement this cockroach will do is just as simple. in my assignment i had to do an interaction in which the legs would articulate, which implied in a different (i.e. more complex) setup for the hierarchy of the legs. Appearance The loaded cockroach is quite pale since no material descriptors were associated with it, but this is not a problem, as you can define your textures for each component of your graph. you must read the material javadoc to understand what is being done here. To save some effort, I will declare some constants for ambient, emissive and specular light colors. the user may choose the diffuse color - the light which is emitted when the object is under the influence of some light. import javax.vecmath.color3f; private static final color3f specular_light_color = new color3f(color.white); private static final color3f ambient_light_color = new color3f(color.light_gray); private static final color3f emissive_light_color = new color3f(color.black); Now you can create a method that returns an apperance based on a given color : import javax.media.j3d.material; import javax.media.j3d.appearance; appearance getappearance(color color) { appearance app = new appearance(); app.setmaterial(getmaterial(color)); return app; } material getmaterial(color color) { return new material(ambient_light_color, emissive_light_color, new color3f(color), specular_light_color, 100f); } It's possible to use an image as a texture, but there are some constraints: the image must be equal in width and height and must be a power of 2. If you have ever used swing, you know you have to pass an instance of component to mediatracker if you want to track the loading of an image. loading a texture uses a similar process: import javax.media.j3d.texture2d; import com.sun.j3d.utils.image.textureloader; appearance getappearance(string path, component canvas, int dimension) { appearance appearance = new appearance(); appearance.settexture(gettexture(path, canvas, dimension)); return appearance; } texture gettexture(string path, component canvas, int dimension) { textureloader textureloader = new textureloader(path, canvas); texture2d texture = new texture2d(texture2d.base_level, texture2d.rgb, dimension, dimension); texture.setimage(0, textureloader.getimage()); return texture; } Applying the material: scene cockroach = getscenefromfile("roach_mod.obj"); map namemap = cockroach.getnamedobjects(); color brown = new color(165, 42, 42); appearance brownappearance = getappearance(brown); namemap.get("wing").setappearance(brownappearance); a material responds to different light positions As far as I've tested, if you assign a texture instead of a material, the object will not respond to different light configurations, instead, it will look like being constantly illuminated. roach with a texture Lights As you have seen, we still need to add two lights and one camera (a view). if you have read the , you have seen a directional light being added to the root of the scene. it's interesting to make the light go with the roach wherever it goes if you don't want it to get completely black after walking out of the reach of the light - in this case you will need to add your lights as leafs on the same node which contains the object you want to illuminate. On the other hand, if you want your object to become shadowed as it moves, you should add the lights to a node other than the one you used to add the model. Except from finding the right vector to point the light to your object, creating and configuring lights is mostly simple. the following figure demonstrates how to construct an ambient light and a directional light: import javax.media.j3d.directionallight; import javax.media.j3d.ambientlight; color3f directionallightcolor = new color3f(color.blue); color3f ambientlightcolor = new color3f(color.white); vector3f lightdirection = new vector3f(-1f, -1f, -1f); ambientlight ambientlight = new ambientlight(ambientlightcolor); directionallight directionallight = new directionallight(directionallightcolor, lightdirection); bounds influenceregion = new boundingsphere(); ambientlight.setinfluencingbounds(influenceregion); directionallight.setinfluencingbounds(influenceregion); Why do you need an influence region? for the same reason you need clipping: to avoid doing useless calculations. see the light javadoc for more information. camera If you want to view your scene on different angles, you will need a camera. java 3d uses a view based model - there are no camera objects, but a viewplatform object. Whenever you want to change the view of your scene, all you have to do is to change parameters on the viewplatform object. If you are using simpleuniverse to facilitate the view configuration of your program, you don't need to add any viewplatform instance to the root node because simpleuniverse has already added that for you. the viewplatform created by simpleuniverse is inside a multitransformgroup , which you can obtain via view ing platform . The following code demonstrates how to obtain this multitransformgroup and use it to change the view of the scene: import com.sun.j3d.utils.universe.viewingplatform; /* you don't have to create a viewingplatform if you are using simpleuniverse */ viewingplatform vp = universe.getviewingplatform(); /* you don't need to add the vp to a transformgroup because the vp is already added in a multitransformgroup; 0 is the topmost transformgroup */ transformgroup vpgroup = vp.getmultitransformgroup().gettransformgroup(0); /* you can transform the view platform as you do with other objects */ transform3d vptranslation = new transform3d(); vector3f translationvector = new vector3f(1.9f, 1.2f, 6f); vptranslation.settranslation(translationvector); vpgroup.settransform(vptranslation); example: translation vectors used on the viewplatorm 0.0, -1.2, 6.0 1.9, 1.2, 6.0 0.0, 1.2, 6.0 -1.9, 1.2, 6.0 Do not confuse viewplatform with view ing platform - the latter is a convenience class used to "set up the view side of the graph" - it contains a viewplatform . Recommended reading: viewingplatform javadoc , viewplatform javadoc Background Unless you want your background to be plain black, you should specify one. just remember to always add the background to the root node of your scene; add it anywhere else and you will get an undesirable illegalsharingexception . color background import javax.media.j3d.background; /* a dull gray background */ background background = new background(new color3f(color.light_gray)); /* incluencregion is a boundingsphere. see the "lights" section for details */ background.setapplicationbounds(influenceregion); /* root is a branchgroup, root node of your scene object */ root.addchild(background); Image background textureloader t = new textureloader("leaves.jpg", canvas); background background = new background(t.getimage()); background.setimagescalemode(background.scale_repeat); // tiles the image background.setapplicationbounds(influenceregion); root.addchild(background); This static background is quite boring. If you are looking for something more interesting, such as a celestial sphere, you should use apply a geometry to a background. you can find examples on java2s website. Recommended reading: background javadoc Interacting with the model Now it's time to use the transformgroup references you've kept a while ago. You will use them to control the movement of the model. The cockroach will do a very silly movement: the left legs will move forward while the right legs stand still, then the right legs move forward while left legs stand still; the body will always move a little bit forward on every movement. it's far from realistic, but you can derive more complex movements if you learn this one. (if you're concerned, as far as my assignment, the movement was more complex than that...) the class behavior will be used to interact with the model. The behavior class is like a listener - you have to implement it to achieve the desired reaction. It has to be activated every time it's used, or it won't react to the next stimulus . The stimulus used on this section will be a key press, but you can use many others - check wakeupcriterion 's direct known subclasses to check for other options. After implementing your behavior subclass, all you have to do is to add it on the node you want to animate. Instance variables /** groups that will be animated. */ transformgroup[] groups; /** used to transform the groups you will animate. */ transform3d[] transforms; /** used to translate the groups you will animate. */ vector3f[] translations; /** type of event for which groups will react. */ wakeuponawtevent wake; /** increments 1 every time the user hits a key. */ int hitcount; /** decides which group will be animated based on the hitcount. */ int bodypartindex; Constructor simpletripodmovement(transformgroup... groups) { this.groups = groups; // you can add a groups count security check if you will wake = new wakeuponawtevent(keyevent.key_pressed); // you decide which key later translations = new vector3f[groups.length]; transforms = new transform3d[groups.length]; for (int i = 0; i < groups.length; i++) { translations[i] = new vector3f(0f, 0f, 0f); transforms[i] = new transform3d(); } } Implementation of initialize public void initialize() { // overriden method wakeupon(wake); // inherited method } Implementation of processstimulus public void processstimulus(enumeration enumeration) { keyevent k = (keyevent) wake.getawtevent()[0]; /* moves only if the key pressed is the right directional key and if the hit count is a multiple of 4 */ if ((k.getkeycode() == keyevent.vk_right) && (hitcount++ % 4 == 0)) { /* selects the body part to be moved */ bodypartindex = (bodypartindex + 1) % 3; /* moves 0.1 on z axis */ translations[bodypartindex].set(translations[bodypartindex].x, translations[bodypartindex].y, translations[bodypartindex].z + 0.1f); transforms[bodypartindex].settranslation(translations[bodypartindex]); groups[bodypartindex].settransform(transforms[bodypartindex]); } /* if you don't put it here, it won't respond the next time you press a key */ wakeupon(wake); } Applying the behavior /** * adds a simple tripod movement to the given roach. * * @param parts parts that will be animated * @param roach supernode of parts * @param bounds world bounds, the smae used for lighting */ void addbehavior(transformgroup[] parts, transformgroup roach, bounds bounds) { behavior behavior = new cockroachbehavior(parts); /* behavior will not work if you don't set the scheduling bounds! */ behavior.setschedulingbounds(bounds); roach.addchild(behavior); } As you have probably noticed, this class is tightly coupled with the objects it animates, but that is predictable; from behavior 's javadoc: the application must provide the behavior object with references to those scene graph elements that the behavior object will manipulate. The application provides those references as arguments to the behavior's constructor when it creates the behavior object. alternatively, the behavior object itself can obtain access to the relevant scene graph elements either when java 3d invokes its initialize method or each time java 3d invokes its processstimulus method. Recommended reading: behavior javadoc Resources cockroach object [you may have to convert it] cockroach wings texture cockroach head texture ground texture leaves background source code [you will need to download the model separately] executable jar [you will need to download the model separately] executable jar + model complete project [src + resources] References java3d javadoc com.sun.j3d.* packages javadoc java3d application tutorial from sun a basic hierarchical model of the top part of a human torso
January 26, 2008
by Dalton Filho
· 65,032 Views
article thumbnail
Class Loading Fun with Groovy
Sometimes you need special measures. Not to make Groovy work, but to make your applications or frameworks a little bit more powerful or versatile.
January 17, 2008
by Steven Devijver
· 42,897 Views · 1 Like
article thumbnail
Ruby On Rails: Change Class Name Into Human Readable String
This turns a class name (like LineItem) into a nice string (like "line item") line_item = LineItem.new puts line_item.class.name.underscore.humanize.lowcase #spits out "line item"
January 9, 2008
by Chris O'Sullivan
· 7,145 Views
article thumbnail
Get All Classes Within A Package
The code below gets all classes within a given package. Notice that it should only work for classes found locally, getting really ALL classes is impossible. /** * Scans all classes accessible from the context class loader which belong to the given package and subpackages. * * @param packageName The base package * @return The classes * @throws ClassNotFoundException * @throws IOException */ private static Class[] getClasses(String packageName) throws ClassNotFoundException, IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; String path = packageName.replace('.', '/'); Enumeration resources = classLoader.getResources(path); List dirs = new ArrayList(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); dirs.add(new File(resource.getFile())); } ArrayList classes = new ArrayList(); for (File directory : dirs) { classes.addAll(findClasses(directory, packageName)); } return classes.toArray(new Class[classes.size()]); } /** * Recursive method used to find all classes in a given directory and subdirs. * * @param directory The base directory * @param packageName The package name for classes found inside the base directory * @return The classes * @throws ClassNotFoundException */ private static List findClasses(File directory, String packageName) throws ClassNotFoundException { List classes = new ArrayList(); if (!directory.exists()) { return classes; } File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) { assert !file.getName().contains("."); classes.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); } } return classes; }
November 30, 2007
by Victor Tatai
· 124,600 Views · 7 Likes
article thumbnail
Javascript Sprintf
September 19, 2007
by Snippets Manager
· 468 Views
  • Previous
  • ...
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×