I created JComboBox in my column and it works fine. The problem occurs when I tried to add one more editor in the same column. Scenario, user need to choose value from ComboBox as their remark. If they choose Others, another textbox should appear below the ComboBox for user to type.
Code for ComboBox
TableColumn col5 = jTable1.getColumnModel().getColumn(4);
String[] options = new String[]{"Font Issue","Text Issue","Image Issue","AI Issue","Others"};
JComboBox combo1 = new JComboBox(options);
JComboBox combo2 = new JComboBox(options);
col5.setCellEditor(new DefaultCellEditor(combo1));
col5.setCellRenderer(new ComboBoxRenderer(combo2));
combo2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox nameCombo = (JComboBox)e.getSource();
String newSelection = (String)nameCombo.getSelectedItem();
if(newSelection.equalsIgnoreCase("others"))
{
}
}
});
When i add one more editor.
MyTableCellEditor textEditor = new MyTableCellEditor ();
col5.setCellEditor(textEditor );
It overwrite the dropdownlist. I want to have something like this.
Swing editors are designed to occupy the space of a single cell. If you want to display a panel with two components then you will need to create a popup editor. Read the section from the Swing tutorial on Using Other Editors for an example of how you might do this.
Related
I'm having difficulty changing unselected options in a JList table to set them to setEnable(false). The method that is receiving the values is an ActionListener button method that, once pressed, receives the selected values from the JList. Here is the method and the buildEnemySelectionPanel() method is creating the JList with the appropriate JPanel for later placement:
private String[] enemies = {"Goblin", "Skeleton"};
private void buildEnemySelectionPanel()
{
enemyPanel = new JPanel();
enemyListPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
enemyListPanel.setPreferredSize(new Dimension(180, 85));
enemyListPanel.setBackground(Color.WHITE);
enemyPanel.setLayout(new BoxLayout(enemyPanel, BoxLayout.Y_AXIS));
enemyList = new JList(enemies);
enemyList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
enemyList.addListSelectionListener(new EnemyListListener());
enemyListPanel.add(enemyList);
enemyPanel.add(enemyListPanel);
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("Select Enemy"))
{
indexEnemy = enemyList.getSelectedIndex();
indexEnemyWeapon = weaponList.getSelectedIndex();
/*
here is where I'm having problems
*/
}
}
So far I've tried to take all of the items from the JList and, matching them with the references from the original String[] list items that I sent to the JList, parsed the indexes and if they didn't match set to false. Unfortunately as you are all probably well aware, compilation errors came up as result due to the fact that the JList is not actually a list. Here is a sample of my for loop that I tried to use in my method above:
for(int x = 1; x < enemyList.length(); x++)
{
if (!(enemies[x] == indexEnemy))
{
enemyList[x].setEnable(false);
}
}
I've read the http://docs.oracle.com/javase/8/docs/api/ , (tried to link 'setEnable') among some examples but don't seem to be making the connection.
Ideally, what I wish to happen is that when the ActionEvent of my button is triggered, all non-selected options in my JList will be disabled. I understand that the end-user will still be able to change his/her mind and make a different selection. But I'd like to still receive some help on how I can set the non-selected items in my JList to false if they are not the indexEnemy from my method above.
I am making a registration page but I am fairly new to Java, I have a combo box for peoples Titles such as "Mr, Mrs, Miss, etc" one of the options is "Other..." And I have a text field next to the combo box to specify your title, I would like the text field to not be editable unless someone selects "Other..." in the combo box, How would I do this?
What it looks like at the moment:
I can't see what I'm doing wrong?
TitleSpecifyChoiceField.setEditable(false);
TitleSpecifyChoiceField.setText("Please specify title...");
TitleChoice.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Mr", "Mrs", "Miss", "Ms", "Dr", "Other..." }));
TitleChoice.setToolTipText("");
TitleChoice.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e) {
if (TitleChoice.getSelectedItem().equals("Other...")){
TitleSpecifyChoiceField.setEditable(true);
};
You would do this the same way you'd respond to any changes in a JComboBox -- by adding a listener to the JComboBox as per the Swing combo box tutorial. Inside the listener, change the setEnabled(...) setting on the JTextField depending on the selected item. i.e., by calling getSelectedItem() on the JComboBox and testing whether calling equalsIgnoreCase("other") is true.
Note that I recommend that you use setEnabled(...) not setEditable(...) as the former will give the user visual cues as to whether the JTextField should be edited or not.
Edit
Regarding your code:
TitleSpecifyChoiceField.setEditable(false);
TitleSpecifyChoiceField.setText("Please specify title...");
TitleChoice.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Mr", "Mrs", "Miss", "Ms", "Dr", "Other..." }));
TitleChoice.setToolTipText("");
TitleChoice.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e) {
if (TitleChoice.getSelectedItem().equals("Other...")){
TitleSpecifyChoiceField.setEditable(true);
}
}
});
Some problems and issues:
Does your JComboBox use Strings or does it hold other types of items?
You will want to add debugging code into your code to try to isolate the problem. For instance, inside of your ItemListener, add a System.out.println(...) to print out the selected item to be sure that the listener is working as expected.
You are checking if the item .equals("Other..."), a String literal. Instead consider making a String constant, OTHER that the JComboBox uses and that you test in the listener to be sure that the tested String and and the displayed are the same.
Again, I suggest you use setEnabled(...) not setEditable(...).
You should learn and follow Java naming conventions including beginning all variable names with lower case letter as this will help us to better understand your code.
You should fix your posted code indentation so that it is regular and makes sense (note my code above vs yours). Why do you want to make it harder for folks who are trying to help you to understand your code? Your job is to make ours as easy as possible as we're all volunteers.
Create and post an sscce to get the best and fastest help.
Add a listener to the combo box. When the selected item changes, call setEditable() on the text field.
You could try adding an ItemListener to your JComboBox and (as #HovercraftFullOfEels suggested) use setEnabled as opposed to setEditable. For a general idea, you could do something like this:
JTextField textField = ...;
JComboBox<String> comboBox = ...;
comboBox.addItemListener(
new ItemListener(){
public void itemStateChanged(ItemEvent e){
final String selected = (String)comboBox.getSelectedItem();
textField.setEnabled(selected.equals("other"));
}
}
);
Or if you are using Java 8 you could use this:
JTextField textField = ...;
JComboBox<String> comboBox = ...;
comboBox.addItemListener(
e -> {
final String selected = (String)comboBox.getSelectedItem();
textField.setEnabled(selected.equals("other"));
}
);
I'm building and app with multiple JTables and I need to detect when cell value change occurs so I can update it in the database. I tried TableModelListener and overriding tableChanged, but it fires only when I click away (click on another row) after I have edited a cell.
Any other way to do this?
You can implement the CellEditorListener interface, as shown in this example. Note that JTable itself is a CellEditorListener.
It may also be convenient to terminate the edit when focus is lost, as shown here:
table.putClientProperty("terminateEditOnFocusLost", true);
More Swing client properties may be found here.
I'm agreeing with #mKorbel - unless all your input is checkboxes and dropdowns, you're going to want to wait until the cell editing is stopped (you don't want to commit to the database every time a letter is typed in a textbox).
If the problem is that it's not committing after focus has gone to another component, add a FocusListener that stops editing the table when focus is lost on the table:
Example:
final JTable table = new JTable();
table.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
TableCellEditor tce = table.getCellEditor();
if(tce != null)
tce.stopCellEditing();
}
});
I use the enter key so everytime a user hit enter the cell will update.
DefaultTableModel dtm = new DefaultTableModel(data, columnNames);
JTable table = new JTable(dtm);
table.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
int row = table.getSelectedRow();
int column = table.getSelectedColumn();
// resul is the new value to insert in the DB
String resul = table.getValueAt(row, column).toString();
// id is the primary key of my DB
String id = table.getValueAt(row, 0).toString();
// update is my method to update. Update needs the id for
// the where clausule. resul is the value that will receive
// the cell and you need column to tell what to update.
update(id, resul, column);
}
}
});
This is also handy if you want to stop the editing on an event handler from selection change or save button.
if (table.isEditing())
table.getCellEditor().stopCellEditing();
Ok I have this table added to a JPanel added to a JFrame.
In the mousePressed Event there it instates a new class tData and calls a method which returns data from the database as a string contained in a vector element.
What I want to happen, every time the btn is pressed it updates the table,
What does happen, every time the btn is pressed it updates the table but adds the same data to the end of the table?
What would cause this to happen?
Object columnHeaders[] = {"Fname", "Mname", "Lname", "Age"};
Object data[][] = {{}};
final DefaultTableModel dtm = new DefaultTableModel(data, columnHeaders);
JTable tb = new JTable(dtm);
JScrollPane scrollPane = new JScrollPane(tb);
tableWrap.add(scrollPane);
btn.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
tData h = new tData(10));
Vector<String> v = h.getInfo();
for(int i = 0; i < v.size() ; i++) {
dtm.insertRow(i, new Object[]{v.get(i).split(",")[0], v.get(i).split(",")[1], v.get(i).split(",")[2], v.get(i).split(",")[3]});
}
dtm.fireTableDataChanged();
frame.repaint();
}
});
Several issues here:
It looks like you need to update the entire table whenever that button is pressed. You have three options here: update the DefaultTableModel using setDataVector, recreate a new model from scratch and set it on the JTable with setModel, implement your own TableModel based on AbstractTableModel and firing appropriate TableModel events. You could also update the model using addRow and removeRow, but that would be very uneffective as it would trigger many events.
To listen for "button pressed" events, rather user an ActionListener (and add it using addActionListener) or an Action (and set it with setAction).
In DefaultTableModel, when you modify the structure, it is not needed to manuall call fireTableDataChanged();. It automatically fires appropriate TableModel events whenever you modify the underlying data. Don't call frame.repaint() either, it is useless and can be time consuming.
Unrelated: Consider following Java coding conventions (Class name starts with a capital letter) and meaningful variable names.
There are quite a few issues with the code you've written here. First, let's address the issue you are having with the code in your mousePressed method:
You are getting a Vector from your data providing code and then setting rows 0...n of the table with your new data. The way to do this is to write a custom extension of AbstractTableModel that returns the data you need when the button is pressed.
Another issue is the way you are handling the button press. Adding a mouse listener to the button is absolutely not the correct way of handling that. You want to add an ActionListener to the button. That listener will be fired whenever the button is pressed and released.
What I'd like to do is be able to tab between elements in table.
I currently am creating my table like this.
this.tableViewer =
new TableViewer(parent , SWT.FULL_SELECTION);
tableViewer.setUseHashlookup(true);
table = tableViewer.getTable();
GridData gridData = new GridData(GridData.FILL_BOTH);
gridData.grabExcessVerticalSpace = true;
table.setLayoutData(gridData);
table.setLinesVisible(true);
table.setHeaderVisible(true);
...
/** Create the Cell Editor Array - will hold all columns **/
editors = new CellEditor[table.getColumnCount()];
/** Cell Editor Row 1 **/
/** Set the column properties **/
tableViewer.setColumnProperties(columnNames);
/** Assign the cell editors to the viewer **/
tableViewer.setCellEditors(editors);
/** Set the cell modifier for the viewer **/
tableViewer.setCellModifier(new MyCellModifier(this));
//Create the Table Viewer
/** Table Viewer Content and Label Provider **/
tableViewer.setContentProvider(new MyContentProvider(this));
tableViewer.setLabelProvider(new MyLabelProvider());
But I'm not sure how to set up the tabulation. Everything else works as far as editing columns, showing data, etc. Just stuck on this last part.
If I've missed obvious documentation or javadocs - my apologies and even pointing to those would be great.
Although the solution thehiatus posted is very low level and will probably work (I haven't tested it), JFace gives you a framework for this specific problem. See the org.eclipse.jface.viewers.TableViewerFocusCellManager along with org.eclipse.jface.viewers.CellNavigationStrategy classes to solve this problem.
I think by default tab does not jump from cell to cell in an swt table. Instead it traverses to the next control. So you'll also need to tell it not to traverse when tab is pressed
KeyListener keyListener = new KeyLisener()
{
public void keyPressed(KeyEvent evt)
{
if (evt.keyCode == SWT.TAB)
{
// There are numerous setSelection methods. I'll leave this to you.
tableViewer.getTable().setSelection(...)
}
}
public void keyReleased(KeyEvent evt){}
}
TraverseListener traverseListener = new TraverseListener()
{
public void keyTraversed(TraverseEvent evt)
{
if (evt.keyCode == SWT.TAB)
evt.doit = false;
}
}
tableViewer.getTable().addKeyListener(keyListener);
tableViewer.getTable().addTraverseListener(traverseListener);
Also, as derBiggi suggested, the listeners need to be added to the Table object, not the TableViewer.
I couldn't get the desired behavior with a TraverseListener (it would not traverse within the table), and I had trouble getting it to work with a FocusCellManager and CellNavigationStrategy. I finally found this solution that enables me to tab from column to column within a row and automatically activate the editor.
Viewer viewer = ...
TableViewerFocusCellManager focusCellManager =
new TableViewerFocusCellManager(
viewer,
new FocusCellHighlighter(viewer) {});
ColumnViewerEditorActivationStrategy editorActivationStrategy =
new ColumnViewerEditorActivationStrategy(viewer) {
#Override
protected boolean isEditorActivationEvent(
ColumnViewerEditorActivationEvent event) {
ViewerCell cell = (ViewerCell) event.getSource();
return cell.getColumnIndex() == 1 || cell.getColumnIndex() == 2;
}
};
TableViewerEditor.create(viewer, focusCellManager, editorActivationStrategy,
TableViewerEditor.TABBING_HORIZONTAL);
You need to add a KeyListener and set the selection or focus to the next cell:
tableViewer.getTable().addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent e) {
System.out.println("Key Pressed");
if (e.keycode == SWT.TAB)
{
System.out.println("Detected TAB key");
// set table viewer selection
}
}
public void keyReleased(KeyEvent e) {
System.out.println("Key Released");
}}
);
I also had to implement tabbing between elements in a table. We use Grid from Nebula as the table.
Firstly, I had to suppress tabbing the focus preventing it from moving out of the table.
and then I added a Key Listener which moves the focus/selection to the next cell:
I also made my own algorithm to move the selection one cell to the right and when at the end of the row, move it to the beginning of the next row. When end of table is reached, the selection moves back to the first cell in the table.
This solved the problem for me.