I have a problem with SWT Tree.
My situation is like this: I have a SWT Tree, which contains many TreeItems (Log entries), which contain TreeItems too. Those log entries have really long messages, which could not be shown in the TreeColumns at all. So my idea was: adding a Listener to the tree, which opens a new Dialog by DoubleClick, which shows the entries' details. So far so good.
If I do a double click on a item, it works. BUT: If I do a double click on a parent Item, it will expand (and thats good), but my double click Listener is active then as well and the Dialog will open.
That's not, what I want.
So, there are two solutions to the problem:
1) prevent the Tree from expanding/collapsing by double click automatically and implement the method by myself or
2) recognize, that the item was expanded and the event has to be aborted.
I do not really know how to do 1 or 2. Do u guys know that?
Thanks in advance.
Other answers did not work for me. This worked:
treeViewer.getControl().addListener(SWT.MeasureItem, new Listener(){
#Override
public void handleEvent(Event event) {
}});
I found this in a discussion in the Eclipse Community Forums: Disabling Treeviewer doubleclick expand/collapse.
When you look at this code you might be tempted to believe that it pretends to the tree control that your tree items have a size of zero, and as a result the tree control fails to detect that the double-click happened within the item, so it does not perform the double-click action. However, this is not what is actually happening. Instead, what this snippet does is that it leverages some weird code in the implementation of the tree control, which checks whether a listener has been added for SWT.MeasureItem, and if so, it deliberately avoids handling a double-click. This piece of code is even prefixed with a lengthy comment which a) fails to make sense and b) does not agree with what the code does. (Whatever.) So, bottom line is that by simply adding a handler for SWT.MeasureItem, and regardless of what the handler does, we are preventing the tree control from handling double-clicks. This is a prime example of Programming by Coincidence1.
1 The term "Programming by coincidence" was coined in the book The Pragmatic Programmer by Andy Hunt and Dave Thomas. It refers to relying on luck and accidental successes rather than programming deliberately.
If you are using TreeViewer, you could make use of IOpenListener
treeViewer.addOpenListener(new IOpenListener() {
#Override
public void open(OpenEvent event) {
}
}
There is another solution which works much better.
The problem with the solution from 'sambi reddy' was, that the tree was prevented from expanding by doubleclick, but it was prevented from expanding by clickling on the left handside cross as well.
My solution (that works well), was easy: I added a TreeListener, which listens to expanding/collapsing the tree and removed the expanding/collpasing implementation from the MouseDoubleClick-Listener.
No JFace TreeViewer - it works fine.
Related
I am using the JTree Swing utility to represent a Tree that actually have loops. I have a single node called root, but some of the children will eventually point back to other parts of the tree, thus not making it a true tree, but rather a graph.
My Java application keeps locking up, (no exceptions being thrown, no stack overflow... etc) when I try to use the little gray arrows to expand and contract parts of the graph.
My question is, does JTree require that none of the DefaulMutableTreeNodes not contain a loop?
If so, how do we represent something like that using a JTree utility. For example, when you are debugging an application say in eclipse, and you can infinitely use the variable tree in debug mode to keep on looking through a looped object. That is the behavior I am looking for.
Any suggestions?
I don't think it's a problem that nodes in a Jtree loop on themselves. Apparently you have a problem only with an "expand all" button, which makes sense because an expand all method will go recursively through the nodes until they have no sons.
Jtree does not have an expand all button by default, so I'm guessing yours is already customized...? My suggestion would be either remove the button, or customize the code to stop the expansion if findind a node that was already expanded higher in the hierarchy.
there is a lot of similar topics that I've seen here but couldn't really find solution to my little problem.
My application is searching through a file and showing the results inside a jtree. and I have a problem with that. When I add new nodes to a tree using insertNodeInto(...); i can search through found items while still searching but there is a problem with visualization. I mean there is a problem with rendering the nodes - I really can't explain that properly so I'm including this image.
When I use reload on jtree at the end of searching everything is back to normal - rendering is ok, unfortunately this closes all tabs that user opened.
I'm a student - sorry for my poor english. I hope someone know why this problem appears.
The way that your GUI is displayed, it certainly looks as if you are adding components to your Model outside of the painting thread (the Event Dispatch Thread (EDT)). This in turn will trigger painting outside of this thread, which will result in erratic painting.
Please take a look at this tutorial on threads in Swing
Looking at DefaultTreeModel, it is clear that the insertNodeInto(..) method will trigger the GUI updates, so if not done on the EDT, you are prone the painting issues depicted in your example.
A quick fix would be to add a method similar to the (uncompiled) code below:
public void safeInsertNodeInto(final MutableTreeNode newChild,
final MutableTreeNode parent, final int index) {
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
model.insertNodeInto(newChild,parent,index);
}
}
);
}
then call that method instead of directly calling on you model.
That said, I heavily recommend reading the tutorial cited above. There are more advanced ways of dealing with the EDT constraints.
In the program I'm writing, I have a JTree storing some objects of my own design. I made my own extension of DefaultTreeCellRenderer and overrode getTreeCellRendererComponent to return a JPanel with some buttons and things. What I found was that the buttons I added didn't act like buttons, which makes think that interaction with the components is being "stolen" by the tree cell. (If you click on the button, the container surrounding the button is also being clicked on, and the tree has its own response to being clicked.)
So my question is this:
If what I want is the basic functionality of a tree, plus some buttons, what approach should I use?
Continue on the same route; add a mouse listener of some kind to manually add the functionality to the button.
Continue on the same route; remove the existing mouse listener and add your own to achieve the right behavior.
Extend or implement a slightly different class or interface than you did - maybe not DefaultMutableTreeNodes, maybe not DefaultTreeCellRenderer, etc. - use the existing XXXX to do what you're trying to do.
Avoid using JTree; make your own, it's not that hard.
I'm leaning toward the last option - there's a decent chance I don't actually want the folding behavior of a tree anyway, so I may just make my own structure. However, even if I choose that option, I'd like to know what I should have done.
You'll also need a TreeCellEditor, illustrated here.
Avoid using JTree; make your own, it's not that hard
I wish you good luck wit that ;-)
What is happening is that the components returned by the renderer are only used as a 'stamp'. So the JTree does not really contain the returned components, they are only painted. Hence no interaction with your button. It only looks like a button. It seems the JTree tutorial does not contain a real section on this, but it is basically the same concept as for tables, which is explained in the 'Renderers and editors' part of the tutorial.
That also explains why a typical renderer class extends JLabel and can simply use return this after it made customizations to itself, without affecting the other nodes in the tree. For example the source code of the DefaultTreeCellRenderer, which extends JLabel, contains
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel,
boolean expanded,
boolean leaf, int row,
boolean hasFocus) {
//...
setText(stringValue);
//...
return this;
}
How to fix this: create an editor as well, as suggested by #trashgod
I'm trying to use dynamically JTree component.
Under root node I have four nodes and one of them ("Operations") can have 0 to many children. This is set by user via editable list in separate window opened on users request. After editing this list user hits button 'Save' and then magic should happen. Edited list is sent to server(on the same machine actually, so it doesn't take to long), the window with list is closed but right before that the main window (with jtree) is told to refresh itself, and I can see that it does what is told in log output, but the changes don't show on the screen.
I am using DefaultTreeModel, this method is called to create model at the beginning(when first opening the window) and after the change to update the new model with new structure.
with dmtn.getLeafCount() I can see that newly downloaded structure from server is the right one with the changed number of leaves under 'Operations'
public DefaultTreeModel getDataStructure() {
int dataID = task.getData().getId();
LoggerUtility.logger.info("Data ID: " + dataID);
DefaultMutableTreeNode dmtn = Manager.manager.getDataStructure(task.getId());
LoggerUtility.logger.info("DTMN created "+dmtn.getLeafCount());
return new DefaultTreeModel(dmtn);
}
the method used to refresh the jtree looks like this (it's very messy):
public void updateTree(){
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel)taskDataTree.getModel()).reload();
this.revalidate();
this.repaint();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
}
It's very messy because I have tried to put in there every possible solution to my problem that I have found on forums,
I also tried with my own treemodel implementation which would call fireTreeStructureChanged(...) but it also didn't change.
I should probably also add that I'm using Netbeans GUI Builder to build my gui although I don't know if it has anything to do with that.
I would be very grateful for any help with that
BR
Lucja
EDIT!!!
I also tried puting it in another thread like that:
public void updateTree() {
SwingWorker sw = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel) taskDataTree.getModel()).reload();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
return null;
}
};
sw.execute();
}
but it also didn't help.
tree.setModel( anotherModel );
Is the only line of code that you need.
If it doesn't work then it means that the tree variable does not contain a reference to the tree that was added to the GUI. Maybe you have a class variable and a local variable of the same name.
From my point of view the own TreeModel implementation was a good approach. But I know that creating an TreeModelEvent with the correct data isn't that simple.
I would suggest to update your question with your TreeModel implementation so that we can find the problem with it.
In principle it should work this way (when you set a new Model, the tree reloads itself). (This is not the most efficient way, better let the model send appropriate events when it changes.)
If this does not work, make sure you are calling the setModel method in the AWT Event Dispatch Thread (with EventQueue.invokeLater (or SwingUtilities.invokeLater, which is the same), for example. I think you should not need all your revalidate(), repaint() etc. calls (and updateUI should only be done if you changed the look-and-feel configuration).
I want to have a JTextField (or another text-like input which supports focus and a cursor -- or maybe I should code my own?) where I want to have full control over the immediate input. I.e. I want to ignore most inputs and handle the rest specifically. It seems that JFormattedTextField is not what I want because it does the verification not on the immediate input but when the focus is lost.
I tried to add a key listener but it's a bit non-obvious how I should use it. It seems I can catch up events like cursor changes (via keys) or copy/paste (via key-shortcuts) in keyPressed and I can catch all normal key input in keyTyped. I am not sure how I can catch cursor changes or copy/paste made via mouse (for some reason, right click does not work anyway, so copy/paste via mouse in the context menu seems not possible but I am not sure if that might be a different issue or if it should work and just does not for some reason).
I basically want something like the following handler:
interface InputHandler {
void addStringAt(int pos, String s);
void deleteSubString(int pos, int len);
void setFocusTo(int pos);
}
And it should be absolutely impossible for the user to get any stuff onto the textbox which are not going through this handler.
Right now, it seems like I have to take care about a lot of specific cases (like on some architectures, there may be some context menu where they could copy/paste or input something, handle all mouse events manually, etc).
Or the other way, which also involves a lot of special handlings: To recode such input field myself. This still seems saver because I can know for sure that there are no tricky methods how the user could bypass the handler (and I really must know that for sure). Btw., how would I do this? I thought of extending a JLabel. How can I extend it so that it can get a focus?
I wonder how you would implement something like this.
It sounds like you need a DocumentFilter. A couple of existing questions that will help with this:
Cut and Paste in JTextArea
Help on writing your own javax.swing.text.Document