Prevent JTree from expanding after drag and drop - java

After I drag and drop a node, the new parent of the node expands. I want to disable this.
I extended the class TransferHandler and overrode the method importData.
In this method I do the actual move. After the move of the node I check if the parent node isExpanded and I get false as an answer.
So where or how can I cancel the expansion?

Maybe you can use addTreeWillExpandListener and add a listener like this:
public class DisableExpansionListener implements TreeWillExpandListener {
#Override
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
throw new ExpandVetoException(event, "Disallow all expansions!");
}
#Override
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException
// allow collapsing!
}
}

Related

Add children on expand in TreeViewer

I have a TreeViewer which has elements with children which I want to fetch from a rest api, so initially there are no children for the nodes. What I currently did is I added a doubleClickListener to the nodes and fetch the children for the selected node, then use the treeviewer's method "expandToLevel" to show them. I want to be able to do that by clicking on the expand arrow too.
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
Module m = (Module) selection.getFirstElement();
//----> theChildren are fetched here <---
m.setStrings(theChildren);
treeViewer.expandToLevel(m, 1);
}
Unfortunately when I try to do it with the treeListener the getChildren method from the content provider is called first and therefore returns that there are no children. Is it ok to make the api call in the getChildren method?
treeViewer.addTreeListener(new ITreeViewerListener() {
#Override
public void treeExpanded(TreeExpansionEvent event) {
Module m = (Module) event.getElement();
//----> theChildren are fetched here <---
m.setStrings(theChildren);
}
#Override
public void treeCollapsed(TreeExpansionEvent event) {
// TODO Auto-generated method stub
}
});
I found a solution. I don't know if its the best one out there but it works.
In treeExpanded I added async call to the expand of treeViewer so the children are shown now.
Display.getCurrent().asyncExec(new Runnable() {
#Override
public void run() {
treeViewer.expandToLevel(m, 1);
}
});

Key bindings don't work, Java SE, Swing

I'm trying to add a shortcut to my JButton. I've read How to Use Key Bindings tutorial and I also have read this page How to use Key Bindings instead of Key Listeners and a loooooooooooooot of other questions about key bindings, but haven't found any answer for me
What I've tried:
public class Example extends JFrame {
public static void main(String args[]) {
Example example = new Example();
}
Example(){
Action action = new Action() {
#Override
public Object getValue(String key) {
return null;
}
#Override
public void putValue(String key, Object value) {
}
#Override
public void setEnabled(boolean b) {
}
#Override
public boolean isEnabled() {
return false;
}
#Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
}
#Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Hello World!");
}
};
JButton button = new JButton("Hello World!");
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("RIGHT"), "doSomething");
button.getActionMap().put("doSomething", action);
button.addActionListener(action);
add(button);
setVisible(true);
pack();
}
}
I've also tried to make it like that: getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "doSmth");
But nothing seems to be working, what am I doing wrong?
Your Action has a method called isEnabled that you've implemented. The Javadoc on it states:
/**
* Returns the enabled state of the <code>Action</code>. When enabled,
* any component associated with this object is active and
* able to fire this object's <code>actionPerformed</code> method.
*
* #return true if this <code>Action</code> is enabled
*/
Since you return a hardcoded false, the Action is never enabled and the actionPerformed method is never called. Your problem is not the binding, it's the action itself!
A simple fix is to change isEnabled to return true, or, even simpler yet, use AbstractAction in place of Action, and override only actionPerformed (AbstractAction is kind of the "I don't care about all this stuff, just give me the simplest thing possible with one method to implement!")

How to disable expand sign in Swing JTree?

