Can't turn off tooltips for text area inside scroll pane - java

All Swing components in my app (except labels) have tooltips that can be annoying once the user knows what's going on, so I have a Preferences menu that allows turning them off. I could name every component and set its tooltip text to "" [e.g., txtPattern.setToolTipText("");] (and 10 others), but I decided (with SO aid that started awhile back) to write code that would be more elegant (a learning experience):
private void tipsOff(Container container){
Component [] c = container.getComponents();
for (Component cc : c)
((JComponent)cc).setToolTipText("");
}
private void mniPrefTooltipsActionPerformed(java.awt.event.ActionEvent evt) {
if(! mniPrefTooltips.isSelected()){
tipsOff(gui.getContentPane());
tipsOff(gui.pnlLetters);
tipsOff(gui.mbrMenuBar);
}
else{
gui.dispose();
gui = new IO();
gui.setVisible(true);
}
}
I have a problem, which is that the tooltips are NOT turned off for the two large text areas at the bottom of the gui (highlighted in the Navigator pane). The two buttons (marked with green in Nav. pane) ARE processed correctly. These items are supposed to be processed via the first call to tipsOff, which processes gui.getContentPane()).
(I added the two lines bellow to try to rectify the problem. Nope.)
tipsOff(gui.scrOutput);
tipsOff(gui.scrScratch);
(Also tried this. Nope.)
tipsOff(gui.txaOutput);
tipsOff(gui.txaScratchwork);
How can I elegantly (i.e., assume I have many text areas, not just 2) turn off the text area tooltips?
P.S. I get the message Access of private field of another object for all but the first call to tipsOff. I don't care, owing to the nature of the task at hand.

Use ToolTipManager.sharedInstance().setEnabled( false ) to disable all tool tips in your Swing application.
Benefits compared to your approach
It works :-)
You do not clear the tooltips, so it is easy to re-enable them again. For example if you want to offer UI to your user to activate/de-activate the tooltips this approach will work. In your approach, you would have to restore all the tooltips you previously cleared, which would be difficult to do in a generic way.

Related

Toggle "enabled" state of a large number of components in a Java Swing applicaiton

I'm making a level editor for my java game using Java swing.
One of the features is that there is a a togglable button to turn the game on and off to test the level out. The game runs inside a jpanel, then you click the button again to untoggle it, and it turns the game off.
I only want the user to be able to change stuff or push buttons in the swing application when the game is NOT running, when it is running I set the focus to the game component. The only button in the swing application that they should be able push is the toggle button to turn the game back off.
The problem is, I can't think of a good way to do this. Using a recursive function I could easily loop through and find all components and do setEnabled(false), but when the game is turned back off it has no way to know what the previous enabled state was (along other issues, like other components responding to setEnabled being called on other components)
What I think I really need is just some kind of way to just outright "kill" user input into the swing application when the game is running.. But preferablly with a way to click the toggle button again to return the application's state, and the game which is running inside a Jpanel needs to be able to have focus...
Is there any way to do this sort of thing at all without massive amounts of "organizational" code to manage the components in the swing application?
You can place everything in a map, like this.
class ComponentState {
private JComponent component;
private bool on;
// Getters & Setters
}
private Map<String, ComponentState> components = new HashMap<>();
in order to add a new component to your game:
components.add("startbutton", new ComponentState(new JButton, true));
then to add all components to your screen:
for(String key : components.KeySet()) {
ComponentState comp = components.get(key);
if(comp.isOn()) { this.add(comp.getComponent()) };
}
and to disable/activate a component:
components.get("myActivatedComponent").disable(); // disable is a self defined method
You want a disableAll() method that sets every component to a disabled state, and a resetAll() method that will reset every component state back to its previous state. You need to save the status of every component when you disable it, in order to be able to restore it after. That will take O(n) space.
private final Map<JComponent, Boolean> components = new HashMap<JComponent, Boolean>();
public void disableAll(JComponent root) {
components.put(root, root.isEnabled());
root.setEnabled(false);
for (int i=0, n=root.getComponentCount(); i<n; i++) {
JComponent child = (JComponent) root.getComponentAt(i);
disableAll(child);
}
}
public void resetAll(JComponent root) {
boolean status = components.get(root);
root.setEnabled(status);
for (int i=0, n=root.getComponentCount(); i<n; i++) {
JComponent child = (JComponent) root.getComponentAt(i);
resetAll(child);
}
}
Another option is to use a GlassPane and "grey out" an area of components. You would also have to capture and ignore clicks in the pane for the area you don't want a users clicking.
See more with an example in the Java Tutorial here: http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html
This write up could also be helpful:
https://weblogs.java.net/blog/alexfromsun/archive/2006/09/a_wellbehaved_g.html

