JTable design to synchronize with back-end data-structure - java

I have a JTable which is loaded from a data-structure using table model.The data-structure is of the format NavigableMap<Float,NavigableMap<Float,Boolean>>.An example data is:
Table Format:
Range f1,v1 f2,v2 f3,v3 f4,v4
12.1-30.2 30,true 32,false 45,true 50,false
30.2-45.6 30,true 32.4,true 45,true 50.1,true
The above data format is represented in the DS as
DS Format:
Key Value
12.1 <<30,true>,<32,false>,<45,true>,<50,false>>
30.2 <<30,true>,<32.4,true>,<45,true>,<50.1,true>>
45.6 null
I have managed to represent the above given data in Jtable using table-model.Once the data is loaded from the DS to the table I have to allow user edit.Now this is where I have problem.My doubt is whether is should keep the data structure synchronized with the changes in the table or should i recreate the DS from the table once the user finish editing and then replace it with the old one.
More over I need to validate the data(for example from above - Suppose the user want's to edit the value 30.1.He should only be allowed to enter values between 12.1 and 45.6.Since data the tables are string's (once loaded) I'm planning to use regex and key-listener and consume all user key presses which doesn't match the regex and values which doesn't come within the range.I'm not sure is this is a good idea or what are implications.I would like to get some suggestions on this.

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);
}
}

Related

How to include a JTable and some text below the table in JOptionPane.showMessageDialog, in Java

