I've a JTable with a ListSelectionModel and ListSelectionListener.
The selection model is set in the JTables constructor: lsm.getSelectionModel()
and the ListSelectionListener is set via a public method:
public void setListSelectionListener(ListSelectionListener l){
lsm.addListSelectionListener(l);
}
called from the Controller class:
view.setTableSelectionListener(new ListSelectionListener(){
#Override
public void valueChanged(ListSelectionEvent e){
if (!e.getValueIsAdjusting()) {
int viewRow = e.getFirstIndex();
System.out.println(viewRow + " is selected");
}
}
});
because the listener is created in another class I can't use the JTable's getSelectedRow(); method, but using the ListSelectionEvent object's getFirstIndex(); obviously doesn't get the current selection.
So I'm now using int viewRow = ((ListSelectionModel)e.getSource()).getLeadSelectionIndex());
Does that seem like the correct way to get the current selection? It seems to be working, but I'm not sure if this is a bad way of doing it. Thanks
Only getMinSelectionIndex() and getMaxSelectionIndex() works, which returns the min and max of selected indices respectively. Lead/anchor selected index may >= 0 even when there is no selected row.
Related
I created a simple mouse event. When the user clicks the JTable it will fetch the records in the JTable and display them in the JTextField. In this case I am trying to display the ID from the Table into the Text Field.
public void fetchRec() {
xtable.addMouseListener(new MouseAdapter() {
public void rowClicked(MouseEvent evt){
xtable =(JTable) evt.getSource();
int row = xtable.rowAtPoint( evt.getPoint() );
int column = xtable.columnAtPoint( evt.getPoint() );
String s=xtable.getModel().getValueAt(row, column)+"";
idLabelField.setText(s);
}
});
}
I am calling the method here but it keeps telling me that rowClicked method is unused. I don't understand how its unused? Everything else I am calling is working except this.
public void bookDimensions() throws Exception {
addTextLabels();
addTextFields();
addPanelButtons();
addRecord();
addTable();
fetchRec();
}
Turn on cell selection and listen to the selection model instead of mouse events. See java: how to select only one cell in a jtable and not the whole row
I have a cell table showing some data. For each row, I want to have two columns which contain edit / delete buttons. When each button is clicked, it should be able to notify a listener which button was clicked (and preferably also be able to pass in the object that row is associated with).
How can I do this? Specifically, I know how to render a button, but how can I process the on-click event and pass in the object which the user clicked to edit or delete?
This is the standard approach:
myTable.addCellPreviewHandler(new Handler<MyObject>() {
#Override
public void onCellPreview(CellPreviewEvent<MyObject> event) {
if ("click".equals(event.getNativeEvent().getType())) {
if (event.getColumn() == 0 || event.getColumn() == 1) {
MyObject object = event.getValue();
Window.alert("Column clicked: " + event.getColumn());
}
}
}
});
This is a more efficient solution, because you only have one handler attached to a table, instead of trying to attach a handler to each button in each row.
I think you can make a foreach through all the rows in the celltable (I never worked with celltables)
And then you can add your own ClickHandler to the Button.
Something like that (not tested):
final int row = myrow; // add the row value or a object identifier or similar
Button delete_button = new Button("delete");
delete_button.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
// Insert your delete funciton
delete(row);
}
});
You mentioned a Listener, Listener are depreciated, use Handler instead.
I need to override the enter key functionality on a JTable. At present the default behaviour is to move the row selection down one row when the user presses the 'Enter' key. I want to disable this and get it to do something different based on their selection. The problem is that it seems to move down before it goes into my keylistener which takes in the row selection - this therefore opens another window with the wrong row selected.
This is my code so far...:
public class MyJTable extends JTable {
public MyJTable(){
setRowSelectionAllowed(true);
addListeners()
}
public void addListeners(){
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
openChannel();
}
}
});
}
public void openChannel(){
for (int selectedRow : getSelectedRows()){
//Code to open channel based on row selected
}
}
}
+1 to #Robin's answer
Adding to my comment...
Swing uses KeyBindings simply replace exisitng functionality by adding a new KeyBinding to JTable (the beauty happens because of JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT):
private void createKeybindings(JTable table) {
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
table.getActionMap().put("Enter", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
//do something on JTable enter pressed
}
});
}
simply call this method and pass JTable instance to override standard functionality of JTable ENTER
This is implemented using key bindings, which is preferred over key listeners. I strongly suggest you do the same: replace your key listener by a key binding.
The solution is replace the entry in the InputMap to point to your own Action (which you insert in the action map), or to just replace the appropriate entry in the action map.
The key bindings tutorial contains more info
I'm trying to understand how getListCellRendererComponent method works but I don't get it. I made a separate class that extends BasicComboBoxRenderer and I added a counter which is printed every time getListCellRendererComponent is called. I then run a test class with a main method that shows a frame with just a JComboBox that uses my custom renderer class. This combobox has 3 items in total and I've set setMaximumRowCount(2) so it only shows 2 of them.
When I first run the program and the frame with the combobox appears, the counter informs that getListCellRendererComponent is called 6 times.
When the frame looses focus (when I click on my desktop for example) the method executes 1 time.
When the frame regains focus (click back on my frame) the method executes 1 time.
When I click on the arrow button and the drop-down list appears for the FIRST time, counter says that the method executes 8 times.
When I click again on the arrow button and the list disappears, the method is called 1 time (this happens always).
When I click on the arrow button AFTER the first time, the method is called 5 times.
When I click on the scrollbar button to go up or down, the method executes 1 time.
When I move the cursor on a not-selected item of the list, the method executes 2 times and after a second 1 more time (this is the most absurd)
When I click on an item of the list the method executes 4 times.
At first I thought that this method will be executed as many times as the number of the items in the list (plus one more that appears on the combobox display area).
But I can only understand one or two cases from the above, for example when I click the scrollbar buttons and the method executes 1 time, probably because a new item is rendered. The rest of them seem insane...
I would expect no less then n + 1 iterations of the renderer to be called at any one time.
The component needs to
Figure out the best size for the contents. This can be achieved by using a prototype value or, if none is specified, iterating through all the items to find the max bounds (thats 3 times)
Render the selected item if one exists +1 times
Render the list if the popup is visible +3 times
Possibly look for a tooltip
= a possible 7 iterations
When losing focus, the component needs to render the selected item +1
When regaining focus, the component will try a render te selected item again +1
When the popup is displayed, see the first part
The second time probably indicates that the component has cached the result of the first popup action (it's possible that the component is invalidating its internal cache between focus events)
Each time you change the view of the scrollpane, it needs to render any items not previously shown on the screen, this is done for optimisation reasons (imagine a lst with 100s of items, rendering all of them is a waste of time, hence the inclusion of the prototype value)
Mouse actions can be triggering a series of different actions, mouse in, mouse out, mouse move. Most likly these are to do with the tooltip manager and component trying to determine if a tooltip is available
Try setting a prototype value & see if that changes the number of iterations when the component displays its popup
I think that you forgot to describe how and which Object(s) you create or re_create in the Renderer,
you forgot to sent here your view about Renderer in the SSCCE form
then everything is in the academic level and too hard to write something about your Renderer ...
Renderer react to the every Mouse and Key events
plain Renderer with output from all important methods to the System.out.println("yyyy")
.
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
public class ComboBoxHoverOver {
private JComboBox combo = new JComboBox();
public ComboBoxHoverOver() {
combo.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXX");
combo.setRenderer(new ComboToolTipRenderer(combo));
combo.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
System.out.println("itemStateChanged");
}
});
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("actionPerformed");
}
});
combo.addItem("");
combo.addItem("Long text 4");
combo.addItem("Long text 3");
combo.addItem("Long text 2");
combo.addItem("Long text 1");
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(combo);
f.pack();
f.setVisible(true);
}
private class ComboToolTipRenderer extends BasicComboBoxRenderer {
private static final long serialVersionUID = 1L;
private JComboBox combo;
private JList comboList;
ComboToolTipRenderer(JComboBox combo) {
this.combo = combo;
}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
System.out.println(value + ", " + index + ", " + isSelected + ", " + cellHasFocus);
if (comboList == null) {
comboList = list;
KeyAdapter listener = new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_UP) {
int x = 5;
int y = comboList.indexToLocation(comboList.getSelectedIndex()).y;
System.out.println("keyReleased " + comboList.getSelectedIndex());
}
}
};
combo.addKeyListener(listener);
combo.getEditor().getEditorComponent().addKeyListener(listener);
comboList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
JList list = (JList) e.getSource();
int item = list.getSelectedIndex();
if (item > -1) {
String string = list.getSelectedValue().toString();
System.out.println("valueChanged " + list.getSelectedValue().toString());
}
}
}
});
}
if (isSelected) {
System.out.println("isSelected " + value.toString());
}
return this;
}
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ComboBoxHoverOver comboBoxHoverOver = new ComboBoxHoverOver();
}
});
}
}
I use the TableViewer to show informations in a table. The user can select one of the shown options by selecting one line of the table.
I want to create a table in matrix form, in which the user can not only select the line. It should be possible to select every item of the table, like row 2 column 3. For every item selection an action is called to handle this item as it is in the TableViewer.
As far as i now, i can add CellModifier and CellEditors to the line of Columns of the table, but the reference for the action is always the line object and not the selected TableItem.
Does somebody have an example how to create such a matrix inside a Composite?
I can create it by setting a GridLayout and adding the components in a for-loop, but than i get issues, when i want to redraw the Composite with new childrens. The TableViewer does already have this handling, so i dont want to implement it again.
I had the same problem a while ago and the only way I found to solve it was to register a mouse listener on the SWT table widget associated to the table viewer.
MouseListener columnSelectionMouseListener = new ColumnSelectionMouseListener();
getViewer().getTable().addMouseListener(columnSelectionMouseListener);
public class ColumnSelectionMouseListener implements MouseListener {
private TableColumn selectedColumn;
#Override
public void mouseDoubleClick(MouseEvent e) {
// Nothing to do here
}
#Override
public void mouseDown(MouseEvent e) {
table = (Table) e.widget;
TableItem item = table.getItem(new Point(e.x, e.y));
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn column = table.getColumn(i);
Rectangle bounds = item.getBounds(i);
if (bounds.contains(e.x, e.y)) {
selectedColumn = column;
}
}
}
#Override
public void mouseUp(MouseEvent e) {
// Nothing to do here
}
public TableColumn getSelectedField() {
return selectedColumn;
}
}
Then, for example in the viewer's selection listener, you can ask to the mouse listener which column was selected when the mouse has been pressed and combine that with the selected line coming from the viewer's selection to perform the appropriate action.
Hope this can help.
Manu
Maybe the following JFace snippet will help:
Snippet058CellNavigationIn34
Ingo