Swing - Changing the content of a panel using UpdateUI

I am going through a legacy application which is using Swing and i am struggling to figure out how the screens are changing when a user clicks a button. One of the reasons i cant figure this out is because this is the first time i am using Swing. I have read a book and got the basics but still struggling.
Basically, the screen i am looking at has a JSplitPane which has a number of shortcut buttons on the left and an empty pane on the right. When i click on the button, the right side pane is populated with a different screen depending on the button pressed.
Going through the code, i was expecting somewhere that there will be something that calls a setVisible() method depending on which button is pressed.
The actionPerformed method for each of the shortcut buttons looks something like this:
void shortCutBtn_actionPerformed(ActionEvent e) {
propertyChangeListeners.firePropertyChange("selectedShortCut", previousShortCutSel, currentShortCutSel);
mainPanel.updateUI();
}
I have gone through most of the code and came to a conclusion that the above code is what is causing the frame switching but i dont understand how that is happening.
Each screen is identified by a numeric constant. In the above code example, previousShortCutSel and previousShortCutSel refer to a numeric value that represents individual screens screen.
I have tried to look for documentation of how updateUI() works but i am lost. How does the above cause the content of the right panel of the JSplitPanel to be updated with a new screen?
This is not an appropriate use of updateUI(), which "Resets the UI property to a value from the current look and feel." As the example itself may be unreliable, consider studying another. GoogleOlympiad, for example, sets a label's icon using a (cached) image.
ImageIcon image = getImage(index);
imageLabel.setIcon(image);
(source: drjohnbmatthews at sites.google.com)
As per comments by ziggy (glad it helped)
Have a look at the PropertyChangeListeners that appear to be added in the code. In particular the propertyChange(PropertyChangeEvent e) method is where the code which changes the content will be present.
+1 to trashgod nice example/advice as always

Java Swing: Do something when a component has *finished* resizing

