Hey there.
I'm using a JTable for the first time, and I've read through the Sun and other tutorials, but this simple concept is still confusing me. So I seek help!
Basically; I'm creating a multiplayer (AI-controlled) mining game, which will display maps loaded from XML. I've parsed the XML into a DOM tree, and then parsed that into a Object[][] array. I can load one map fine, and have loaded each of the maps, so I'm sure the issue is with my displaying of the JTable instead of the parsers.
Basically; once I load the initial map on startup I can't load any more - the window size changes, but all cell images stay exactly as they were in the previous map and just become squashed/pulled depending on if the new map is smaller/larger. I imagine this is a simple conceptual problem with how I'm using JTable/Table Models/CellRenderers. If you could point out the obvious, I'd most appreciate it!
Here's the GUI class. The table setting method is at the top, followed by the constructor which creates a blank map and has a file chooser that loads other maps.
package gui;
//Imports the modules used for generating the GUI.
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import mine.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
public class MineInterface extends JFrame implements ActionListener {
Mine mineInstance = new Mine();
private static final long serialVersionUID = 1L;
private File mapFile;
JTable mapTable = null;
MineTableModel tableModel = null;
public JTable newMap(Object[][] map) {
mineInstance.setMap(map); //Sets the mine to use the given map
tableModel = new MineTableModel(map); //Creates a new table model and assigns it the given map
mapTable = new JTable(tableModel); //Creates a new JTable assigned to the table model.
for(int i=0; i<mapTable.getColumnCount(); i++) {
mapTable.getColumnModel().getColumn(i).setCellRenderer(new IconCellRenderer()); //Updates each cell to display its icon
mapTable.getColumnModel().getColumn(i).setWidth(20); //Sets the column width to that of the image icon
mapTable.setRowHeight(20); //Sets the row height to that of the icon
}
mapTable.setTableHeader(null); //Hides the header
this.setSize(mapTable.getColumnCount() * 20,(mapTable.getRowCount() * 20) + 175); //Resizes the window to suit the new map
mapTable.revalidate(); //Revalidates the table display
return mapTable;
}
MineInterface() {
super("Diamond Mine Game");
setSize(625, 400); // initial size
setLayout(new BorderLayout(10, 10)); // sets layout to border style (which sections out the GUI to N/E/S/W and Center).
if (mapTable == null) { //If no previous map exists, creates a blank one (e.g. on startup)
newMap(Mine.createBlankMap());
}
JScrollPane mapScrollPane = new JScrollPane(mapTable);
JPanel optionsMenu = new JPanel();
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem openChooser = new JMenuItem("Load Map");
//Adds the action listener for openChooser which activates a file chooser.
openChooser.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
JFileChooser chooser = new JFileChooser();
//Limits the user choice to text files.
chooser.addChoosableFileFilter(new FileFilter(){
//Overrides the accept method to only allow text files to be selected by the user.
public boolean accept(File f) {
return f.isDirectory() || f.getName().toLowerCase().endsWith(".xml");
}
//Creates a new description for use in the file selection dialog menu.
public String getDescription() {
return "Diamond Mine XML Map Files (.xml)";
}
});
//Shows the open file dialog window.
chooser.showOpenDialog(MineInterface.this);
mapFile = chooser.getSelectedFile();
System.out.println("Loading new map called: " + mapFile.getName()); //For testing, shows the filename being loaded.
System.out.println("Loading new map called: " + mapFile.getAbsolutePath()); //Shows filepath
mapTable = newMap(mineInstance.getMap(mapFile.getName())); //Makes a new map, using the given map file name, and then loads it.
}
});
//Adds the openChooser menu item to the file menu.
fileMenu.add(openChooser);
fileMenu.add(new JMenuItem("Quit")).addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent e) { System.exit(0); }
});
menuBar.add(fileMenu);
optionsMenu.add(menuBar);
add(mapScrollPane, BorderLayout.CENTER);
add(optionsMenu, BorderLayout.NORTH);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
MineInterface display = new MineInterface();
display.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0); // Ends the program
}
});
}
}
Here's the table model I'm using:
package gui;
import javax.swing.table.AbstractTableModel;
class MineTableModel extends AbstractTableModel {
private static final long serialVersionUID = 2L;
private String[] columnNames;
private Object[][] mapData;
MineTableModel(Object[][] map) {
mapData = map; //Assigns the map to the mapData
columnNames = new String[map[0].length]; //Creates an array of the appropriate size
for (int i=0; i<map[0].length; i++) {
columnNames[i] = Integer.toString(i+1); //Column array is then filled with numbers as placeholders.
}
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return mapData.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public boolean isCellEditable(int row, int col)
{ return false; }
public Object getValueAt(int row, int col) {
return mapData[row][col];
}
public void setValueAt(Object value, int row, int col) {
mapData[row][col] = value;
fireTableCellUpdated(row, col);
}
}
And finally here's the cell renderer:
package gui;
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class IconCellRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
ImageIcon img = null;
if (value.getClass() == mine.Rock.class) {
img = new ImageIcon(getClass().getResource("rock.jpg")); //If the cell contains a rock, loads the rock image icon.
}
else if (value.getClass() == mine.Diamond.class) {
img = new ImageIcon(getClass().getResource("diamond.jpg")); //As rock, but for diamond.
}
else if (value.getClass() == mine.Exit.class) {
img = new ImageIcon(getClass().getResource("exit.jpg")); //As rock, but for exit.
}
else if (value.getClass() == mine.ToolStore.class) {
img = new ImageIcon(getClass().getResource("toolstore.jpg")); //As rock, but for the toolstore.
System.out.println("TOOLSTORE is located at: " + "(" + row + "," + column + ")"); //Test purposes, to show if the toolstore is at a different position on the two maps.
}
else {
img = new ImageIcon(getClass().getResource("space.jpg")); //If none of the above, must be a space.
}
setIcon(img); //Sets the icon for the cell to the image specified above.
return this;
}
}
Thanks! :)