Monday, September 5, 2011

Setting up a List for tile selection within the dungeon editor

The mission on this run was to create and install a list of tiles to the user on the map designer. These tiles represent the tiles that can be used to edit the map on the display.

The list in question is build, specifically, to be used in conjunction with the display made during the last run (see the most recent blog), so it would have to be displayed convieniently on the same form as the map editor display.

The actual functionality of this component was not a goal of this coding run, simply to create a list that displayed the tiles in a desirable way, and to get it onto the display form in a convienient, extensible fashion.

The first step was to figure out how to create a list whose style I could control. After a little reasearch looking up the javadoc for JList http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JList.html

it only took a minute to the contraption that Sun/Oracle had designed to allow coders to accomplish the very task I set out to do. I simply had create a new class to act as the cell renderer for this list.

While the JList object is complicated, and has layers of controls deeper than what's needed here, one needed only to grasp how the JList organizes its data, as well as how it displays that same data. Here is the essential breakdown of the JList, for purposes of this task: displaying customized data in a sane, rational way.

The JList basically uses an internal data structure that can use any type of Object as it's data member - of course, each of these data members must be of the same type - but as long as they derive from Object (duh), you're golden.

After loading in your objects (which can be done in the JList constructor, feeding in a simple Object[]), all that remains is to create the JList's cell renderer to interpret these objects in whatever way pleases you.

The following describes the procedure used for accomplishing this task, as well as displaying the new list on the main display:

EXTEND JLIST

By simply extending JList into a new class (RHD_TileList), a space was created to create the cell renderer, exclusive to this list, and add any other specialized members or methods for this specifiic list. It also allowed for customized stylization of the list itself, within the constructor body.

Next, within the RHD_TileList class, and Inner Class was created that implemented ListCellRenderer (the object responsible for turning each data item in the JList into a selectable display item) and extended JLabel. JLabel was used as an extension to simply display within the list - this will be explianed in more detail shortly.

The ListCellRenderer uses only one method that must be overwritten, public Component getListCellRendererComponent(), which returns the Component which will be used to represent each given list item. This method is called once for each object within the JList, so the code within this method must be able to generate Components dynamically based on their content.

JLabel was extended into ListCellRenderer because this made it easy to generate the entire Component within the context of JLabel (an ideal Component model for display on a list), and then return 'this' to the JList when finished.

Because of the way this method was designed, it is possible to know whether or not the list is enabled, the list-item in question is selected by the user, as well as having access to the parent list itself and the object representing the data.

Here, with full documentation, is the code used to represent this new extension of JList:

/** * A specialized JList offering a selection of tiles to the user * for map making. * * @author timon */ public class RHD_TileList extends JList{ /** * CONSTRUCTOR (default) * * Makes a call to parent (JList) */ public RHD_TileList() { super(); init(); } /** * CONSTRUCTOR * * Makes a call to parent (JList), and loads in the array of tiles * as the data. * * @param tiles * An array of tiles */ public RHD_TileList(Tile[] tiles) { super(tiles); init(); } private void init() { setCellRenderer(new TileListCellRenderer()); setEnabled(true); setFont(new Font("Arial", Font.PLAIN, 11)); setPreferredSize(new Dimension(150,400)); setBackground(Color.WHITE); setBorder(new LineBorder(Color.black)); } class TileListCellRenderer extends JLabel implements ListCellRenderer { @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { // Get the tile from the parameters Tile tile = (Tile) value; ImageIcon icon = new ImageIcon(); // The display icon //Get the display name from the tile String displayMessage = tile.getTileName(); // Get the icon from the tile try { icon = (ImageIcon) FileBroker.readTileIcon(tile.getImagepath()); } catch (IOException ex) { } // Set the displayed text setText(displayMessage); // Set the displayed icon setIcon(icon); // Enable this selection setEnabled(list.isEnabled()); // Draw a border according to this item's selection status if (isSelected) { // Set blue border around selected item setBorder(new LineBorder(Color.blue)); // Set background to blue highlight on selected item setBackground(new Color(220,220,235)); } else { // Set border to match list background on un-selected item setBorder(new LineBorder(list.getBackground())); // Set background to match list background on un-selected // item setBackground(list.getBackground()); } // Share the same font with the rest of the list setFont(list.getFont()); // Set the preferred size of the list as a display setPreferredSize(new Dimension(100,20)); // Set opacity to true to allow background colors to take hold setOpaque(true); // Return this item back to the list manager return this; } } }

Finally, in terms of placing this new List on the designer display, it was decided that a new Tab Panel would be placed to the right of the map editor on the same form. A blank panel was added to the tab panel, creating a new 'tab page' (NetBeans knows to do this automatically). Within this tab page, I placed a JScrollPane.

After this point, there was an attempt to extend the list into a bean, and then place that Tile List Bean within the scroll pane. After complications and time consumption that came with waiting for the bean to load, inappropriate settings, etc, a change in plan was made, and probably for the better.

It was very simple just to use the JScrollPane.setViewportView(Component view) method, for both initialization and updating. An extra method was added to the designer: public void loadTileList(Tile[] tiles). Another method was added to the state manager (in charge of delegating commands througout the Map Designer): public static void loadAvailableTiles(Tile[] tiles). Now with these methods, the state manager can be called from anywhere and load in a new set of tiles into the program memory, and hence into the list being displayed on the designer.

After these updates, a new test start garnered the following visual results:

The new list can be seen within the tab panel labeled "Basic" on the right of the map designer display.

No comments:

Post a Comment