Is there an elegantish way in Swing to find out if there are any tooltips currently being displayed in my frame?
I'm using custom tooltips, so it would be very easy to set a flag in my createToolTip() method, but I can't see a way to find out when the tooltip is gone.
ToolTipManager has a nice flag for this, tipShowing, but of course it's private and they don't seem to offer a way to get to it. hideWindow() doesn't call out to the tooltip component (that I can tell), so I don't see a way there.
Anyone have any good ideas?
Update: I went with reflection. You can see the code here:
private boolean isToolTipVisible() {
// Going to do some nasty reflection to get at this private field. Don't try this at home!
ToolTipManager ttManager = ToolTipManager.sharedInstance();
try {
Field f = ttManager.getClass().getDeclaredField("tipShowing");
f.setAccessible(true);
boolean tipShowing = f.getBoolean(ttManager);
return tipShowing;
} catch (Exception e) {
// We'll keep silent about this for now, but obviously we don't want to hit this
// e.printStackTrace();
return false;
}
}
It appears that the isEnabled() property of the hideTipAction is directly tied to the tipShowing boolean. You could try this:
public boolean isTooltipShowing(JComponent component) {
AbstractAction hideTipAction = (AbstractAction) component.getActionMap().get("hideTip");
return hideTipAction.isEnabled();
}
You probably want to do some sanity checking for nulls, etc. But this should get you pretty close.
EDIT, to your responses:
Short of some ugly reflection code, I don't think you have much choice. You cannot subclass ToolTipManager because of the package private constructor, and the showTipWindow() and hideTipWindow() are also package private, so the Adapter pattern is out as well.
It looks like that is going to require looping over all of the components to see if they have a tooltip. I'm looking for a global value. It may be that a loop is doable, but it seems inefficient.
That's too bad. After an internal discussion, "ugly reflection" was what we came up with as well, but I was hoping someone out there had a better idea.
Since you already have your own createToolTip(), maybe you can try something like this :)
public JToolTip createToolTip() {
JToolTip tip = super.createToolTip();
tip.addAncestorListener( new AncestorListener() {
public void ancestorAdded( AncestorEvent event ) {
System.out.println( "I'm Visible!..." );
}
public void ancestorRemoved( AncestorEvent event ) {
System.out.println( "...now I'm not." );
}
public void ancestorMoved( AncestorEvent event ) {
// ignore
}
} );
return tip;
}
Related
I have the following code, I cannot use setEnabled(false), because I need to set the background- and foregroundcolor.
public class RadioButton extends JRadioButton implements ItemListener {
public RadioButton(String text)
{
super(text);
addItemListener(this);
}
public void itemStateChanged(ItemEvent e) {
synchronized (this) {
removeItemListener(this);
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("item is selected true [changed]");
setSelected(false);
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
System.out.println("item is selected false [changed]");
setSelected(true);
}
addItemListener(this);
}
}
}
This should be a radio button, that can't be changed. Hoever if I try testing the code, it gives me an endless loop printing
item is selected true [changed]
once...
...and then always
item is selected false [changed]
until there is a Java StackOverflowError.
How can this be? Is the disabling of the ItemListener not working?
If you can then please also show me, how to pack this into a lamda function. I got a illegal self reference-error, when trying to put this into a lamda function.
Please correct me, if the title is not correct.
As MadProgrammer pointed out, disabling the AbstractButton (aka RadioButton or Checkbox) can be archieved by setting the ButtonModel to a custom one always returning a constant value.
MainClass:
radioButtonOrCheckbox.setModel(new ButtonCustomModel(true));
ButtonCustomModel:
public class ButtonModel implements javax.swing.ButtonModel {
protected boolean state;
public ButtonModel(boolean state)
{
this.state = state;
}
#Override
public boolean isSelected() {
return state;
}
#Override
public boolean isEnabled() {
return true;
}
// other methods of ButtonModel-interface
[...]
}
I cannot use setEnabled(false), because I need to set the background- and foregroundcolor
This is probably just purely a personal thing, but I have a distinct dislike or UI's which don't conform to establish norms and user expectations.
So, when a button shouldn't be interacted with, it should be disabled. This is a convention that a user understands immediately.
I change the background-color and foreground-color for the evaluation-radiobuttons and -checkboxes.
Okay, so you want to decorate the buttons in some way, fair enough
It is clear from context that they are not meant to be checked by the user
To you perhaps, I'd probably be madly trying to click it, but I'm just that kind of user ;)
Okay, so with just a little but of paying around with the UIManager's default values, it's possible to take more control over how some elements are rendered, for example...
UIManager.put("RadioButton.disabledText", Color.BLUE);
JRadioButton rb = new JRadioButton("Test");
rb.setOpaque(true);
rb.setBackground(Color.RED);
rb.setForeground(Color.BLUE);
rb.setEnabled(false);
add(rb);
UIManager.put("CheckBox.disabledText", Color.RED);
JCheckBox cb = new JCheckBox("Test");
cb.setOpaque(true);
cb.setBackground(Color.BLUE);
cb.setForeground(Color.RED);
cb.setEnabled(false);
add(cb);
Now, this is just a quick hack.
For me, I might consider doing something different to highlight the correct answer, maybe fading or removing the other questions or use a LineBorder to highlight the correct answer or use a JLabel and nice big green tick or red cross, as some simple idea off the top of my head.
i've got some problem with my Mouse Cursor. I set it inside my MouseMotion Event of a JPanel with this.setCursor(), but it dosen't changed.
After getting out ouf the Window for example on my Desktop and go back inside , the cursor will be changed by any motion.
The Code of the mouse Event of the JPanel is this:
public void mouseMoved(MouseEvent e) {
this.requestFocusInWindow();
this.requestFocus();
this.cL.doMouseMoved(e);
}
The Code of the Method doMouseMoved is this:
public void doMouseMoved(MouseEvent e) {
this.lastMouseEvent = e;
this.sList.setCurrentElements(e.getPoint());
this.setMovedCursor(e);
}
An finally this is the code of the method setMovedCursor:
public void setMovedCursor(MouseEvent e) {
java.awt.Cursor cu = new java.awt.Cursor(java.awt.Cursor.SW_RESIZE_CURSOR);
view.setCursor(cu);
}
(I know that this isn't the best way)
I hope everyone can help me.
Sorry for any mistakes, it's my first post at stackoverflow.
if (sList.getCurrentShapeType() == "rec") {
Not sure if it will fix your problem but don't use "==" to compare objects.
Instead you should be using the equals(...) method.
if ("rec".equals(sList.getCurrentShapeType()) {
Note: I changed the order of the test so you don't have to worry about the getCurrentShapeType() method returning a null value.
else if (k.getBorderByPoint(e.getPoint()) == 4)
Also, I don't know what your getBorderByPoint() method does but why are you comparing it to an integer value. We have no idea what "4" means. Don't use "magic numbers. Instead create variables like: CURSOR_NORTH. Or better yet why not just return the cursor from that method so you don't have to check the value twice.
Some background: I'm a fairly experienced C++ programmer, but I'm currently teaching myself Java.
I have an application with several JTextFields, and I want the content of a field to be highlighted when I click on it. I know I can write a simple inline FocusAdapter for each one, but I'd like to write a single nested class that is used for each JTestField's addFocusListener. I figured out the following code works:
private class textFieldFocusListener extends FocusAdapter {
#Override
public void focusGained(FocusEvent arg0) {
((JTextComponent) arg0.getComponent()).selectAll();
}
}
...but that JTextComponent cast troubles me a little bit. In C++ casts are frowned upon, and I'm not familiar with the Best Practices of Java.
So, is this solution with the cast to JTextComponent "good" Java coding, or is there a better/cleaner solution?
JTextComponent cast troubles me a little bit
This is fine to do, as long as you take care to only add the FocusListener to JTextComponents such as JTextFields. If you want to be extra careful, you could always do an instanceof check,
Component comp = e.getComponent();
if (!(e instanceof JTextComponent)) {
return;
}
but likely it's not necessary.
Perhaps better: create a method that adds the FocusListener and that only accepts JTextComponent as its parameter.
test if arg0 is a JTextComponent
private class textFieldFocusListener extends FocusAdapter {
#Override
public void focusGained(FocusEvent arg0) {
if (arg0 instanceOf JTextComponent) {
((JTextComponent) arg0.getComponent()).selectAll();
}
}
}
Just create a function which all of your listeners calling it.
I have an application which consists mainly in a JList being displayed on the screen. I would like that everytime I make a change to the AbstractListModel(adding or removing items to the list) , to somehow notify the app that changes have been made and modify the JFrame's title to something like frame_title[unsaved]. After I would save the app, the [unsaved] tag would go away.
I think maybe using the observer/observable technique would do the job but I am not sure how to do it. Maybe there is something much more appropriate to my problem? I am new to java new to java so that is why I came here asking for help. Thanks.
UPDATE : I can't really use the Observer-pattern in my case because I am already extending the AbstractListModel class.
Use this:
AbstractListModel model = ...;
model.addListDataListener(new ListDataListener() {
public void intervalAdded(ListDataEvent e) {
}
public void intervalRemoved(ListDataEvent e) {
}
public void contentsChanged(ListDataEvent e) {
}
});
I have a textbox and one suggestbox. I attach a value change and key up handler to the text box such that whatever the user types (or pastes) into the text box is echo-ed inside the suggestbox. I can get the suggestbox to display the suggestion list by calling showSuggestionList on each value change and key up event.
Now, how do I get the suggestbox to automatically choose the first item in the suggestion list?
One of the methods I tried is to programatically simulate key presses, i.e
suggestBox.setFocus(true);
NativeEvent enterEvent = Document.get().createKeyPressEvent(false, false, false, false, KeyCodes.KEY_ENTER);
DomEvent.fireNativeEvent(enterEvent, suggestBox);
textBox.setFocus(true);
This doesn't work at all. The enter key isn't simulated. Another possible solution is to extend SuggestionBox.SuggestionDisplay, but I'm not too sure how to that. Any pointers appreciated.
Update: I'm still working on this and trying various methods.
Here, I tried to implement my own SuggestionDisplay by subclassing DefaultSuggestionDisplay and overriding getCurrentSelection() to make accessible from my class. This doesn't work either. Null is returned.
private class CustomSuggestionDisplay extends DefaultSuggestionDisplay {
#Override
protected Suggestion getCurrentSelection() {
return super.getCurrentSelection();
}
}
suggestBox.setAutoSelectEnabled(true);
textBox.addKeyUpHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
suggestBox.setValue(textBox.getText(), true);
suggestBox.showSuggestionList();
if (suggestBox.isSuggestionListShowing()) {
String s = ((CustomSuggestionDisplay) suggestBox.getSuggestionDisplay()).getCurrentSelection().getDisplayString();
Window.alert(s);
}
}
});
Here, I tried to attach a value change handler to the SuggestBox, and casting the event type to SuggestOracle.Suggestion. Again, null is returned.
suggestBox.addValueChangeHandler(new ValueChangeHandler<String>() {
public void onValueChange(ValueChangeEvent<String> event) {
String s = ((SuggestOracle.Suggestion) event).getDisplayString();
Window.alert(s);
}
});
Use suggesBox.setAutoSelectEnabled(true)
Here more info about the SuggestBox of GWT:
You could try using addSelectionHandler in conjunction with setAutoSelectEnabled to receive an event whenever a suggestion is selected. You could also have your Oracle send a message when it suggests something, or your Display send a message when it displays a list:
public class AutomaticallySelectingSuggestionDisplay extends SuggestBox.DefaultSuggestionDisplay {
#Override
protected void showSuggestions(SuggestBox box, Collection<? extends SuggestOracle.Suggestion> suggestions, boolean isDisplayHtml, boolean isAutoSelectEnabled, SuggestBox.SuggestionCallback callback) {
super.showSuggestions(box, suggestions, isDisplayHtml, isAutoSelectEnabled, callback);
fireValueChangeEventWithFirstSuggestion(suggestions);
}
}
This idea feels a little muddled to me, so I hope you can find a solution just using event handlers.