Have been working on web application for quite sometime. But, I must say, a taste of how desktop applications are built using Swing and JavaFx is not bad either.
Recently, one of my friend came up with a question, how to get a pop up editor for a row in JTable the way we get for a grid in web application. Honestly, I never worked on Swing based app in my career, my first hand experience on swing programming lasted only till college. So, I decided to take this opportunity to learn a bit of swing.
After doing a bit of study on oracle's swing docs & tutorial and going thru a few similar questions on stack overflow, I found a close answer to the problem.
I thinks, couple of tricks to achieve this was:
- First, to instantiate JTable, use the constructor that accepts TableModel (that extends AbstractTableModel), so that, the default cell editing can be disabled, otherwise the double click event will enable the cell editing instead of popping up an editor JFrame.
- Second, use a JInternalFrame as a popup editor box.
And, here is the sample code:
package com.myapp.test;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
public class JTableFrame extends JFrame {
private static final long serialVersionUID = 1L;
public static final boolean DEBUG = false;
JTableFrame() {
MyTableModel myMyTableModel = new MyTableModel();
JTable table = new JTable(myMyTableModel);
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
JTable target = (JTable) e.getSource();
int row = target.getSelectedRow();
int column = target.getSelectedColumn();
System.out.println("row=" + row + " - " + "col=" + column);
System.out.println("value here is:"
+ target.getValueAt(row, column));
// use JInternalFrame as pop up editor
JInternalFrame editorPopup = new JInternalFrame(
"Edit Record", true, true, true, true);
GridLayout gridLayout = new GridLayout(0, 2);
gridLayout.setHgap(5);
gridLayout.setVgap(5);
editorPopup.setLayout(gridLayout);
// creating the popup form elements and setting the values
for (int i = 0; i < target.getColumnCount(); i++) {
System.out.print(target.getValueAt(row, i) + ":");
editorPopup.add(new JLabel(getColumnTitle(i)));
JTextField txtFname = new JTextField(20);
txtFname.setText(target.getValueAt(row, i).toString());
editorPopup.add(txtFname);
}
JButton okButton = new JButton("Ok");
okButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JOptionPane.showMessageDialog(((JButton) e
.getSource()).getParent(), "Record Saved!");
}
});
editorPopup.add(okButton);
editorPopup.add(new JButton("Cancel"));
editorPopup.pack();
target.add(editorPopup);
editorPopup.setVisible(true);
}
}
});
table.setPreferredScrollableViewportSize(new Dimension(1000, 700));
table.setFillsViewportHeight(true);
// Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
this.setSize(1000, 600);
// pack();
setVisible(true);
}
class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private String[] columnNames = { "First Name", "Last Name", "Sport",
"# of Years", "Vegetarian" };
private Object[][] data = {
{ "Kathy", "Smith", "Snowboarding", new Integer(5),
new Boolean(false) },
{ "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
{ "Sue", "Black", "Knitting", new Integer(2),
new Boolean(false) },
{ "Jane", "White", "Speed reading", new Integer(20),
new Boolean(true) },
{ "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
/*
* JTable uses this method to determine the default renderer/ editor for
* each cell. If we didn't implement this method, then the last column
* would contain text ("true"/"false"), rather than a check box.
*/
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Overriden this to disable the default editing of cell
*/
public boolean isCellEditable(int row, int col) {
return false;
}
/*
* Don't need to implement this method unless your table's data can
* change.
*/
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value + " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
private String getColumnTitle(int index) {
String title = null;
switch (index) {
case 0:
title = "First Name";
break;
case 1:
title = "Second Name";
break;
case 2:
title = "Sport";
break;
case 3:
title = "No of Year";
break;
case 4:
title = "is Vegitarian?";
break;
case 5:
title = "--";
break;
}
return title;
}
public static void main(String args[]) {
new JTableFrame();
}
}