Jtable Design to Synchronize With Back-End Data-Structure

JTable design to synchronize with back-end data-structure

I would recreate your DS once the user is finised editing the table.

You can always create a custom editor to display a popup dialog where you have two separate text fields for each value of the range. Then you can edit each field as a double value within your specified range and recreate the formatted string before saving it to the model. Here's an old example I have lying around to get you started:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

/*
* The editor button that brings up the dialog.
*/
//public class TablePopupEditor extends AbstractCellEditor
public class TablePopupEditor extends DefaultCellEditor
implements TableCellEditor
{
private PopupDialog popup;
private String currentText = "";
private JButton editorComponent;

public TablePopupEditor()
{
super(new JTextField());

setClickCountToStart(2);

// Use a JButton as the editor component

editorComponent = new JButton();
editorComponent.setBackground(Color.white);
editorComponent.setBorderPainted(false);
editorComponent.setContentAreaFilled( false );

// Set up the dialog where we do the actual editing

popup = new PopupDialog();
}

public Object getCellEditorValue()
{
return currentText;
}

public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{

SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
System.out.println("run");
popup.setText( currentText );
// popup.setLocationRelativeTo( editorComponent );
Point p = editorComponent.getLocationOnScreen();
popup.setLocation(p.x, p.y + editorComponent.getSize().height);
popup.show();
fireEditingStopped();
}
});

currentText = value.toString();
editorComponent.setText( currentText );
return editorComponent;
}

/*
* Simple dialog containing the actual editing component
*/
class PopupDialog extends JDialog implements ActionListener
{
private JTextArea textArea;

public PopupDialog()
{
super((Frame)null, "Change Description", true);

textArea = new JTextArea(5, 20);
textArea.setLineWrap( true );
textArea.setWrapStyleWord( true );
KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
textArea.getInputMap().put(keyStroke, "none");
JScrollPane scrollPane = new JScrollPane( textArea );
getContentPane().add( scrollPane );

JButton cancel = new JButton("Cancel");
cancel.addActionListener( this );
JButton ok = new JButton("Ok");
ok.setPreferredSize( cancel.getPreferredSize() );
ok.addActionListener( this );

JPanel buttons = new JPanel();
buttons.add( ok );
buttons.add( cancel );
getContentPane().add(buttons, BorderLayout.SOUTH);
pack();

getRootPane().setDefaultButton( ok );
}

public void setText(String text)
{
textArea.setText( text );
}

/*
* Save the changed text before hiding the popup
*/
public void actionPerformed(ActionEvent e)
{
if ("Ok".equals( e.getActionCommand() ) )
{
currentText = textArea.getText();
}

textArea.requestFocusInWindow();
setVisible( false );
}
}

public static void main(String[] args)
{
String[] columnNames = {"Item", "Description"};
Object[][] data =
{
{"Item 1", "Description of Item 1"},
{"Item 2", "Description of Item 2"},
{"Item 3", "Description of Item 3"}
};

JTable table = new JTable(data, columnNames);
table.getColumnModel().getColumn(1).setPreferredWidth(300);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);

// Use the popup editor on the second column

TablePopupEditor popupEditor = new TablePopupEditor();
table.getColumnModel().getColumn(1).setCellEditor( popupEditor );

