I want to have a JEditorPane inside a JScrollPane. When the user clicks a button, the click listener will create a textEditor, call jscrollpane.setViewPort(textEditor), call textEditor.setText(String) to fill it with editable text, and call jscrollpane.getVerticalScrollBar().setValue(0). In case you're wondering, yes, the setText() must come after the setViewPort() for reasons that aren't on topic.
Here is the problem: After the user clicks the button, the JScrollPane's view scrolls all the way to the bottom. I want the scrollbar to be at the top, as per the last line in my click listener.
I popped open a debugger, and to my horror, discovered that the jscrollpane's viewport is being forced down to the bottom after the conclusion of the click listener (when pumping filters). It appears that Swing is delaying the population of the editor/jscrollpane until after the conclusion of the clicklistener, but is calling the scrollbar command first. Thus, the undesired behavior.
Anyway, I'm wondering if there is a clean solution. It seems that wanting a scrollpane to be scrolled to the top after modification would be a reasonably common requirement, so I'm assuming this is a well-solved problem.
Thanks!
You could use JEditorPane.setCaretPosition(0).
Ok, it amazes me how I always figure out the answer fractions of a second after posting.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pane.getVerticalScrollBar().setValue(0);
}
});
This allows the scrolling action to be delayed until after the other task completes. Question: is this good style/reliable or is it just a race condition? Can I depend on this working?
Related
I have a JPanel (pNums) which contains another JPanel (pGrid). pGrid itself contains a grid (JLabel[][] in a GridLayout) of labels. There is a mouse listener which catches events from pGrid and does fairly important stuff with them (as in, the entire functionality of the program relies on the mouseClicked() event). This works perfectly, exactly the way I wanted it to... until I add tooltips to the labels.
As soon as I call JLabel.setToolTipText("SomeString") the listener stops reacting to events (I have tried most, if not all of the mouse events, none of them seem to be called).
I am sure that it is the tooltips by the way, commenting out the setToolTipText() completely fixes the problem. Of course, since I needed the tooltips, it also causes a whole host of other problems.
I've looked around and while I haven't found anything quite right, I get the impression that I just chose a really bad way to do what I wanted. But I also want to know for sure.
Can I get both the event and the tooltip or should I go back to the drawing board.
I think you might be able to "fix" this issue, with setting delay on tooltip appearance. But once it will appear user will have to click to hide it anyway.
http://docs.oracle.com/javase/7/docs/api/javax/swing/ToolTipManager.html
The reson for this might be, that tooltip itself needs mouse click, to hide.
I've been struggling with some problem while creating my app based on Swing. I have a main JFrame which consists of:
JMenu
JPanel containing a JButton and a JLabel
JButton is linked with ActionListener. Clicking JMenu (MenuListener) brings up a JDialog with some form. The problem is, when the JDialog is closed (it doesn't make difference whether I do it with dispose() or rather showVisible(false)) I need to click the JButton two times before it triggers for the first time. From now it normally works with one click.
Every time the JDialog is in front, the problem appears.
PS. The JDialog is set to be modal, with JFrame as parent.
It sounds like a focus issue.
The first click restores focus to the app and the second clicks the button. Typically, I have seen this when the JDialog has the wrong parent and focus can not be returned.
Thank you for your answers.
I have considered posting some code, but it involves 4 classes so will be quite long.
I have also tried things with focus before, but nothing helped. What is interesting: if I display the JDialog by new myDialog.showVisible(true) it behaves like I've described. But if I use construction like this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JDialog.setVisible(true);
}
});
it closes normally and parent frame doesn't need to be clicked before responding, but on the other hand the displayed Dialog needs so. Additonally, what I do not understand, after opening the Dialog cursor is placed in the text field and I can write normally, but to click some button on it I must click once on the Dialog, only second and next clicks behave like I want to.
PS. Closing the dialog like in the second included example changes nothing.
I have a java panel with 4 buttons. When I click on of these buttons, a new frame appears and the first is hidden with setVisibile(false).
On that new window, I have another button, but when i click it, I got the event corresponding to the fourth button of the first window. Clicking the button again does the trick, but of course this is not acceptable.
Am I missing something? I just show the frames with
nameOfTheFrame.setVisible(true);
and I have MouseListeners on every button.
The code of the last button is simply:
System.exit(0);
EDIT
Sample code:
private void btn_joinGamePressed(java.awt.event.MouseEvent evt) {
GraphicsTools.getInstance().getCreateGame().setVisible(false);
GraphicsTools.getInstance().getMainPanel().setVisible(false);
GraphicsTools.getInstance().getRegistration().setVisible(true);
}
GraphicsTools is a Singleton.
EDIT 2
Some more informations.
I noticed that on MAC OS works fine. The problem happens only on Linux and Windows.
This must be happening because of your mouse listeners. May be it is identifying the old button in your first click which is in the same location of new button (It is just my guess).
Change the mouse listeners to action listeners. For a button, it is sufficient if you have action listener.
Try this.
Try calling revalidate() on the frames as you change their viability.
Edit:
It could be something with the creation of the frames. Make sure you are calling 'pack()` on the frames.
I have a swing frame that contains embedded panels that contain other panels, etc.
Deep down, there is a button. I want the button to get focus so that pressing the "enter" key would generate an actionPerformed event.
However, if I do myButton.requestFocus() or myButton.requestFocusInWindow() the whole window gets the focus, but nothing seems to happen in terms of keyboard.
I'm obviously missing something about the focus subsystem.
Update2: I explicitly added a KeyListener in addition to the ActionListener and now it works. This is really weird, since I thought that actionListener includes both key and mouse actions.
For the enter key to work you probably want to set the default button rather than the keyboard focus:
button.getRootPane().setDefaultButton(button);
If you really want the keyboard focus then your problem might be related to when you call requestFocus. Sometimes if it is called before a component is fully visible it can be ignored. To fix that you can delay the requestFocus call until after other events have been processed:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
button.requestFocus();
}
});
Sounds like requestFocus() is failing at some level. Try testing to see if any of the parent jPanels or other components can request focus, and work your way up to find out where the problem lies.
There is a way to programatically specify the functionality of the tab ( you know when you press tab and the next widget gets selected )
By default it follows the way the components were added.
Using this custom mechanism will let you select your nested button as the first which receive the actionperformed event.
Unfortunately I don't remember what the name for this "mechanism" is, but is something like traversal or focus traversal
First, don't use requestFocus() use requestFocusInWindow(). requestFocus has platform specific issues, while requestFocusInWindow is more consistent.
Your actual problem; the component (or one of its parents) is probably not visible, or has been render non-focusable.
I want the button to get focus so that
pressing the "enter" key would
generate an actionPerformed event.
The is LAF dependents. Enter works in Windows, but not the Metal LAF. Check out Enter Key and Button for more inforation.
The requestFocusInWindow() method only works if the Component is currently visible on the frame. There are no other tricks so we are just making random guesses about what your are doing wrong. If you need further help you need to post a SSCCE demonstrating the problem.
You can get the rootPane of the frame and update the inputMap and actionMap. See the below code.
InputMap map = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ok");
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put("ok", enterAction);
Here enterAction is a AbstractAction object whose actionPerformed() will be called when user presses Enter.
There is a JTabbedPane In my Swing program.
When user clicks on a tab, the program takes a while to get the data and process the results, then shows the results in the selected tab.
How can I display a hour glass, or something of that effect so that user knows it's processing data? Not to click on the tab again before it finishes it job.
The simplest way is to just call setCursor on the appropriate component (probably the top-level window) with the appropriate Cursor.
component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
And then set it back when you are done.
component.setCursor(Cursor.getDefaultCursor());
A JProgressBar (possibly in indetermiante mode) sounds right - put that on the tab until the data has been fetched. A well-designed UI shouldn't force the user to wait for long-running tasks to complete and instead allow them to do something else inbetween.
setCursor(int) is deprecated. This is probably a bit cleaner:
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
As the other answers mention, you can set a wait cursor, but you also mention preventing additional mouse clicks. You can use a glass pane to prevent clicks on components until the long operation is finished. In addition to the Sun tutorials on the glass pane, there is a nice example at http://www.java2s.com/Code/Java/Swing-JFC/DemonstrateuseofGlassPane.htm
I would as other mentioned
Change the cursor
Use a SwingWorker
Display the progressbar or an animated image in the glasspane
Hide the glasspane when the task is completed
Restore the default cursor