I am trying to include a JTable in JOptionPane.showMessageDialog and adding some more text below the table. To do so, I have tried next code:
import javax.swing.JOptionPane;
import javax.swing.*;
public class TextInTable {
public static void main(String[] args) {
String[][] rowValues = {
{"1","2","3"}
};
String[] columnNames = {
"A","B", "C"
};
JTable table = new JTable(rowValues, columnNames);
JOptionPane.showMessageDialog(null, new JScrollPane(table) +"\n"+ "I need to add some text here \n" + "and here”);
}
}
However, the JTable does not show correctly if I put this code (+"\n"+ "I need to add some text here \n" + "and here”) after the table.
This is what I am trying to do:
Any idea about how to solve it? Thanks in advance.
You need to create your own JPanel the way you want it with the components you would like and then pass that panel to the JOptionPane. Below I provide a runnable demo of this. Read all the comments in code as they explain what is going on. You can delete them later if you like. Here is what it produces on Screen:
Here is the runnable code:
package joptionpanewithjtabledemo;
public class JOptionPaneWithJTableDemo {
public static void main(String[] args) {
// Application started this way to avoid the need for statics.
new JOptionPaneWithJTableDemo().startApp(args);
}
private void startApp(String[] args) {
/* Create a JDialog box to use as a parent for the JOptionPane
just in case the JOptionPane has no parent and needs to be
displyed on top of a window that has its own ON TOP property
set to true and the JOptionPane's parent property is set to
null. If this is the case then the message box will be hidden
behind it! If your JOptionPane will be displayed on an actual
parent window then use that window's variable name as parent.
You can then delete anything in code related to iDialog.
*/
javax.swing.JDialog iDialog = new javax.swing.JDialog();
iDialog.setAlwaysOnTop(true);
iDialog.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
iDialog.setLocationRelativeTo(null);
// Create a JPanel to display within the JOptionPane MessageBox //
javax.swing.JPanel panel = new javax.swing.JPanel();
// Size the Panel to what you want to hold the JTable and JLabel
panel.setPreferredSize(new java.awt.Dimension(400, 250));
panel.setLayout(new java.awt.BorderLayout()); // Set BorderLayout as the layout manager
// JTable Column Names
Object[] columnNames = {"A", "B", "C"};
// Some fictitious data for the JTable...
Object[][] data = {
{1000, 2000, 3000}, {1001, 2001, 3001}, {1002, 2002, 3002},
{1003, 2003, 3003}, {1004, 2004, 3004}, {1005, 2005, 3005},
{1006, 2006, 3006}, {1007, 2007, 3007}, {1008, 2008, 3008},
{1009, 2009, 3009}, {1010, 2010, 3010}, {1011, 2011, 3011},
};
// Declare a JTable and initialize with the table data and column names.
javax.swing.JTable table = new javax.swing.JTable(data, columnNames);
/* Align JTable Header Text to Center.
Alignment options are: Align_LEFT (2), Align_CENTER (0), Align_RIGHT (4),
Align_LEADING (10), or Align_TRAILING (11) */
int alignType = 0;
for (int i = 0; i < table.getColumnCount(); i++) {
table.getTableHeader().getColumnModel().getColumn(i)
.setHeaderRenderer(new HeaderRenderer(table, alignType));
}
// Declare a JScrollPane and place the JTable into it.
javax.swing.JScrollPane tableScrollPane = new javax.swing.JScrollPane(table);
// Ensure the ScrollPane size.
tableScrollPane.setPreferredSize(new java.awt.Dimension(400, 200));
panel.add(tableScrollPane, java.awt.BorderLayout.NORTH); // Add the scrollpane to top of panel.
/* Use basic HTML to create you message text. Gives you more
flexability towards how your message will look. */
String msg = "<html><font size='4'>I need to add some text "
+ "<font color=blue>here</font><center>and right "
+ "<font color=red>here</font>!</center></html>";
javax.swing.JLabel msgLabel = new javax.swing.JLabel(msg);
// Set the initial text alignment in the JLabel.
msgLabel.setHorizontalAlignment(javax.swing.JLabel.CENTER);
//msgLabel.setBorder(BorderFactory.createLineBorder(Color.blue, 1));
// Ensure label width and desired height.
msgLabel.setPreferredSize(new java.awt.Dimension(panel.getWidth(), 50));
panel.add(msgLabel, java.awt.BorderLayout.SOUTH); // add label to bottom of panel.
// Display The Message Box...
javax.swing.JOptionPane.showMessageDialog(iDialog, panel, "My Table Message Box",
javax.swing.JOptionPane.INFORMATION_MESSAGE);
iDialog.dispose();
}
// Inner class - A Header cell renderer class for header text alignment options.
class HeaderRenderer implements javax.swing.table.TableCellRenderer {
javax.swing.table.DefaultTableCellRenderer renderer;
int horAlignment;
HeaderRenderer(javax.swing.JTable table, int horizontalAlignment) {
horAlignment = horizontalAlignment;
renderer = (javax.swing.table.DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer();
}
#Override
public java.awt.Component getTableCellRendererComponent(javax.swing.JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
java.awt.Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
javax.swing.JLabel label = (javax.swing.JLabel) c;
label.setHorizontalAlignment(horAlignment);
return label;
}
}
}

KeyListeners for a JComboBox which is used as a cell editor in a table

I am sorry if this sounds likes a basic question but I am relatively new to java. I have a JComboBox which I populate from a database and then use it in a JTable. I do that using the following code:
itemEditortxt = new JComboBox(buildComboBoxmodel("SELECT item_name FROM items ORDER BY item_name"));
AutoCompleteDecorator.decorate(itemEditortxt);
TableColumn ledgerColumn = invoicePurchasedTable.getColumnModel().getColumn(0);
ledgerColumn.setCellEditor(new ComboBoxCellEditor(itemEditortxt));
I am trying to add key listeners to the JComboBox but for some reason they are not being called when I press any key when the focus is on the cell which uses the JComboBox. Following is how I add the litterers:
itemEditortxt.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {System.out.print("line1");}
#Override
public void keyReleased(KeyEvent e) {System.out.print("line2");}
#Override
public void keyTyped(KeyEvent e) {System.out.print("line3");}
});
Can someone please tell me what Im doing wrong? Thanks.
Following is the SSCCE. There are two similar JComboBoxes, one is added normally and the other is used as a cell editor. In the first one the user can use the keyboard arrows and then press ENTER in order to make a selection. This is not the case for the one in the table. Thanks:
package sp2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import javax.swing.table.*;
import org.jdesktop.swingx.autocomplete.*;
class InvoicePurchasedModel extends DefaultTableModel {
public InvoicePurchasedModel (Vector<Vector<Object>> data, Vector<String> columnNames) {
super(data, columnNames);
}
#Override
public Class getColumnClass(int col) {
if (col == 0)
return String.class;
else
return Double.class;
}
}
public class SP2 {
JFrame mainPage;
JTabbedPane jtp;
JPanel mainPanel;
JPanel purchasedInvoicesPanel;
RXTable invoicePurchasedTable;
DefaultTableModel invoicePurchasedtm;
JComboBox itemEditortxt;
JComboBox itemEditortxt2;
SP2() {
mainPage = new JFrame("System");
mainPage.getContentPane().setLayout(new GridLayout());
mainPage.setSize(1200, 1200);
mainPage.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createTabs();
mainPage.setVisible(true);
}
void createTabs() {
jtp = new JTabbedPane();
mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout());
mainPage.getContentPane().add(jtp);
purchasedInvoicesPanel = new JPanel();
jtp.addTab("Purchased", purchasedInvoicesPanel);
invoicePurchasedtm = buildInvoicePurchasedTableModel();
invoicePurchasedTable = new RXTable(invoicePurchasedtm) {
private final KeyStroke tabKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
public void changeSelection(int row, int column, boolean toggle, boolean extend)
{
super.changeSelection(row, column, toggle, extend);
if (editCellAt(row, column))
{
Component editor = getEditorComponent();
editor.requestFocusInWindow();
}
}
};
invoicePurchasedTable.setCellSelectionEnabled(true);
invoicePurchasedTable.setSelectAllForEdit(true);
purchasedInvoicesPanel.setLayout(new BoxLayout(purchasedInvoicesPanel, BoxLayout.PAGE_AXIS));
JPanel purchasedInvoicesPanel1 = new JPanel();
JPanel purchasedInvoicesPanel2 = new JPanel();
purchasedInvoicesPanel.add(purchasedInvoicesPanel1);
purchasedInvoicesPanel.add(purchasedInvoicesPanel2);
JScrollPane invoicePurchasedscrollPane = new JScrollPane(invoicePurchasedTable);
invoicePurchasedTable.setPreferredScrollableViewportSize(new Dimension(1000, 400));
String[] names = {"aa", "aa1", "aa2", "bb", "bb1", "bb2"};
itemEditortxt = new JComboBox(names);
itemEditortxt2 = new JComboBox(names);
AutoCompleteDecorator.decorate(itemEditortxt);
AutoCompleteDecorator.decorate(itemEditortxt2);
TableColumn ledgerColumn = invoicePurchasedTable.getColumnModel().getColumn(0);
ledgerColumn.setCellEditor(new ComboBoxCellEditor(itemEditortxt));
purchasedInvoicesPanel1.add(itemEditortxt2);
purchasedInvoicesPanel2.add(invoicePurchasedscrollPane);
}
public static DefaultTableModel buildInvoicePurchasedTableModel() {
Vector<String> columnNames = new Vector<String>();
columnNames.add("Item");
columnNames.add("Quantity");
columnNames.add("Unit Price");
columnNames.add("Amount");
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
Vector<Object> vector = new Vector<Object>();
vector.add("");
vector.add(0.00);
vector.add(0.00);
vector.add(0.00);
data.add(vector);
return new InvoicePurchasedModel(data, columnNames);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SP2();
}
});
}
}
"I am trying to add key listeners to the JComboBox but for some reason they are not being called when I press any key when the focus is on the cell which uses the JComboBox."
I think what you may be trying to do is add a listener to "text field" for the combobox. The first thing you need to do is actually get the editor component. then you can add a DocumentListener to the Document of the JTextComponent
JTextComponent editor = (JTextComponent) comboBox.getEditor().getEditorComponent();
editor.getDocument().addDocumentListener(new DocumentListener(){
...
});
Ok, so the problem was caused by the AutoCompleteDecorator. I deactivated it and used instead the AutoCompletion.enable(employeeDelete). Now the ENTER and TAB keys work as expected. I appreciate all the comments that helped me.