JFrame frame = new JFrame("Popup Editor Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add( scrollPane );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}

Get position of Click JTable while using Cell renderer

My current situation requires a large amount of text information to be displayed next to [the] relevant data

Instead of a MouseListener, add a TableModelListener to your TableModel and update the Document model of an adjacent JTextComponent. In this related example, the TableModelListener updates the ListModel of an adjacent JList.

Alternatively, add a ListSelectionListener to your table's ListSelectionModel and update an adjacent component accordingly. In this related example using SINGLE_SELECTION, the ListSelectionListener updates an adjacent JButton.

Alternatively, look at this TablePopupEditor, which uses a JButton as a TableCellEditor. The button's ActionListener evokes a popup modal JDialog containing a JTextArea.

JTable and Excel-like formulas

For numbers, let your TableModel store expressions as String and let your implementation of getValueAt() return the result of evaluating the expression. Several libraries are available.

How to create a jtable with different buttons in each row

I would guess that EnumSet is what you are looking for:

Sample Image

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;

public final class EnumSetTest {
private JComponent makeUI() {
String[] columnNames = {"REPORT ID", "ACTION"};
Object[][] data = {
{"Report1", EnumSet.of(Actions.PRINT)},
{"Report2", EnumSet.of(Actions.PRINT, Actions.EDIT)},
{"Report3", EnumSet.allOf(Actions.class)},
{"Report4", EnumSet.of(Actions.PRINT)}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
@Override public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
JTable table = new JTable(model);
table.setRowHeight(36);
TableColumn column = table.getColumnModel().getColumn(1);
column.setCellRenderer(new ButtonsRenderer());
column.setCellEditor(new ButtonsEditor(table));
return new JScrollPane(table);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new EnumSetTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}

enum Actions { PRINT, EDIT; }

class ButtonsPanel extends JPanel {
public final List<JButton> buttons = new ArrayList<>();
public ButtonsPanel() {
super(new FlowLayout(FlowLayout.LEFT));
setOpaque(true);
for (Actions a : Actions.values()) {
JButton b = new JButton(a.toString());
b.setFocusable(false);
b.setRolloverEnabled(false);
add(b);
buttons.add(b);
}
}
protected void updateButtons(Object value) {
if (value instanceof EnumSet) {
EnumSet ea = (EnumSet) value;
removeAll();
if (ea.contains(Actions.PRINT)) {
add(buttons.get(0));
}
if (ea.contains(Actions.EDIT)) {
add(buttons.get(1));
}
}
}
}

class ButtonsRenderer implements TableCellRenderer {
private final ButtonsPanel panel = new ButtonsPanel();
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
panel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
panel.updateButtons(value);
return panel;
}
}

class PrintAction extends AbstractAction {
private final JTable table;
public PrintAction(JTable table) {
super(Actions.PRINT.toString());
this.table = table;
}
@Override public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(table, "Printing");
}
}

class EditAction extends AbstractAction {
private final JTable table;
public EditAction(JTable table) {
super(Actions.EDIT.toString());
this.table = table;
}
@Override public void actionPerformed(ActionEvent e) {
int row = table.convertRowIndexToModel(table.getEditingRow());
Object o = table.getModel().getValueAt(row, 0);
JOptionPane.showMessageDialog(table, "Editing: " + o);
}
}

class ButtonsEditor extends AbstractCellEditor implements TableCellEditor {
private final ButtonsPanel panel = new ButtonsPanel();
private final JTable table;
private Object o;
private class EditingStopHandler extends MouseAdapter implements ActionListener {
@Override public void mousePressed(MouseEvent e) {
Object o = e.getSource();
if (o instanceof TableCellEditor) {
actionPerformed(null);
} else if (o instanceof JButton) {
ButtonModel m = ((JButton) e.getComponent()).getModel();
if (m.isPressed() && table.isRowSelected(table.getEditingRow()) && e.isControlDown()) {
panel.setBackground(table.getBackground());
}
}
}
@Override public void actionPerformed(ActionEvent e) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
fireEditingStopped();
}
});
}
}
public ButtonsEditor(JTable table) {
super();
this.table = table;
panel.buttons.get(0).setAction(new PrintAction(table));
panel.buttons.get(1).setAction(new EditAction(table));

EditingStopHandler handler = new EditingStopHandler();
for (JButton b : panel.buttons) {
b.addMouseListener(handler);
b.addActionListener(handler);
}
panel.addMouseListener(handler);
}
@Override public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
panel.setBackground(table.getSelectionBackground());
panel.updateButtons(value);
o = value;
return panel;
}
@Override public Object getCellEditorValue() {
return o;
}
}

Force JTable row selection if clicking outside visible JPopupMenu

This a LAF issue.

It works for me when I use the default LAF but doesn't work when I use the platform LAF, which for me is Windows.

A potential solution on Windows is to use a MouseListener to select the line. Note the code is added to the mouseReleased event. For some reason the table does not receive the mousePressed event even though according to the AWTEventListener the table is the source of the mousePressed event.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TablePopupListener extends JPanel
{
public TablePopupListener()
{
JTable table = new JTable(10, 5);
add( new JScrollPane( table ) );

JPopupMenu popup = new JPopupMenu();
popup.add( new JMenuItem("Do Something1") );
popup.add( new JMenuItem("Do Something2") );

table.setComponentPopupMenu( popup );

table.addMouseListener( new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
System.out.println("Pressed JTable");
}

public void mouseReleased(MouseEvent e)
{
System.out.println("Released JTable");

int row = table.rowAtPoint( e.getPoint() );

if (row != -1
&& !table.isRowSelected(row))
{
table.setRowSelectionInterval(row, row);
}
}
});
}

private static void createAndShowGUI()
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception ex) { System.out.println(ex); }

JFrame frame = new JFrame("TablePopupListener");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TablePopupListener());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );

Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
{
public void eventDispatched(AWTEvent e)
{
String event = null;

switch (e.getID())
{
case MouseEvent.MOUSE_PRESSED: event = "Pressed: " ; break;
case MouseEvent.MOUSE_RELEASED: event = "Released: " ; break;
case MouseEvent.MOUSE_ENTERED: event = "Entered: " ; break;
case MouseEvent.MOUSE_EXITED: event = "Exited: " ; break;
default: event = null; break;
}

if (event != null)
{
System.out.println();
System.out.println(event + e.getSource().getClass());
}
}
}, AWTEvent.MOUSE_EVENT_MASK);
}

public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}

Adding extra unvisible information to each cell in the JTable

One appproach would be to display the extra details in a tooltip. The article How to Use Tables: Specifying Tool Tips for Cells includes a complete example that shows how to change the tooltip text for each cell. You could keep the registrar information in your TableModel and get to it in your TableCellRenderer via the table parameter seen by getTableCellRendererComponent(). Alternatively, display it in a TablePopupEditor, seen here.



Related Topics



Leave a reply



Submit