I am new to working with JTables and having trouble with getting my custom JTable editor to work properly.
I have a number of custom panels with lists and buttons. To renderder them in a cell I am using a custom PanelCellRenderer that has various constructors for each type of the panel.
To make the buttons clickable I have created this simple PanelCellEditor that extends DefaultCellEditor. To access the data stored within cells at the time of editting I pass the reference to the PanelCellRenderer.
The problem I am having is that when I select the cell (by clicking at it), from displaying the list with the button, the cell selected becomes completely blank. When the cell gets deselected the list with data and the button reappear again. Any advice on this will be helpful. Thanks.
public class PanelCellEditor extends DefaultCellEditor {
private PanelCellRenderer pcr;
private Object value;
public PanelCellEditor(final PanelCellRenderer pcr) {
super(new JCheckBox());
this.pcr = pcr;
this.pcr.setOpaque(true);
if (pcr.firstPanel != null) {
pcr.firstPanel.Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//do something
fireEditingStopped();
}
});
pcr.firstPanel.List.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
String value = (String) ((javax.swing.JList) e.getSource()).getSelectedValue();
//do something
fireEditingStopped();
}
});
}
else if (pcr.secondPanel != null) {
pcr.secondPanel.Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//do something
fireEditingStopped();
}
});
pcr.secondPanel.List.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
String value = (String) ((javax.swing.JList) e.getSource()).getSelectedValue();
//do something
fireEditingStopped();
}
});
}
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
//// if I comment this whole bit ////
if (isSelected) {
pcr.setForeground(table.getSelectionForeground());
pcr.setBackground(table.getSelectionBackground());
} else {
pcr.setForeground(table.getForeground());
pcr.setBackground(table.getBackground());
}
if (pcr.firstPanel != null)
pcr.firstPanel.list.setListData((String[])value);
else if (pcr.secondPanel != null) {
pcr.secondPanel.list.setListData((String[])value);
}
//////// nothing changes /////////
this.value = value;
return pcr;
}
public Object getCellEditorValue() {
return value;
}
public boolean stopCellEditing() {
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
}
you could trace the JTable.getTableCellEditor into your objects.
Have you actually registered your editor with the value it should edit with the Jtable?
Related
So this is the first time I tried using CellEditors for my JTable to embed JComboBox and JSpinner. Everything works fine as expected wherein I can see the values in JComboBox model as well as JSpinner's model values.
However, I noticed that it always displays the JComboBox's values as soon as I make a single click on JTable's column that has the JComboBox.
It's not very user friendly because I think the user would prefer to double click on a JTable's column to get the dropdown box values and select values from it instead of a single click.
How can I change the JComboBox's behaviour to only display itself on double click?
I thought I'd apply a MouseListener to the JComboBox but I don't know what to do next.
Here's what I've written so far.
public class ScheduleDayCellEditor extends DefaultCellEditor{
private JComboBox jcmbDays;
private JTable jtblSchedule;
private DefaultComboBoxModel model;
public ScheduleDayCellEditor(){
super(new JComboBox());
model = new DefaultComboBoxModel(new String[]{"Mon","Tue","Wed","Thu","Fri"});
jcmbDays = new JComboBox(model);
jcmbDays.setEditable(false);
jcmbDays.setSelectedIndex(-1);
jcmbDays.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2){
//? ? ? ?
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return jcmbDays;
}
#Override
public Object getCellEditorValue() {
return jcmbDays.getSelectedItem(); //To change body of generated methods, choose Tools | Templates.
}
Here's a screenshot for additional description.
I'd appreciate any help.
Thank you.
If you don't need to extend DefaultCellEditor for some other reason, you can simply invoke its setClickCountToStart() method with a count of 2.
DefaultCellEditor editor = new DefaultCellEditor(jcmbDays);
editor.setClickCountToStart(2);
jcmbColumn.setCellEditor(editor);
Simply override isCellEditable by applying further criterion:
#Override
public boolean isCellEditable(EventObject aAnEvent) {
boolean cellEditable = super.isCellEditable(aAnEvent);
if (cellEditable && aAnEvent instanceof MouseEvent) {
cellEditable = ((MouseEvent) aAnEvent).getClickCount() == 2;
}
return cellEditable;
}
I have a JCombobox in which when I select any one from drop down list of JCombobox ,the selected item is opening but when I click on "Custom" among one of the drop down list I have to open a daiolg ,here daiolg is opening but drop down list is not closing I want to hide the drop down when I click on Custom. here is my sample code....
private PropertyChangeSupport pcs;///here Iam using ActionListener and PopupMenuListener
public void actionPerformed(ActionEvent ae){
if(ae.getSource() instanceof ComboBox )
{
ComboBox comboBox = (ComboBox)ae.getSource();
Object selectedItem = comboBox.getSelectedItem();
if(selectedItem != null && (!selectedItem.equals("(Custom..)")))
{
pcs.firePropertyChange("ITEM_SELECTED",getCaption(),null);
}}}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
{
ComboBox comboBox = (ComboBox)e.getSource();
Object repeatedSelectedItem = comboBox.getSelectedItem();
if(repeatedSelectedItem != null && repeatedSelectedItem.equals("(Custom..)"))
{
invokeCustomFilterDialog(repeatedSelectedItem, comboBox);
}}
private void invokeCustomFilterDialog(Object repeatedSelectedItem, ComboBox comboBox)
{
customFilterDialog.showDialog(); //here Iam opening dailog...
if(customFilterDialog.isCustomFilterAppliedFlag() == true)
{
pcs.firePropertyChange("ITEM_SELECTED",getCaption(),null);
}
else
{comboBox.setSelectedItem(lastSelectedItem);}}
public void popupMenuCanceled(PopupMenuEvent e)
{ }
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
ComboBox comboBox = (ComboBox)e.getSource();
this.lastSelectedItem = comboBox.getSelectedItem();
}
combobox.getUI().setPopupVisible(combobox, false);
You can use SwingUtilities.invokeLater.
For example
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
final JComboBox comboBox = (JComboBox) e.getSource();
final Object repeatedSelectedItem = comboBox.getSelectedItem();
if (repeatedSelectedItem != null
&& repeatedSelectedItem.equals("(Custom..)")) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
invokeCustomFilterDialog(repeatedSelectedItem, comboBox);
}
});
}
}
first question...
I've read the tutorial at http://www.orbital-computer.de/JComboBox/ and based on that I have made modifications to create a class that you pass an existing JComboBox in order to make it searchable.
I've managed to make the JComboBox modify the results but there seems to be something going on with the caret that I've broken.
Specifically I want any JComboBox passed to this class, to auto-select any existing items in the list that return true for my .indexOf statement.
Code:
public class SearchableJComboBox extends PlainDocument {
JComboBox comboBox;
ComboBoxModel model;
JTextComponent editor;
// flag to indicate if setSelectedItem has been called
// subsequent calls to remove/insertString should be ignored
boolean selecting=false;
boolean hidePopupOnFocusLoss;
boolean hitBackspace=false;
boolean hitBackspaceOnSelection;
public SearchableJComboBox(final JComboBox comboBox) {
this.comboBox = comboBox;
model = comboBox.getModel();
editor = (JTextComponent) comboBox.getEditor().getEditorComponent();
editor.setDocument(this);
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
editor.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (comboBox.isDisplayable()) comboBox.setPopupVisible(true);
hitBackspace=false;
}
});
// Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out
hidePopupOnFocusLoss=System.getProperty("java.version").startsWith("1.5");
// Highlight whole text when gaining focus
editor.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent e) {
// Workaround for Bug 5100422 - Hide Popup on focus loss
if (hidePopupOnFocusLoss) comboBox.setPopupVisible(false);
}
});
// Handle initially selected object
Object selected = comboBox.getSelectedItem();
if (selected!=null) setText(selected.toString());
}
void setPrototypeValue(Object value, JList list) {
comboBox.setPrototypeDisplayValue(value);
list.setPrototypeCellValue(value);
}
JList getListBox() {
JList listBox;
try {
Field field = JComponent.class.getDeclaredField("ui");
field.setAccessible(true);
BasicComboBoxUI ui = (BasicComboBoxUI) field.get(comboBox);
field = BasicComboBoxUI.class.getDeclaredField("listBox");
field.setAccessible(true);
listBox = (JList) field.get(ui);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
return listBox;
}
public void remove(int offs, int len) throws BadLocationException {
// return immediately when selecting an item
if (selecting) return;
if (hitBackspace) {
// user hit backspace => move the selection backwards
// old item keeps being selected
if (offs>0) {
if (hitBackspaceOnSelection) offs--;
} else {
// User hit backspace with the cursor positioned on the start => beep
comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
}
} else {
super.remove(offs, len);
}
}
private void setText(String text) {
try {
super.remove(0, getLength());
super.insertString(0, text, null);
} catch (BadLocationException e) {
throw new RuntimeException(e.toString());
}
}
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
// return immediately when selecting an item
if (selecting) return;
// insert the string into the document
super.insertString(offs, str, a);
// lookup and select a matching item
Object item = lookupItem(getText(0, getLength()));
if (item != null)
setSelectedItem(item);
}
private void setSelectedItem(Object item) {
selecting = true;
model.setSelectedItem(item);
selecting = false;
}
private Object findStringWithin(String pattern) {
for(int i=0; i<model.getSize();i++)
{
if(model.getElementAt(i).toString().toLowerCase().indexOf(pattern.toLowerCase())!=-1)
return model.getElementAt(i);
}
return null;
}
private Object lookupItem(String pattern) {
return this.findStringWithin(pattern);
}
}
I checked your code and the website you reference.
No where do you include the line from the "curser" section:
editor.setCaretPosition(getLength());
This causes your caret to get stuck at the beginning, and essentially as you type you over-write the previous characters.
Give it a try ...
The default behavior of a JTable is to append to the contents when you start typing, and to place the caret at the clicked location when clicking. I want the behavior of both these things to change, so the contents is replaced when I edit a cell, either by typing or by clicking and then typing. When I click a cell and then change the caret position, however, I want the contents to stay so I can change it.
I know how to select all when the cell becomes editing, by replacing the cell editor with one that selects all inside a SwingUtilities.invokeLater (see elsewhere), but that causes the typing behavior to break. When I do this and start typing in a cell, first the typed character is appended to the string, then it is selected (but the selection is invisible!) and when typing another character the contents gets replaced by that.
Is there a way to replace the contents immediately when typing in a highlighted (but not editing) cell, but select all when clicking a cell?
Here is the code I use for the CellEditor:
public class TextFieldCellEditor extends JTextField implements TableCellEditor
{
private CellEditorListener cellEditorListener = null;
private boolean isInteger = false;
private Object oldValue;
// Start editing
#Override
public Component getTableCellEditorComponent(JTable table, Object obj, boolean isSelected, int row, int column)
{
Color color2 = DefaultLookup.getColor(this, ui, "Table.alternateRowColor");
super.setBackground(color2 != null && (row & 1) == 1? color2 : table.getBackground());
super.setForeground(table.getForeground());
super.setBorder(DefaultLookup.getBorder(this, ui, "Table.focusCellHighlightBorder"));
super.setText(obj.toString());
isInteger = obj instanceof Integer;
if (isInteger)
{
super.setHorizontalAlignment(SwingConstants.RIGHT);
oldValue = obj;
}
// SwingUtilities.invokeLater(new Runnable()
// {
// public void run()
// {
// TextFieldCellEditor.this.selectAll();
// }
// });
return this;
}
// Retrieve e dited value
#Override
public Object getCellEditorValue()
{
if (isInteger)
{
// Try to convert to integer. If input is invalid, revert.
try
{
return new Integer(super.getText());
}
catch (NumberFormatException e)
{
return oldValue;
}
}
return super.getText();
}
#Override
public boolean isCellEditable(EventObject e)
{
return true;
}
#Override
public boolean shouldSelectCell(EventObject e)
{
return true;
}
#Override
public boolean stopCellEditing()
{
cellEditorListener.editingStopped(new ChangeEvent(this));
return true;
}
#Override
public void cancelCellEditing()
{
cellEditorListener.editingCanceled(new ChangeEvent(this));
}
#Override
public void addCellEditorListener(CellEditorListener celleditorlistener)
{
cellEditorListener = celleditorlistener;
}
#Override
public void removeCellEditorListener(CellEditorListener celleditorlistener)
{
if (cellEditorListener == cellEditorListener) cellEditorListener = null;
}
}
In your getTableCellEditorComponent() implementation, add the following:
if (isSelected) {
this.selectAll();
}
As an aside, why not extend AbstractCellEditor or DefaultCellEditor(JTextField textField)? See also How to Use Tables: Using Other Editors.
Addendum: See also Table Select All Renderer and Table Select All Editor.
The cleanest solution I could find for this case was to overwrite the JTable's editCellAt and inform the CellEditor of how the edit was triggered:
#Override
public boolean editCellAt(int row, int column, EventObject e) {
cellEditor.setKeyTriggered(e instanceof KeyEvent);
return super.editCellAt(row, column, e);
}
And here is the relevant CellEditor code:
public class MyCellEditor extends DefaultCellEditor {
private boolean keyTriggered;
public MyCellEditor() {
super(new JTextField());
final JTextField textField = (JTextField) getComponent();
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (!keyTriggered) {
textField.selectAll();
}
}
});
}
});
}
public void setKeyTriggered(boolean keyTriggered) {
this.keyTriggered = keyTriggered;
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
final JTextField textField = (JTextField)
super.getTableCellEditorComponent(table, value, isSelected, row, column);
textField.selectAll();
return textField;
}
}
I have been trying with no luck to get a JFormattedTextField to highlight on mouse click. I have been able to get it to work fine while tabbing through fields, however I would like to highlight everything on clicking.
I am only able to highlight on mouse click if I click and hold for about 1.5-2 seconds on the text field; I have no idea why.
I've searched and tried a few fixes including extending the class;
class HFTextField extends JFormattedTextField
{
HFTextField(MaskFormatter formatter)
{
super(formatter);
}
#Override
protected void processFocusEvent(FocusEvent e)
{
super.processFocusEvent(e);
if (e.getID() == FocusEvent.FOCUS_GAINED)
{
this.selectAll();
}
}
}
I am also defining a (rather verbose!) FocusListener which uses SwingUtilities.invokelater;
public static FocusListener CreateHighlightTextFieldFocusListener(final JTextField text_field)
{
FocusListener fl =
new FocusAdapter()
{
public void focusGained(FocusEvent evt)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
text_field.selectAll();
}
});
}
};
return fl;
}
and this is the function that creates formatted text fields;
public static JTextField CreateFormattedTextField(int x, int y, int width, int height,
Method action_method, Method changed_method, Method remove_method,
Method update_method, String mask_formatter, String banned_chars)
{
MaskFormatter formatter = null;
try {
formatter = new MaskFormatter(mask_formatter);
} catch (ParseException e) {
assert(false);
}
if(banned_chars != null)
formatter.setInvalidCharacters(banned_chars);
JTextField text_field = new HFTextField(formatter);
text_field.setBounds(x, y, width, height);
if(action_method != null)
{
text_field.addActionListener(CreateTextFieldActionListener(action_method, text_field));
}
text_field.getDocument().addDocumentListener(
CreateTextFieldDocumentListener(changed_method, remove_method,
update_method, text_field));
text_field.addFocusListener(CreateHighlightTextFieldFocusListener(text_field));
return text_field;
Any help would be greatly appreciated!
maybe you have got problems with EDT,
how method you use for/how you added value to JTextField
works with JTextField, JFormateddTextField, with JComboBox too, and with AutoCompleted funcionalies http://www.java2s.com/Code/Java/Swing-JFC/AutocompleteTextField.htm
private FocusListener focsListener = new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
dumpInfo(e);
}
#Override
public void focusLost(FocusEvent e) {
//dumpInfo(e);
}
private void dumpInfo(FocusEvent e) {
//System.out.println("Source : " + name(e.getComponent()));
//System.out.println("Opposite : " + name(e.getOppositeComponent()));
//System.out.println("Temporary: " + e.isTemporary());
Component c = e.getComponent();
if (c instanceof JFormattedTextField) {
((JFormattedTextField) c).requestFocus();
((JFormattedTextField) c).setText(((JFormattedTextField) c).getText());
((JFormattedTextField) c).selectAll();
} else if (c instanceof JTextField) {
((JTextField) c).requestFocus();
((JTextField) c).setText(((JTextField) c).getText());
((JTextField) c).selectAll();
}
}
private String name(Component c) {
return (c == null) ? null : c.getName();
}
};
Try the following code
yourTextField.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
yourTextField.selectAll();
}
});
}
});
I hate to give a simple answer, but have you tried using the MouseListener interface (or MouseAdapter class)?
Have you tried something like this:
fieldName.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
JTextComponent text = (JTextComponent) e.getSource();
text.selectAll();
}
});
Also, I would not recommend doing this asynchronously.
If you want specialized behavior for a mouse click, then add a MouseAdapter to your JTextFiled, and in the mouseClicked event handler, explicitly alter the background.
basically you can use this code (not sure that for each formatter and input masks), but for Number, Date and String you can use following, with ensure that this JFormattedTextField doesn't implements AutoCompleted
myTextField.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
myTextField.requestFocus();
myTextField.setText(myTextField.getText());
myTextField.selectAll();
}
#Override
public void focusLost(FocusEvent e) {
}
});
sure you can pack that into InvokeLate...