Switch between frames when select exercise in jTable

I'm building an Typing program and i have made an list with exercises to type
public class OefeningenListModel extends AbstractListModel {
private JComboBox time; //time combo box to select time
public OefeningenListModel() {
oefeningen = new ArrayList<Oefening>();
Oefening o1 = new Oefening("1", "Oefening HJ");
Oefening o2 = new Oefening("2", "Oefening KL");
Oefening o3 = new Oefening("3", "Oefening JH");
oefeningen.add(o1);
oefeningen.add(o2);
oefeningen.add(o3);
}
those exercises are shown in an jTable on my frame
public BasisSchermm() {
initComponents();
jList1.setModel(new OefeningenListModel());
and on this frame there is even add an jButton
now is my question:
i want to add a actionperformed on this button when a exercise is selected in the table and you click to button(when the exercise is selected) you move to a new frame to type the exercise but i have no idea how i can do this
to get the selected item in your JList you could do like this:
// Get the index of the selected item
int selectedIndex = jList1.getSelectedIndex();
// Get the selected item from the model
Object sel = jList1.getModel().getElementAt(selectedIndex);
or if needed you could cast it to the type you need:
Oefening selectedItem = (Oefening) list.getModel().getElementAt(selectedIndex);
to add the action listener:
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
if (xItemIsSelected) {
//open 'x' frame
new xFrame().show();
}
if (yItemIsSelected) {
//open 'y' frame
new yFrame().show();
}
}
};
//add the listener to the button
button.addActionListener(actionListener);
To put you in the right direction a small piece of sample code (minus the imports) which creates a JFrame where the contents of the main panel is controlled by the selection in the JList. The example shows how to react on selection changes in the JList, and shows an alternative for constantly opening new windows, which is a terrible user experience.
public class ListSelectionExample {
private static String[] MODEL_CONTENTS = new String[]{"String1","String2","String3"};
public static void main( String[] args ) throws InvocationTargetException, InterruptedException {
EventQueue.invokeAndWait( new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame( "TestFrame" );
//create a JList
final JList list = new JList( );
DefaultListModel listModel = new DefaultListModel();
for ( String modelContents : MODEL_CONTENTS ) {
listModel.addElement( modelContents );
}
list.setModel( listModel );
list.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
//use a CardLayout to switch between different labels
final CardLayout cardLayout = new CardLayout();
final JPanel contentPane = new JPanel( cardLayout );
for ( String label_content : MODEL_CONTENTS ) {
contentPane.add( new JLabel( label_content ), label_content );
}
cardLayout.show( contentPane, MODEL_CONTENTS[0] );
//when the list selection is changed, switch the contents of the JPanel
list.addListSelectionListener( new ListSelectionListener() {
#Override
public void valueChanged( ListSelectionEvent aListSelectionEvent ) {
int selectedIndex = list.getSelectedIndex();
String modelElement = ( String ) list.getModel().getElementAt( selectedIndex );
cardLayout.show( contentPane, modelElement );
}
} );
frame.getContentPane().add( list, BorderLayout.EAST );
frame.getContentPane().add( contentPane, BorderLayout.CENTER );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
} );
}
}

