Scenario: The user selects a tabular file for analysis, which is then loaded as a preview in the GUI using JTable. I want the user to annotate the columns prior to the analysis, but I cannot replace the column headers because that would be confusing.
My existing solution works but is very crude, as you can see in the screenshot below the positioning of the comboboxes isn't particularly well, and this gets pretty confusing when the number of columns increases to 20-30 or more.
Currently the tabbedPane has three children, the top panel that includes the label and the buttons, the middle panel that includes the comboBoxes and the table, and bottom panel that has the analysis button.
private void dataPreview(final String[][] data, String[] headers, final JTabbedPane comp) {
// Take care of column headers
if (headers.length == 0) {
headers = new String[data[1].length];
for (int i = 0; i < headers.length; i++)
headers[i] = "C" + i;
}
// Column annotations
final Dataset.ANNOT_TYPE[] annots = new Dataset.ANNOT_TYPE[headers.length];
final JComboBox<?>[] combos = new JComboBox[annots.length];
// the upper part of the panel
final PreviewPanel descPanel = new PreviewPanel(frame);
final ParamPanel paramPanel = new ParamPanel();
final JPanel upperContainer = new JPanel(new BorderLayout());
paramPanel.setVisible(false);
descPanel.setParamButtonAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean b = paramPanel.isVisible();
paramPanel.setVisible(!b);
}
});
upperContainer.add(descPanel, BorderLayout.NORTH);
upperContainer.add(paramPanel, BorderLayout.SOUTH);
// Define table model
DataPreviewTableModel model = new DataPreviewTableModel(data, headers);
final JTable table = new JTable(model);
table.getColumnModel().getColumn(0).setPreferredWidth(25);
table.setTableHeader(new JTableHeader(table.getColumnModel()){
//Implement table header tool tips.
private static final long serialVersionUID = -7015589028339208609L;
public String getToolTipText(MouseEvent e) {
java.awt.Point p = e.getPoint();
int index = columnModel.getColumnIndexAtX(p.x);
return table.getColumnName(index);
}
});
for(int i=0; i<headers.length; i++)
table.getColumnModel().getColumn(i).setMinWidth(60);
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
// create the combo boxes for column annotation
final JPanel comboPanel = new JPanel();
comboPanel.setBorder(new EmptyBorder(3, 0, 3, 0));
comboPanel.add(new JLabel("Columns:"));
for (int i = 0; i < combos.length; i++) {
final JComboBox<?> box = new JComboBox<Object>(Dataset.ANNOT_TYPE.values());
final int colIndex = i;
box.setMinimumSize(new Dimension(60, box.getMinimumSize().height));
box.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
int colType = box.getSelectedIndex();
table.getColumnModel().getColumn(colIndex+1)
.setCellRenderer(new CellColorRenderer(colType));
table.repaint();
}
});
comboPanel.add(box);
combos[i] = box;
}
final JPanel middlePanel = new JPanel(new BorderLayout());
middlePanel.add(comboPanel, BorderLayout.NORTH);
middlePanel.add(new JScrollPane(table), BorderLayout.CENTER);
JPanel lowerPanel = new JPanel(new BorderLayout());
final JButton analyzeButton = new JButton("Analyze Dataset!");
lowerPanel.add(analyzeButton, BorderLayout.LINE_END);
final JPanel container = new JPanel(new BorderLayout());
container.add(upperContainer, BorderLayout.NORTH);
container.add(new JScrollPane(middlePanel), BorderLayout.CENTER);
container.add(lowerPanel, BorderLayout.SOUTH);
comp.addTab("Preview", container);
Questions:
- Is this a reasonable setup, if so, how can I position my combo-boxes better?
- If the existing design is sub-optimal, how can I improve it without having to redo the whole thing?
I looked at [JTableHeader.getHeaderRect()][2]
as advised here but I am not sure how I can place the combos according to the x,y coordinates of the header rectangles, seeing as they are in different panels.