Using XNA DrawableGameComponent
Apr 8th
This post is for those thinking about using the DrawableGameComponent class in the XNA framework.
I am going to demonstrate how you might use the class by using the example of dice.

Project Files
Download Dice.zip for the Visual Studio Express 2005 XNA 2.0 project files. Extract the zip, then run Dice.csproj to open the project in VSE 2005. You can then just compile the project by pressing the play icon.
DrawableGameComponent
Dice are ideal for illustrating the DrawableGameComponent class because dice, even in the real-world, are reusable across many table games, and that’s really where DrawableGameComponent comes in handy.
The DrawableGameComponent provides the developer a nice structured way to create modular, self-contained and reusable game components. A component should by definition be able to be dropped into a game and with minimal wiring up, just work.
Understanding the Source
The way in which to use DrawableGameComponent is to extend it. By doing this, when we add our component to the game, the XNA framework will know how to call it properly.
The Dice class therefore is made to extend DrawableGameComponent. The constructor for DrawableGameComponent requires the Game instance to be passed, so we need to ensure our component class constructor receives the game instance in addition to any specific variables so that it may pass the game instance on to the superclass for instantiation.
In essence when creating a component, you will want to override 3 of the methods of the DrawableGameComponent superclass; LoadContent, Update and Draw. For beginners, LoadContent is a method in which we instantiate resources like graphics and sounds, Update is used to update game logic (and this is done per game loop cycle – which is fast), and Draw in which we paint stuff to the screen.
You will see in the Dice class that I have overridden these 3 methods using the override keyword in the method declarations. Each of these methods as their last statement call the superclass’s version of the method to ensure the component is fully called.
A die has 6 faces, so I added 6 graphics files to represent each face of a die. These are added to the Content folder in the project. As such, within LoadContent, I am able to load them as Texture2D files.
A separate Die class represents a single die since the actual Dice class supports as many die instances as you want. In practice this will be 1 or 2, but hey, it’s all about extensibility!
The Die class contains a method for rolling the single die. It uses a static instance of Random to roll a random face between 1 and 6.
The Dice class also contains some logic methods. Roll iterates all the die instances and calls their Roll methods. And Total returns the sum of all die instance faces at the time of call.
Using the Dice Component
To use the Dice component, we need to add it to our main game instance. In Game1 we just have to add an instance of Dice to the Game.Components collection. Simple as that.
By doing this, each game update tick, the Dice component’s Update and Draw methods are called.
The Dice.Update method monitors the keyboard for presses of the Space Bar. This triggers a roll of the active die instances.
Dice.Draw draws the relevant Texture2D graphics for the active die instances.
In the project, I just draw out each die next to each other.
Keep pressing Space Bar and you will see the dice change as you roll them.#
Final Words
I hope this article was of use to some of you, particularly those starting out with XNA. The DrawableGameComponent method of encapsulating game logic is a really good pattern to follow.
Some of you may be wondering though – since the Dice class is constantly monitoring the Space Bar, when you add that to a real game, where you would want to block dice rolls until certain other events take place – how do you do that?
Well, you’d need additional wiring in that case. One idea might be to maintain a flag CanDiceRoll for example in the main game. The Dice.Update method would need to use a conditional block based on that flag to determine if it should roll. Suggestions from readers are welcome.
Dynamic PDF generation with JasperReports, Struts and a database
Oct 15th
Generating a dynamic PDF from a database with JasperReports and Struts
A requirement appeared recently as part of a Purchase Ordering application to allow a user to dynamically generate a PDF copy of the final Purchase Order to send to the supplier. Taking a look around I stumbled rather fortunately upon an API called JasperReports (JR). JasperReports is a powerful open source Java reporting tool that has the ability to deliver rich content onto the screen, to the printer or into PDF, HTML, XLS, CSV and XML files. This tutorial is aimed at the beginner JR user who is happy with J2EE web application development. It will show you how JR was used to deliver the requirement described and should convince you that it is a truly fantastic piece of kit.
What we will be doing in 1 sentence
You will define a report template using JR’s XML syntax and then bind data from a database into it and get a PDF sent back to a web browser.
What will I need
OK, you need a few bits of kit. Firstly, I hate to break it to you but I kind of cheated with defining the report template. See, thing is, you can write this manually, but I didn’t have time to learn the ins and outs of JR’s XML syntax, so I got hold of JasperAssistant, a brilliant Eclipse IDE plugin that allows a developer to visually draw their report for JR. If like me you use Eclipse, or indeed you just want to use this method for creating your report template, grab Eclipse and JasperAssistant. There is also another tool called iReport that does a similar thing without Eclipse but you’ll need to look at that yourself. So, you will need
- JasperReports – head to the Download section
- Either JasperAssistant, iReports OR a willingness to learn the JR XML syntax for which there are many examples with the JR distribution. Whichever method you chose, I leave it to you to configure the environment – full instructions are available on each site.
- A knowledge of J2EE web application development. In this tutorial I shall be using Struts but only in the slightest way to illustrate how to send the PDF back to the web user. You can do the same stuff with a plain old Servlet.
Creating the report template
First of all, you need to think about what data your report needs to show. In my scenario, we are talking about a Purchase Ordering application. In this application is the master object called PurchaseOrder. A PurchaseOrder has at least one or more LineItem stored in a list collection. Each of these 2 objects have other attributes that reveal information, e.g the PuchaseOrder has a createdDate and orderId whereas a LineItem has a description and unitCost. These objects are persisted to a database. It is not really important how, it may be via a series of SQL statements or it may be via some Object Relational Mapping API such as Hibernate (which for the record, is how I have done it), but what matters is that you have code in place to save and fetch your particular application objects/data. Now, my report layout requires that the header contain master detail such as the created date and order id and then to list all the line items in a table below. Finally, some more master detail such as delivery address is required at the foot. JR divides up a report into a series of stacked bands from top to bottom, e.g title, header, detail and footer are names of some bands. In my case, I chose to use the header, detail and footer bands for the areas I have just mentioned.
Parameters, fields and static text
Using JasperAssistant, I was able to draw my report layout using guides and properties boxes. You may do the same or do it manually, but the main elements that I had to use were parameters, fields and static text. JR has a mechanism for binding a Map of data to a report. This is referred to as a parameter map. The idea being that the map element’s key is used for binding the map element’s value to the parameter defined in the report. For example, if I have an empty report with a parameter declaration orderId as follows:
http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
then I would need a corresponding Map
Map map = new HashMap(); map.put(orderId, "12345");
I will show how you can bind this to the report later. In addition to the parameter map mechanism, you can also use something called a DataSource. You musn’t think a DataSource is a database necessarily like it is with an application server. A DataSource is an object that provides methods that can be called by the report in obtaining rows of data. For my purposes if you remember, I have a collection of LineItem elements inside my PurchaseOrder and I need to loop through them outputting to a table in my report. The way I achieved this was by implementing JR’s DataSource interface JRDataSource. This interface requires an implementation provide methods;
public boolean next() throws JRException; public Object getFieldValue(JRField field) throws JRException;
In your report, you must define fields in the detail band. When the report is run together with the custom implementation, JR will automatically keep calling next and then attempt to bind each field in the detail band to a call to getFieldValue(JRField field).
Since my implementation of JRDataSource will return operation on a collection of LineItem I have named my DataSource LineItemDataSource. It has 2 class variables; private List data; private int index; Which is an internal data List to use (which I will populate with LineItem objects later), and the index allows us to know at which position we are in iteration of the List. That’s why you need to use List, because it is indexed and has methods for getting elements at certain indexes.
I also have an add(LineItem lineItem) for adding LineItem objects. Now, the implementation of next is quite simple:
public boolean next() throws JRException {
index++;
return (index < data.size());
}
I increase the index by 1, and then return a boolean as to whether the index is still within the List’s bounds. JR will use this to determine if any more binding to fields in the detail band is required. Finally, the implementation of getFieldValue. First, let’s show you how to define iterating fields in your report template. You need to define fields in your detail band like this:
< ![CDATA[$F{getItemName}]]> < ![CDATA[$F{getItemCost}]]>
The detail band is iterated over using the custom DataSource implementation which I will show you in a moment. What is important is that you declare your textField elements along with their child textFieldExpression elements. The textFieldExpression tells the JR binding process what fields (by name) to look for in the DataSource. You can call these whatever you like, but as you can see in my case, I have decided to call them getXXX like a traditional bean accessor. Why have I done this? Well, because my LineItem object has matching accessor methods. So now let’s return to the custom DataSource implementation of getFieldValue. Here is the full listing:
public Object getFieldValue(JRField field) throws JRException {
LineItem lineItem = (LineItem) data.get(index);
Object value = null;
try {
Object[] args = {};
Class[] paramTypes = {};
Class lineItemClass = lineItem.getClass();
Method getMethod = lineItemClass.getDeclaredMethod(field.getName(), paramTypes);
value = "" + getMethod.invoke(lineItem, args);
} catch (Exception e) {
throw new JRException(e.getMessage());
}
return value;
}
Clever huh? You don’t have to do it like this, but I have decided to use Java Reflection in order to dynamically call the appropriate LineItem method for the JRField parameter. That is why I named my textFieldExpression elements with getXXX. So, now if I were ever to add a new attribute to LineItem that I wanted in my report, I only need add it to LineItem with the accessors, and then into the report. I can leave my custom DataSource alone. One last note, I have defined all my fields as String even through my LineItem has attributes of float, int, Calendar. I am not really bothered that the report uses correct data types, but you can do that if you want, just set it up with your fields.
Putting it all together
So, you have hopefully got an idea about how JR works, particularly for my Purchase Order scenario. You should understand that a report template is defined by you either manually or using an editor like JasperAssistant. You will also appreciate 2 ways in which you can bind data to this report through parameters and fields. Furthermore, you have seen a clever way to use both methods in binding a master object with internal collection of elements to a report template. So now you probably want to see how to get the PDF back to the user. Well, remember that I am using a web application here but you don’t necessarily need to. First of all, I need to load my PurchaseOrder with it’s collection. You can do this however you like. In my case, I use Hibernate to load the object out of the database. PurchaseOrder po = poDAO.load(id); Now, I need to setup a parameter map for the master details
Map parameterMap = new HashMap();
parameterMap.put("orderId", po.getOrderId());
parameterMap.put("createdDate", convertToDateString(po.getCreated()));
parameterMap.put("deliveryAddress", po.getDeliveryAddress());
There are a lot more! But this will do. Finally, I need to add my LineItem collection to my custom DataSource LineItemDataSource
LineItemDataSource lineItemDataSource = new LineItemDataSource(po.getLineItems());
And last of all, let’s setup the response to the browser, and bind the parameter map and custom DataSource.
response.setContentType("application/pdf");
response.addHeader(
"Content-Disposition",
"attachment; filename=PO - " + po.getReference() + ".pdf");
try {
JasperRunManager.runReportToPdfStream( getClass().getClassLoader().getResourceAsStream( "com/mycomp/po/pof.jasper"), response.getOutputStream(), parameters, lineItemDataSource );
} catch (Exception e) {
e.printStackTrace(System.out);
logger.error(e);
}
Right, so I have used just one of the many ways in which you can bind to the report. You will of course need to find out how to compile your report template. When you author your template it is in .jrxml format and this needs to be compiled into a .jasper file which you can do either automatically with JasperAssistant, or manually with bundled tools with JR. In my example here, the compiled report is located in the class struture and I dynamically load it as an InputStream as required by the runReportToPdfStream method.
You should examine the JR API for all the other alternatives including running PDFs to file and even doing HTML output rather than PDF. In an application you would need to use slightly different calls that can be found in the JR API also. Some of you have asked how to send the result direct to the browser. Well, that’s easy – the code above forces a Save to Disk for the PDF by using the content-disposition header, so just comment out the response.addHeader call
/* comment the save to disk feature out so that the pdf goes straight to the browser response.addHeader("Content-Disposition", "attachment; filename=PO - " + po.getReference() + ".pdf"); */
Conclusion
This tutorial has covered some specific aspects of the fantastic JasperReports API that may or may not be suitable for your own projects. I hope if nothing else, it provides an insight into one way of using the API or grounds you in the basics. There is so much more to JR that I have not used myself so take time once you get the idea to look at the bundled examples and API to make sure you are making the right choices.
JasperAssistant was an invaluable piece of kit for this job. It is quite tough getting to grips with the report template XML syntax, especially when your report needs pixel perfect alignment and so fourth. I did not go into a great deal of depth with layout elements like boxes and lines, but I have used them to draw the table boundaries around my detail LineItem band. Good luck, and if this article was helpful or not, leave a comment.
Recent Comments