views:

2623

answers:

2

I have a function which gets a key from the user and generates a Hashtable (on a pattern specified by the key). After creating a Hashtable, I would like to populate a JTable so that each each column represents a key and every rows represents the values associated with the key. I tried everything but couldn't get this work. I'm not creating the table from within the constructor as I need to get input from the user.

+1  A: 

See How to Use Tables: Creating a Table Model.

The JTable constructor used by SimpleTableDemo creates its table model with code like this:

new AbstractTableModel() {
 public String getColumnName(int col) {
  return columnNames[col].toString();
 }
 public int getRowCount() { return rowData.length; }
 public int getColumnCount() { return columnNames.length; }
 public Object getValueAt(int row, int col) {
  return rowData[row][col];
 }
 public boolean isCellEditable(int row, int col)
  { return true; }
 public void setValueAt(Object value, int row, int col) {
  rowData[row][col] = value;
  fireTableCellUpdated(row, col);
 }
}

You basically have to wrap your hashtable in the above manner. Here's an example.

package eed3si9n.hashtabletable;

import java.awt.BorderLayout;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.JButton;
import java.awt.Dimension;

public class MainForm extends JFrame {

 private static final long serialVersionUID = 1L;
 private JPanel jContentPane = null;  //  @jve:decl-index=0:visual-constraint="23,38"
 private JScrollPane m_scrollPane = null;
 private JTable m_table = null;
 private Hashtable<String, String> m_hash = null;
 private JButton m_btnAdd = null; 

 /**
  * This is the default constructor
  */
 public MainForm() {
  super();
  initialize();
  m_hash = new Hashtable<String, String>();
  m_hash.put("Dog", "Bow");
 }

 private void onButtonPressed() {
  m_hash.put("Cow", "Moo");
  m_table.revalidate();
 }

 /**
  * This method initializes this
  * 
  * @return void
  */
 private void initialize() {
  this.setSize(409, 290);
  this.setTitle("JFrame");
  this.setContentPane(getJContentPane());
 }

 /**
  * This method initializes jContentPane
  * 
  * @return javax.swing.JPanel
  */
 private JPanel getJContentPane() {
  if (jContentPane == null) {
   jContentPane = new JPanel();
   jContentPane.setLayout(new BorderLayout());
   jContentPane.setSize(new Dimension(500, 500));
   jContentPane.setPreferredSize(new Dimension(500, 500));
   jContentPane.add(getM_scrollPane(), BorderLayout.NORTH);
   jContentPane.add(getM_btnAdd(), BorderLayout.SOUTH);
  }
  return jContentPane;
 }

 /**
  * This method initializes m_scrollPane 
  *  
  * @return javax.swing.JScrollPane 
  */
 private JScrollPane getM_scrollPane() {
  if (m_scrollPane == null) {
   m_scrollPane = new JScrollPane();
   m_scrollPane.setViewportView(getM_table());
  }
  return m_scrollPane;
 }

 /**
  * This method initializes m_table 
  *  
  * @return javax.swing.JTable 
  */
 private JTable getM_table() {
  if (m_table == null) {
   m_table = new JTable();
   m_table.setModel(new AbstractTableModel(){
 private static final long serialVersionUID = 1L;

 public int getColumnCount() {
  return 2;
 }

 public int getRowCount() {
  return m_hash.size();
 }

 public String getColumnName(int column) {
  if (column == 0) {
   return "Animal";
  } else {
   return "Sound";
  }
 }

 public Object getValueAt(int rowIndex, int columnIndex) {
  if (columnIndex == 0) {
   return getKey(rowIndex);
  } else {
   return m_hash.get(getKey(rowIndex));
  } // if-else

 }

 private String getKey(int a_index) {
  String retval = "";
  Enumeration<String> e = m_hash.keys();
  for (int i = 0; i < a_index + 1; i++) {
   retval = e.nextElement();
  } // for

  return retval;
 }

   });
  }
  return m_table;
 }

 /**
  * This method initializes m_btnAdd 
  *  
  * @return javax.swing.JButton 
  */
 private JButton getM_btnAdd() {
  if (m_btnAdd == null) {
   m_btnAdd = new JButton();
   m_btnAdd.setPreferredSize(new Dimension(34, 30));
   m_btnAdd.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
     onButtonPressed();
    }
   });
  }
  return m_btnAdd;
 }

 public static void main(String[] args) {
  //Schedule a job for the event-dispatching thread:
  //creating and showing this application's GUI.
  javax.swing.SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    MainForm frame = new MainForm();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(500, 500);
    frame.setVisible(true);
   }
  });
 }
}  //  @jve:decl-index=0:visual-constraint="10,10"
eed3si9n
A: 

Firstly, avoid Hashtable, go straight for Map. In this case there two potential standard implementations you mights want: LinkedHashMap can retain the order that the entries were added; TreeMap, a SortedMap/NavigableMap, will sort the results (order of which can be determined by a Comparator. Alternatively you might want a form of Map that fire events or also provides a TableModel.

If you want a one time conversion from the Map to table, then it's pretty straightforward.

public static TableModel toTableModel(Map<?,?> map) {
    DefaultTableModel model = new DefaultTableModel(
        new Object[] { "Key", "Value" }, 0
    );
    for (Map.Entry<?,?> entry : map) {
        model.addRow(new Object[] { entry.getKey(), entry.getValue() });
    }
    return model;
}

Then just create the JTable with this pre-populated model.

(Disclaimer: I've not tested or so much as compiled this code.)

To keep the Map and TableModel synchronized is more code. Generally it's best to avoid duplicating state whereever possible. Write a class that exposes itself as both a Map and a TableModel. You could go more disjoint by having a Map that fires events and a TableModel that adapts the Map (although note that Map does not have random access based on index, so you'll need to be iether clever or slow for large maps).

Going the other way, a simpler approach would be to add the data straight to a DefaultTableModel and not using a Map at all.

Tom Hawtin - tackline