views:

179

answers:

2

Hi all.

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!

+1  A: 

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

aioobe
@aioobe: Hmm. First try it worked. Then I double click the list again, and after the text appear on the textPane, no more Caret. Why is it so weird?
Alex Cheng
I'd noticed that after I double click on the second time, the focus runs to the `JToolBar` (one of the buttons). What should I do?
Alex Cheng
Try enclosing the grabfocus in a SwingUtilities.invokeLater.
aioobe
That did the trick. Before I thank you, would you mind telling me how would you know to use invokeLater for it? Also, where should I look into for more knowledge on Swing? Thanks!
Alex Cheng
Don't use the grabFocus() method. Please read the API.
camickr
@camickr: Thank you for pointing it out. I should use `requestFocusInWindow()` instead.
Alex Cheng
Even though the invokeLater() appears to fix the problem I doubt it is the correct solution. If you have focus ending up on the toolbar, then I suggest you have a bigger problem in your code. If you click on a JList, focus should not jump to the toolbar, it should remain on the JList.
camickr
Actually, it went to JToolbar after I disabled my Combobox in another JPanel, which resides in a splitpane. So if I enable my combobox, it will get the focus on the second time somehow. What should I do?
Alex Cheng
A: 

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 );
 }
}
camickr
@camickr: Thanks for the link. Very much appreciated. Edit: ... and wow, that's quite neat.
Alex Cheng
Hmm does it work hand in hand with another InputMap as I have one that is used for UndoAction and RedoAction (taken from Sun's example)? If you don't add the same key and action to both it should be fine right?
Alex Cheng
As long as the KeyStroke is different it should work. However in this case is shouldn't even be an issue because this adds a binding to the JList and I'm guessing your Undo/Redo is bound to the text pane so these are two completely different input maps. Each compnent has its own input map.
camickr