I'm working in Swing and I would like to disable the expand (plus [+]) sign on a certain type of nodes.
Not sure how to do it because my nodes aren't leaves and I also cannot use setShowsRootHandles (which is only for the root).
I'm referring to to JTree: suppose i got this structure:
Root
--[+] node1
--[+] node2
when I load this structure i would like not to see the [+] sign on node2 (because it a special type node). But I also would like to expand it by using a special command.
I've overridden isLeaf() (method from DefaultMutableTreeNode) so it would set to to TRUE when i'm in the special type node, but then when I'm trying to expand it, it wouldn't expand because isLeaf() == TRUE...
Hope this will make things more clear.
While it is not possible to remove the handles, it is possible to restrict the expansion of nodes. The way to go is a TreeWillExpandListener combined with a custom treeNode that has state to restrict expansion:
the custom node below has an expandable property that's false by default
when detecting custom nodes, the listener allows/vetoes expansion based on that expandable property
for programmatic expansion, the expandable property is set to true temporarily to pass the listener
Example code:
// mixed tree of normal/restricted noded
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode normalSubTree = new DefaultMutableTreeNode("normal");
normalSubTree.add(new DefaultMutableTreeNode("normalChild"));
MyNode restrictedSubTree = new MyNode("restrictedSubtree");
restrictedSubTree.add(new DefaultMutableTreeNode("restrictedChild"));
root.add(normalSubTree);
root.add(restrictedSubTree);
final JTree tree = new JTree(root);
// the listener which vetos expansion of MyNodes that are not expandable
TreeWillExpandListener l = new TreeWillExpandListener() {
#Override
public void treeWillExpand(TreeExpansionEvent event)
throws ExpandVetoException {
TreePath path = event.getPath();
if (path.getLastPathComponent() instanceof MyNode) {
if (!((MyNode) path.getLastPathComponent()).isExpandable()) {
throw new ExpandVetoException(event, "node not expandable");
}
}
}
#Override
public void treeWillCollapse(TreeExpansionEvent event)
throws ExpandVetoException {
}
};
tree.addTreeWillExpandListener(l);
Action expand = new AbstractAction("Expand") {
#Override
public void actionPerformed(ActionEvent e) {
TreePath selected = tree.getSelectionPath();
if (selected == null) return;
if (selected.getLastPathComponent() instanceof MyNode) {
MyNode last = (MyNode) selected.getLastPathComponent();
boolean old = last.isExpandable();
last.setExpandable(true);
tree.expandPath(selected);
last.setExpandable(old);
}
}
};
JXFrame frame = wrapWithScrollingInFrame(tree, "veto expand");
addAction(frame, expand);
show(frame);
}
// custom node which has an expandable property
public static class MyNode extends DefaultMutableTreeNode {
private boolean expandable;
public MyNode() {
this(null);
}
public MyNode(Object userObject) {
super(userObject);
}
public void setExpandable(boolean expandable) {
this.expandable = expandable;
}
public boolean isExpandable() {
return expandable;
}
}
It's possible to remove the handles - despite what others have mentioned.
I've attached a snippet on how to do this below. The key thing is to override shouldPaintExpandControl in BasicTreeUI.
jtree.setUI(new BasicTreeUI() {
#Override
protected boolean shouldPaintExpandControl(final TreePath path, final int row
, final boolean isExpanded, final boolean hasBeenExpanded, final boolean isLeaf)
{
boolean shouldDisplayExpandControl = false;
return shouldDisplayExpandControl;
}
This should really be documented in the JTree API but that's another issue.
Another approach to consider:
If you call DefaultTreeModel(TreeNode root, boolean asksAllowsChildren) the model will "ask" the nodes you insert if they are allowed to have children. If they cannot, it should not display the expand icon.
Be sure to override javax.swing.tree.TreeNode.getAllowsChildren() in your class.

JSlider with 2 data sources event handling

I have a JSlider component on my frame which is being constantly updated by an external component (a media player which sets a new value from time to time). I want the slider to handle the stateChanged event only when I manipulate the slider and not my external component.
Is there any way to achieve this?
I'd implement my own BoundedRangeModel, this way you can add additional flags that indicates whether it should accept updates or not
UPDATE with EXAMPLE
The basic idea would be to implement your own model, that way you can control when the value is actually changed
public class MyBoundedRangeModel extends DefaultBoundedRangeModel {
private boolean updatesAllowed;
public void setUpdatesAllowed(boolean updatesAllowed) {
this.updatesAllowed = updatesAllowed;
}
public boolean isUpdatesAllowed() {
return updatesAllowed;
}
#Override
public void setMinimum(int n) {
setUpdatesAllowed(true);
super.setMinimum(n);
setUpdatesAllowed(false);
}
#Override
public void setMaximum(int n) {
setUpdatesAllowed(true);
super.setMaximum(n);
setUpdatesAllowed(false);
}
#Override
public void setExtent(int n) {
setUpdatesAllowed(true);
super.setExtent(n);
setUpdatesAllowed(false);
}
#Override
public void setValue(int n) {
super.setValue(n);
}
#Override
public void setValueIsAdjusting(boolean b) {
setUpdatesAllowed(true);
super.setValueIsAdjusting(b);
setUpdatesAllowed(false);
}
#Override
public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean adjusting) {
if (isUpdatesAllowed()) {
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
}
}
}
This would allow you to control the change of the "value" property. The problem you have here is that ALL the set methods go through the setRangeProperties method, so you need to decide what should be allowed to effect it. In my example, the only method that does not control it is the setValue method.
In your code you would need to call it something like...
MyBoundedRangeModel boundedRangeModel = new MyBoundedRangeModel();
slider.setModel(boundedRangeModel);
...
boundedRangeModel.setUpdatesAllowed(true);
slider.setValue(value);
boundedRangeModel.setUpdatesAllowed(false);
Your only other choice is to extend the JSlider itself and override the setValue method directly in a similar way

How to add onclick selection to rows of wicket TreeTable?

I'm working with a TreeTable (from wicket-extensions) and I'd like to be able to select a row by clicking anywhere within it instead of the usual behavior of clicking the link in one cell to select the row. I understand this should be possible by adding an AjaxEventBehavior("onclick") to the component representing the row, but I can't seem to find any methods where the row component is exposed.
I figured out a solution after. The row element is available in the populateTreeItem method from TreeTable. When you're creating your treetable, override this method like so:
#Override
protected void populateTreeItem(final WebMarkupContainer item, final int level) {
super.populateTreeItem(item, level);
item.add(new AjaxEventBehavior("onclick") {
#Override
protected void onEvent(final AjaxRequestTarget target) {
final TreeNode node = ((TreeNode) item.getDefaultModelObject());
rowClickSelect(node);
});
}
};
Generally useful in adding behaviors to rows. In my case, I'll have to do some more overriding to reconcile this toggle-on-click behavior with the clicks that are supposed to expand/contract nodes as well as link clicks.
Just toggling selection again in these cases has the unfortunate effect of briefly toggling the node in and out of the unwanted state, which is not ideal. Instead, override the onJunctionLinkClicked and onNodeLinkClicked methods, which will be touched by a click event before it gets to the onClick behavior we just set-up in populateTreeItem:
#Override
protected void onJunctionLinkClicked(final AjaxRequestTarget target, final TreeNode node) {
super.onJunctionLinkClicked(target, node);
skipNextRowClick();
}
#Override
protected void onNodeLinkClicked(final AjaxRequestTarget target, final TreeNode node) {
super.onNodeLinkClicked(target, node);
skipNextRowClick();
}
Finally, add the methods skipNextRowClick and rowClickSelect:
/**
* Ensure the next call to rowClickSelect() will have no effect.
*/
private void skipNextRowClick() {
this.skipNextClickSelect = true;
}
private void rowClickSelect(final TreeNode node) {
if (this.skipNextClickSelect) {
this.skipNextClickSelect = false;
return;
}
// select on click row
final boolean isSelected = Log4jPanel.this.treeTable.getTreeState().isNodeSelected(node);
treeTable.getTreeState().selectNode(node, !isSelected);
}

Categories