Get a component from JList by click location - java

How can I fetch a component from a JList, with the click location?
I have my own list cell renderer where I insert some panels and labels.
Now i want to get e.g. the label where the user clicked at.
I tried the method list.getComponentAt(evt.getPoint()); but it returns only the entire JList.

I've not tested this, but the basics would be...
Use JList#locationToIndex(Point) to get the index of the element at
the given point.
Get the "element" at the specified index (using
JList#getModel#getElementAt(int)).
Get the ListCellRenderer using JList#getCellRenderer.
Render the element and get it's Component representation
Set the renderer's bounds to the required cell bounds
Convert the original Point to the Components context
Use getComponentAt on the renderer...
Possibly, something like...
int index = list.locationToIndex(p);
Object value = list.getModel().getElementAt(int);
Component comp = listCellRenderer.getListCellRendererComponent(list, value, index, true, true);
comp.setBounds(list.getCellBounds(index, index));
Point contextPoint = SwingUtilities.convertPoint(list, p, comp);
Component child = comp.getComponentAt(contextPoint);

MadProgrammer's works fine as long as the user doesn't click outside a cell. If he does that, the index returned by locationToIndex() will be the last index's cell, so the converted point will be "under" the rendered component
To check if the user really clicked a cell you have to do:
int index = list.locationToIndex(p);
if (index > -1 && list.getCellBounds(index, index).contains(p)){
// rest of MadProgrammer solution
...
}

Related

Moving selected item in JScrollPane to top of list and show remaining items in java

I have a list box with scroll pane which loads in an alphabetical list of 100+ song tabs. I can scroll to a song or type the full name to find what I'm looking for in the list.
What I am trying to add is a way to find a song in this long list more easily by just typing in the first letter and then have the index move to that item. I have accomplished this with the code below but what happens is the first item with letter 'r' (as an example) is identified, selected and then forced to be visible in the pane, but what I would like to do is have that selected item move to the top of the list and drag the next items in line with it.
searchByLetter.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
char c;
String s = (letterField.getText().toUpperCase());
if(s != null) {
c = s.charAt(0);
// the line below sends the typed letter to the method listed & returns where in the
// list the first item with the identified letter is, then the following lines
// 'select it' and make it visible in the pane
indexNumber = GetSongList.getListIndexNumber(c);
}
letterField.setText(null);
list.setSelectedIndex(indexNumber);
list.ensureIndexIsVisible(indexNumber);
// what I need now is a way to move this selected item to the top of the list dragging
// the next items in the list after it
}
I would like to do is have that selected item move to the top of the list
You don't actually change the data in the model. Instead you change the position of the viewport in the scroll pane:
Point p = list.indexToLoction( indexNumber );
scrollPane.getViewport.setViewPosition( p );
Or another option is to actually filter the items in the list. You could do this by using a single column JTable along with your JTextField. Read the section from the Swing tutorial on Sorting and Filtering for a working example.

TableViewer how to set caret position for the cell with Editing Support and remove FULL_SELECTION

I have a TableViewer with last column which has EditingSupport to edit the cell's value. The viewer has style set to FULL_SELECTION.
Once I click on the cell, the text value is fully selected:
I can start editing, it will clear off the current value "max value" and start new value.
However, If i want to move the mouse to a specific position to edit, I need to give a delay of a sec or so. If I click too fast right after the first click to select, the cell will be deselected.
Is there any way to avoid that? Can I make the cell not fully selected ? or always have the caret to the end of the text ? Thanks!
I assume you are using TextCellEditor as the cell editor.
Create your own class extending TextCellEditor and override the doSetFocus class to be something like:
#Override
protected void doSetFocus()
{
super.doSetFocus();
if (text != null) {
text.setSelection(0, 0);
}
}
to remove full selection and set caret to end of text, override doSetFocus and set text.setSelection( text.getText().length() );
to ignore double click event, override getDoubleClickTimeout to return 0

tooltips for individual JComponents within JList item