Updating Data in a JTable

Lets say I have a table. One of the cells holds a JLabel. If I change the text of the JLabel how do I get the JTable to show the change?
Look at the following code, what should I change to make it show the changes to the JLabel?
public class ActivTimerFrame extends JFrame implements ActionListener{
//Data for table and Combo Box
String timePlay = "1 Hour";
String timeDev = "2 Hours";
String[] comboChoices = {"Play Time", "Dev Time"};
String[] columnNames = {"Activity", "Time Allowed", "Time Left"};
Object[][] data = {{"Play Time", "1 Hour", timePlay }, {"Dev Time", "2 Hours", timeDev }};
//This is where the UI stuff is...
JTable table = new JTable(data, columnNames);
JScrollPane scrollPane = new JScrollPane(table);
JPanel mainPanel = new JPanel();
JComboBox comboBox = new JComboBox(comboChoices);
JButton start = new JButton("Start");
JButton stop = new JButton("Stop");
public ActivTimerFrame() {
super("Activity Timer");
setSize(655, 255);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setResizable(false);
GridLayout layout = new GridLayout(2,1);
setLayout(layout);
add(scrollPane);
stop.setEnabled(false);
start.addActionListener(this);
mainPanel.add(comboBox);
mainPanel.add(start);
mainPanel.add(stop);
add(mainPanel);
}
#Override
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if(source == start) {
timePlay ="It Works";
}
}
}
You can do
table.getModel().setValueAt(cellValueObject, rowIndex, colIndex);
to set a particular cell.
in you case for what you are trying, you can do
timePlay ="It Works";
table.getModel().setValueAt(timePlay, 0, 1);
You need to have your JTable use a TableModel such as an AbstractTableModel or DefaultTableModel and then change the data in the table model when desired. This will then be reflected as changes in the data displayed in the JTable if you also fire the appropriate listener notification method (which is done automatically for you if you use the DefaultTableModel). The Swing tutorial on JTables explains all of this, and if you haven't gone through it, you owe it to yourself to do so.