Apologies for the somewhat unclear question - couldn't think of a better way of putting it.
I use a JXTaskPane (from the Swing labs extension API) to display some information.
The user can "click" the title to expand the panel. The JXTaskPane is in a container JPanel, which is then added to a JFrame, my main application window.
I want my application window to resize to the size of the expanded task pane. To achieve this, I added a component listener to my container JPanel which would set size to the now expanded panel.
panel.addComponentListener(new ComponentListener()
{
public void componentResized(ComponentEvent e)
{
Dimension newSize = ((JXTaskPane)e.getSource()).getSize();
reSizeFrame(newSize);
}
}
private void reSizeFrame(Dimension newSize)
{
if ((newSize.height < maxSize.height) && (newSize.width < maxSize.width))
{
containerPanel.setSize(newSize);
appFrame.setSize(containerPanel.getSize());
appFrame.pack();
}
}
The problem is that the componentResized method is called as the task pane expands, as a result the resizeFrame method is called lots of times, and looks really awful on the screen.
How can I detect when the JXTaskpane has finished resizing? I thought of two approaches:
Put the resizeFrame() method in a SwingUtilities.invokeLate(..) call.
Put in a timer resizeFrame call, so any subsequent calls do not do anything until the timer fires. This should give enough time for the panel to resize.
What is the best way forward?
Also - This is my first serious Java GUI app after years of server side program. StackOverflow has been very helpful. So thanks!
I know you've already selected an answer, but overriding the paint method is definitely not correct, and while you may be able to hack something in place, it won't be ideal.
Looking at the source for JXTaskPane and specifically looking in setExpanded() (line 387), you can see it calls JXCollapsiblePane.setCollapsed(...) and then fires a property change event for expanded. A listener on that property won't be correct, because it'll fire before the animation is complete. So, if you go into JXCollapsiblePane and look at setCollapsed(...) (line 470) you'll see that if it's animated, it sets the paramaters and starts a timer. We want to know when the animation ends, so in that file, look at the animator (line 620, and specifically 652-667), which shows that when the animation ends, it fires a property change for ANIMATION_STATE_KEY with a value of "collapsed" or "expanded". This is the event you actually want. However, you don't have access to JXCollapsiblePane, so go back to JXTaskPane and search for ANIMATION_STATE_KEY, and you find line 208, which shows that JXTaskPane creates a listener on JXCollapsiblePane.ANIMATION_STATE_KEY and refires it as it's own event.
Since you do have access to JXTaskPane, you can listen for that event, so doing ...
taskPane.addPropertyChangeListener(JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
if(e.getNewValue().equals("expanded") {
...
}
else if(e.getNewValue().equals("collapsed") {
...
}
}
}
should get your event exactly when you want it.
The correct way to listen for events in Swing is through property listeners. Unfortunately, the only way to find out what the correct properties and values are is by digging through source code.
As a suggestion, have you tried overriding the paint method, first calling super and then putting your resize code at the end of that if (and only if) the size has changed significantly.
I'm not familiar with JXTaskPane, but my first reaction is that maybe you're handling the wrong event. You want the frame to resize when the user clicks on the header - so why not handle that event (perhaps using EventQueue.invokeLater() to resize the frame after the task pane has been resized)?
But if that doesn't work and you need to use the approach you've outlined above, using a javax.swing.Timer is probably best. Set it for 200 milliseconds or so and just restart() it every time componentResized() fires.

Is there a standard way to handle many different options for mouse events in java?

I'm developing a grid based sim game in java, and I was wondering if there is a standard way of doing the following.
I have a panel which is the game panel, and there are many different things which could happen when the panel is clicked. For example, when building a room, there are several stages, where dragging the mouse and left clicking will have different actions.
Right now, the way I have done it, is to use booleans to check what's being built, and then what stage it is at.
Is there any better or standard way of handling something like this? I had a quick google, but as I have said before, people on Stack Overflow always give a better, more relevant, up to date answer.
I consider myself still rather new to java.
Thanks in advance.
You might try looking into something similar to the strategy pattern.
Basically, you start by clicking the room button on your toolbar. The toolbar goes through and tells the grid to use the 'room place' actionlistener. Presumably removing any previous action listener that was listening
The room place actionlistener would in turn implement all the interesting bit of logic for left/right clicking, dragging, etc.
If you have multiple stages to building a room (say, placing doors, then windows, then trap doors); the action listeners would be responsible for handing control off to the next stage: a bit of a finite state machine.
So, start by clicking 'room' button, 'place room' listener is added. Drag out the area you want the room to be, 'place room' modifies the game state, then changes the actionlistener to the 'place windows' listener. Ad infinitum... until you finish.
One very simple (non compilable) example:
class GridPanel extends JPanel
{
void SetMouseListener(MouseListener newListener)
{
for(MouseListener ml : getMouseListeners())
removeMouseListener(ml);
addMouseListener(newListener);
}
}
class ControlPanel extends JPanel
{
GridPanel gameGrid;
void OnRectangleButtonClicked(some stuff)
{
gameGrid.SetMouseListener(new PlaceRoomListener(gameGrid));
}
}
class PlaceRoomListener extends MouseAdapter
{
GridPanel gameGrid;
//constructor, etc
void OnClick(mouse event)
{
gameGrid.doCoolStuff();
gameGrid.SetMouseListener(new PlaceTrapDoorListener());
}
}
//etc
Now, that non-compilable example aside, Pyrolistical does have a point: you generally don't want to combine your game model and graphic interface into one single glob of classes. You want the model separated from the GUI, and to manipulate it through a well defined interface.
(Also, there are probably better methods for going about removing the mouse listener then just randomly removing all listeners... I was in a bit of a rush, sorry)
It sounds like you need to define your game model/state and keep it separate from your mouse actions.
Are you using MVC?

"Fixing" the first few columns in an SWT table to prevent them from scrolling horizontally

We have implemented a table-based editor with an SWT tree table. It pretty much does what we want it to, except that we can't find a way to ensure that the first few columns remain at their position when the user scrolls horizontally (so that one can identify the row being edited).
There are a number of third-party table controls in various degrees of being incomplete or abandoned, and a snippet that shows how to use two tables (which get out of sync when they're being scrolled vertically).
What's the best way to solve this?
This 'official' SWT snippet does what you want to do, at least on my machine - it does not get out of sync on vertical scroll. But the price is a second scrollbar - way ugly. To prevent this, you can add the style SWT.NO_SCROLL in the constructor of the left table.
To improve the thing you will have to add a Listener on SWT.Traverse to both Tables, which syncs them if the user navigated using keys, something like this:
leftTable.addListener(SWT.Traverse, new Listener() {
public void handleEvent( Event event ) {
rightTable.setTopIndex(leftTable.getTopIndex());
}
});
I wouldn't go with another Table implementation, since you lose the biggest advantage you have with SWT: using a native widget, which looks and feels 'right' in each OS. If you want to do that anyway, Grid from the Nebula project is much more mature than the alpha tag implies. Don't know if it can do what you want, though.
the "syncing problem" only appears on MacOs based SWT. If your target platform is windows you should have no problem with the given SWT-Snippet. There will be more listeners to register on both tables to synchronise all occuring events (collapse, expand, mouse scroll, etc.)

Categories