I am working on a dictionary app that displays word entries like this:
The word entry is made up of five JLabels. The JLabels EN, n and the star have tooltip text that explains what the abbreviation or symbol means. This works correctly when the word entry is placed in a regular JPanel, but if it is placed in a JList item the tooltip text is not displayed- presumably overwritten by the JList's (non-existent) tooltip.
I have seen answers like this, but they only add a tooltip for the JList item, not for individual JComponents with the item.
Is there any way to, for example, change the Z-order so that the tooltips for the JLabels is visible?
The word entry is made up of five JLabels.
You should NOT be storing Swing compnents in the ListModel. The point of using renderers is to store the data in the model and then use a renderer to display the data.
So in your case you need to create a custom object with 8 properties. 5 properties for the text to be displayed in the labels and 3 properties for the tooltip text. Then your renderer will be a JPanel with 5 labels. In the rendering code you simply set the text of each of the 5 labels with the data from your custom object. You would also set the tooltip text.
Next you will need to override the getToolTipText(MouseEvent) method of the JList. The default implementation of this code gets the renderer and then just returns the tootip of the renderer. This is simple because the renderer is usually just a single JLabel.
In your case the logic will be slightly more complicated because you have child components in the renderer so you will need to get the tooltip of the child component.
Following is the current code from the getToolTipText(...) method:
public String getToolTipText(MouseEvent event) {
if(event != null) {
Point p = event.getPoint();
int index = locationToIndex(p);
ListCellRenderer<? super E> r = getCellRenderer();
Rectangle cellBounds;
if (index != -1 && r != null && (cellBounds =
getCellBounds(index, index)) != null &&
cellBounds.contains(p.x, p.y)) {
ListSelectionModel lsm = getSelectionModel();
Component rComponent = r.getListCellRendererComponent(
this, getModel().getElementAt(index), index,
lsm.isSelectedIndex(index),
(hasFocus() && (lsm.getLeadSelectionIndex() ==
index)));
if(rComponent instanceof JComponent) {
MouseEvent newEvent;
p.translate(-cellBounds.x, -cellBounds.y);
newEvent = new MouseEvent(rComponent, event.getID(),
event.getWhen(),
event.getModifiers(),
p.x, p.y,
event.getXOnScreen(),
event.getYOnScreen(),
event.getClickCount(),
event.isPopupTrigger(),
MouseEvent.NOBUTTON);
String tip = ((JComponent)rComponent).getToolTipText(
newEvent);
if (tip != null) {
return tip;
}
}
}
}
return super.getToolTipText();
}
I thank the code you need to change would be in this area:
p.translate(-cellBounds.x, -cellBounds.y);
newEvent = new MouseEvent(rComponent, event.getID(),
This translates the mouse point from the JList to the renderer. So now I think you just need to modify the logic to get the label at the translated point and then get the labels tool tip.
So the new code might be something like:
p.translate(-cellBounds.x, -cellBounds.y);
Component label = rComponent.getComponentAt(p);
if (label == null) return super.getToolTipText();
newEvent = new MouseEvent(label, event.getID(),
You are confused. You don't add Components to a JList, you use a ListRenderer.
So you have two choices: You can either build your own custom tooltip for the JList, or create your own version of JList

Replace a node at (row,col) in a JavaFX GridPane

I am making a grid-style game/simulation based on bugs "sensing" and eating food. I am using a gridPane (called worldGrid) of labels to show the grid of bugs and food. This is obviously going to be constantly updated when a bug moves cells towards food etc.
I currently have a function updateGrid(int col, int row, String cellContent) which I want to replace the label at [row,col] with a label that has the new text in cellContent.
I have the follow which works
worldGrid.add(new Label(cellContent), row,col);
however im worried that that is just adding a label on top of the current label and obviously over 100 iterations of the simulation thats not ideal.
I have tried this before adding the label:
worldGrid.getChildren().remove(row,col);
However I then get an IllegalArgumentException when trying to do the add line.
Any ideas on how to do this? Or even better, any ideas on how best to show a constantly changing grid that will eventually use sprites instead of text?
The col/row provided by grid.add(node, col, row) (ATTENTION first comes col!) is only a layout constraint. This does not provide any means to access columns or rows like slots in a 2-dimensional array. So to replace a node, you have to know its object itself, e.g. remember them in a separate array.
Then you are able to call getChildren().remove(object)... e.g.:
GridPane grid = new GridPane();
Label first = new Label("first");
Label second = new Label("second");
grid.add(first, 1, 1);
grid.add(second, 2, 2);
second.setOnMouseClicked(e -> {
grid.getChildren().remove(second);
grid.add(new Label("last"), 2, 2);
});
box.getChildren().addAll(grid);
I agree with Jens-Peter but I would add that you can use GridPane's getColumnIndex and getRowIndex to obtain a particular node's location.
For example ( this is in a component which extends GridPane ):
// set the appropriate label
for (Node node : getChildren()) {
if (node instanceof Label
&& getColumnIndex(node) == column
&& getRowIndex(node) == row) {
((Label)node).setTooltip(new Tooltip(tooltip));
}
}
in other words, go through all the nodes in the GridPane and check for a match of the conditions you want, in this case row and column.
You called getChildren().remove() method directly will cause the gridpane to go out of sync with the constraints. When you add, it also setup the constraint for the node. Add clearConstraints() method.

Why does viewToModel return the position of the last char even if mouse is not over text?

I have a JTextPane and using a MouseAdapter I need to get the position ofthe char that is clicked on. Using viewToModel does return the wanted position when I click directly over chars, however, it returns the position of the last char in the row when I click in the empty area of the JTextPane.
Does anyone know how I can avoid getting the position of the last char when I don't click on chars?
Hers's the code that gets the position:
public void mouseClicked(MouseEvent e) {
JTextPane editor = (JTextPane) e.getSource();
Point pt = new Point(e.getX(), e.getY());
int pos = editor.viewToModel(pt);
}
What result do you expect when click on empty area? Actually it returns closest position to the clicked point.
You can get the position from viewToModel() and use modelToView() passing the obtained offset. Then just compare returned rectangle with the clicked point.

Categories

Resources