Trying to get focus onto JTextPane after doubleclicking on JList element (Java)

Problem:
I have the following JList which I add to the textPane, and show it upon the caret moving. However, after double clicking on the Jlist element, the text gets inserted, but the caret is not appearing on the JTextPane.
This is the following code:
listForSuggestion = new JList(str.toArray());
listForSuggestion.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listForSuggestion.setSelectedIndex(0);
listForSuggestion.setVisibleRowCount(visibleRowCount);
listScrollPane = new JScrollPane(listForSuggestion);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mouseEvent) {
JList theList = (JList) mouseEvent.getSource();
if (mouseEvent.getClickCount() == 2) {
int index = theList.locationToIndex(mouseEvent.getPoint());
if (index >= 0) {
Object o = theList.getModel().getElementAt(index);
//System.out.println("Double-clicked on: " + o.toString());
//Set the double clicked text to appear on textPane
String completion = o.toString();
int num= textPane.getCaretPosition();
textPane.select(num, num);
textPane.replaceSelection(completion);
textPane.setCaretPosition(num + completion.length());
int pos = textPane.getSelectionEnd();
textPane.select(pos, pos);
textPane.replaceSelection("");
textPane.setCaretPosition(pos);
textPane.moveCaretPosition(pos);
}
}
theList.clearSelection();
Any idea on how to "de-focus" the selection on the Jlist, or make the caret appear on the JTextPane after the text insertion?
I'll elaborate more if this is not clear enough. Please help, thanks!
Have a look and play around with the focus-methods in JComponent
Specifically grabFocus and requestFocusInWindow
What happens for instance, if you add textPane.grabFocus() after textPane.moveCaretPosition(pos);?
Although not related to your problem, you may want to check out the List Action, which attempts to handle this type of request in a more general way.
Edit:
Here is my simple SSCCE that shows invokeLater is not required:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ListActionTest
{
public static void main(String[] args)
throws Exception
{
final JTextField textField = new JTextField();
Action displayAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
JList list = (JList)e.getSource();
System.out.println(list.getSelectedValue());
textField.setText(list.getSelectedValue().toString());
textField.requestFocusInWindow();
}
};
String[] data = { "zero", "one", "two", "three", "four", "five" };
JList list = new JList( data );
ListAction la = new ListAction(list, displayAction);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( new JScrollPane(list) );
frame.add(textField, BorderLayout.SOUTH);
frame.setSize(400, 100);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}

Categories